3 * V1.71 18 Jan 2001 (c) 2000, 2001 John Lim (jlim@natsoft.com.my). All rights reserved.
4 * Released under both BSD license and Lesser GPL library license.
5 * Whenever there is any discrepancy between the two licenses,
6 * the BSD license will take precedence.
9 * MySQL code that does not support transactions. Use mysqlt if you need transactions.
10 * Requires mysql client. Works on Windows and Unix.
12 * 28 Feb 2001: MetaColumns bug fix - suggested by Freek Dijkstra (phpeverywhere@macfreek.com)
15 * Included with PhpWiki, which uses for now this mysql-specific backend directly,
16 * instead of going through the main adodb.inc.php library.
17 * Initial port by Lawrence Akka. See lib/WikiDB/ADODB.php
20 if (! defined("_ADODB_MYSQL_LAYER")) {
21 define("_ADODB_MYSQL_LAYER", 1 );
22 rcs_id('$Id: adodb-mysql.inc.php,v 1.2 2004-04-06 20:00:10 rurban Exp $');
24 class ADODB_mysql extends ADOConnection {
25 var $databaseType = 'mysql';
26 var $hasInsertID = true;
27 var $hasAffectedRows = true;
28 var $metaTablesSQL = "SHOW TABLES";
29 var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
30 var $fmtTimeStamp = "'Y-m-d H:i:s'";
32 var $hasMoveFirst = true;
34 var $upperCase = 'upper';
35 var $isoDates = true; // accepts dates in ISO format
37 function ADODB_mysql()
43 return mysql_insert_id($this->_connectionID);
46 function _affectedrows()
48 return mysql_affected_rows($this->_connectionID);
51 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
52 // Reference on Last_Insert_ID on the recommended way to simulate sequences
53 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
54 var $_genSeqSQL = "create table %s (id int not null)";
55 var $_genSeq2SQL = "insert into %s values (%s)";
57 function GenID($seqname='adodbseq',$startID=1)
59 //if (!$this->hasGenID) return false;
60 $getnext = sprintf($this->_genIDSQL,$seqname);
61 $rs = @$this->Execute($getnext);
63 $u = strtoupper($seqname);
64 $this->Execute(sprintf($this->_genSeqSQL,$seqname));
65 $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
66 $rs = $this->Execute($getnext);
68 $this->genID = mysql_insert_id($this->_connectionID);
70 if ($rs) $rs->Close();
75 function &MetaDatabases()
77 $qid = mysql_list_dbs($this->_connectionID);
80 $max = mysql_num_rows($qid);
82 $arr[] = mysql_tablename($qid,$i);
88 // returns concatenated string
92 $arr = func_get_args();
102 // suggestion by andrew005@mnogo.ru
103 $s = implode(',',$arr);
104 if (strlen($s) > 0) return "CONCAT($s)";
108 // returns true or false
109 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
111 $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);
112 if ($this->_connectionID === false) return false;
113 if ($argDatabasename) return $this->SelectDB($argDatabasename);
117 // returns true or false
118 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
120 $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);
121 if ($this->_connectionID === false) return false;
122 if ($argDatabasename) return $this->SelectDB($argDatabasename);
126 function &MetaColumns($table)
129 if ($this->metaColumnsSQL) {
130 global $ADODB_FETCH_MODE;
132 $save = $ADODB_FETCH_MODE;
133 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
135 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
137 $ADODB_FETCH_MODE = $save;
139 if ($rs === false) return false;
143 $fld = new ADOFieldObject();
144 $fld->name = $rs->fields[0];
145 $fld->type = $rs->fields[1];
147 // split type into type(length):
148 if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
149 $fld->type = $query_array[1];
150 $fld->max_length = $query_array[2];
152 $fld->max_length = -1;
154 $fld->not_null = ($rs->fields[2] != 'YES');
155 $fld->primary_key = ($rs->fields[3] == 'PRI');
156 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
157 $fld->binary = (strpos($fld->type,'blob') !== false);
160 if ($d != "" && $d != "NULL") {
161 $fld->has_default = true;
162 $fld->default_value = $d;
164 $fld->has_default = false;
168 $retarr[strtoupper($fld->name)] = $fld;
177 // returns true or false
178 function SelectDB($dbName)
180 $this->databaseName = $dbName;
181 if ($this->_connectionID) {
182 return @mysql_select_db($dbName,$this->_connectionID);
187 // parameters use PostgreSQL convention, not MySQL
188 function &SelectLimit($sql,$nrows=-1,$offset=-1,
189 $inputarr=false, $arg3=false,$secs=0)
191 $offsetStr =($offset>=0) ? "$offset," : '';
193 return ($secs) ? $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr,$arg3)
194 : $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr,$arg3);
198 // returns queryID or false
199 function _query($sql,$inputarr)
201 global $ADODB_COUNTRECS;
203 if($ADODB_COUNTRECS) return mysql_query($sql,$this->_connectionID);
204 else return mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
207 /* Returns: the last error message from previous database operation */
210 if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
211 else $this->_errorMsg = @mysql_error($this->_connectionID);
212 return $this->_errorMsg;
215 /* Returns: the last error number from previous database operation */
218 if (empty($this->_connectionID)) return @mysql_errno();
219 else return @mysql_errno($this->_connectionID);
224 // returns true or false
227 @mysql_close($this->_connectionID);
228 $this->_connectionID = false;
231 function ActualType($meta)
234 case 'C': return 'VARCHAR';
235 case 'X': return 'LONGTEXT';
237 case 'C2': return 'VARCHAR';
238 case 'X2': return 'LONGTEXT';
240 case 'B': return 'LONGBLOB';
242 case 'D': return 'DATE';
243 case 'T': return 'DATETIME';
244 case 'L': return 'TINYINT';
245 case 'R': return 'INTEGER NOT NULL AUTO_INCREMENT';
246 case 'I': return 'INTEGER'; // enough for 9 petabytes!
248 case 'F': return 'DOUBLE';
249 case 'N': return 'NUMERIC';
256 * Maximum size of C field
264 * Maximum size of X field
273 /*------------------------------------------------------------------------------
274 Class Name: Recordset
275 ------------------------------------------------------------------------------*/
277 class ADORecordSet_mysql extends ADORecordSet{
279 var $databaseType = "mysql";
282 function ADORecordSet_mysql($queryID) {
283 GLOBAL $ADODB_FETCH_MODE;
285 switch ($ADODB_FETCH_MODE)
287 case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
288 case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
290 case ADODB_FETCH_DEFAULT:
291 case ADODB_FETCH_BOTH:$this->fetchMode = MYSQL_BOTH; break;
294 $this->ADORecordSet($queryID);
299 GLOBAL $ADODB_COUNTRECS;
300 $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
301 $this->_numOfFields = @mysql_num_fields($this->_queryID);
304 function &FetchField($fieldOffset = -1) {
305 if ($fieldOffset != -1) {
306 $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
307 $f = @mysql_field_flags($this->_queryID,$fieldOffset);
308 // suggested by: Jim Nicholson (jnich@att.com)
309 $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset);
310 // mysql returns the max length less spaces -- so it is unrealiable
311 //$o->max_length = -1;
312 $o->binary = (strpos($f,'binary')!== false);
314 /* The $fieldOffset argument is not provided thus its -1 */
315 else if ($fieldOffset == -1) {
316 $o = @mysql_fetch_field($this->_queryID);
317 // suggested by: Jim Nicholson (jnich@att.com)
318 $o->max_length = @mysql_field_len($this->_queryID);
319 // mysql returns the max length less spaces -- so it is unrealiable
320 //$o->max_length = -1;
326 function &GetRowAssoc($upper=true)
328 if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $rs->fields;
329 return ADORecordSet::GetRowAssoc($upper);
332 /* Use associative array to get fields array */
333 function Fields($colname)
335 if ($this->fetchMode != MYSQL_NUM) return $this->fields[$colname];
338 $this->bind = array();
339 for ($i=0; $i < $this->_numOfFields; $i++) {
340 $o = $this->FetchField($i);
341 $this->bind[strtoupper($o->name)] = $i;
344 return $this->fields[$this->bind[strtoupper($colname)]];
349 return @mysql_data_seek($this->_queryID,$row);
352 /*function &FetchRow()
354 if ($this->EOF) return false;
356 $arr = $this->fields;
357 $this->_currentRow++;
358 // using & below slows things down by 20%!
359 $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
361 if (is_array($this->fields)) return $arr;
366 // 10% speedup to move MoveNext to child class
370 $this->_currentRow++;
371 // using & below slows things down by 20%!
372 $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
374 if (is_array($this->fields)) return true;
377 /* -- tested raising an error -- appears pointless
378 $conn = $this->connection;
379 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
380 $fn = $conn->raiseErrorFn;
381 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
389 $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
390 return (is_array($this->fields));
394 @mysql_free_result($this->_queryID);
395 $this->_queryID = false;
398 function MetaType($t,$len=-1,$fieldobj=false)
400 $len = -1; // mysql max_length is not accurate
401 switch (strtoupper($t)) {
409 if ($len <= $this->blobSize) return 'C';
416 // php_mysql extension always returns 'blob' even if 'text'
417 // so we have to check whether binary...
422 return !empty($fieldobj->binary) ? 'B' : 'X';
424 case 'DATE': return 'D';
427 case 'TIMESTAMP': return 'T';
436 if (!empty($fieldobj->primary_key)) return 'R';
450 // c-hanging-comment-ender-p: nil
451 // indent-tabs-mode: nil