3 V4.20 22 Feb 2004 (c) 2000-2004 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 if (! defined("_ADODB_MYSQL_LAYER")) {
16 define("_ADODB_MYSQL_LAYER", 1 );
18 class ADODB_mysql
extends ADOConnection
{
19 var $databaseType = 'mysql';
20 var $dataProvider = 'mysql';
21 var $hasInsertID = true;
22 var $hasAffectedRows = true;
23 var $metaTablesSQL = "SHOW TABLES";
24 var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
25 var $fmtTimeStamp = "'Y-m-d H:i:s'";
27 var $hasMoveFirst = true;
29 var $upperCase = 'upper';
30 var $isoDates = true; // accepts dates in ISO format
31 var $sysDate = 'CURDATE()';
32 var $sysTimeStamp = 'NOW()';
33 var $hasTransactions = false;
34 var $forceNewConnect = false;
35 var $poorAffectedRows = true;
37 var $substr = "substring";
38 var $nameQuote = '`'; /// string to use to quote identifiers and names
40 function ADODB_mysql()
46 $arr['description'] = ADOConnection
::GetOne("select version()");
47 $arr['version'] = ADOConnection
::_findvers($arr['description']);
51 function IfNull( $field, $ifNull )
53 return " IFNULL($field, $ifNull) "; // if MySQL
56 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
59 $save = $this->metaTablesSQL
;
60 $mask = $this->qstr($mask);
61 $this->metaTablesSQL
.= " like $mask";
63 $ret =& ADOConnection
::MetaTables($ttype,$showSchema);
66 $this->metaTablesSQL
= $save;
72 function &MetaIndexes ($table, $primary = FALSE, $owner=false)
74 // save old fetch mode
75 global $ADODB_FETCH_MODE;
77 $save = $ADODB_FETCH_MODE;
78 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
79 if ($this->fetchMode
!== FALSE) {
80 $savem = $this->SetFetchMode(FALSE);
84 $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table));
88 $this->SetFetchMode($savem);
90 $ADODB_FETCH_MODE = $save;
92 if (!is_object($rs)) {
98 // parse index data into array
99 while ($row = $rs->FetchRow()) {
100 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
104 if (!isset($indexes[$row[2]])) {
105 $indexes[$row[2]] = array(
106 'unique' => ($row[1] == 0),
111 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
114 // sort columns by order in the index
115 foreach ( array_keys ($indexes) as $index )
117 ksort ($indexes[$index]['columns']);
124 // if magic quotes disabled, use mysql_real_escape_string()
125 function qstr($s,$magic_quotes=false)
127 if (!$magic_quotes) {
129 if (ADODB_PHPVER
>= 0x4300) {
130 if (is_resource($this->_connectionID
))
131 return "'".mysql_real_escape_string($s,$this->_connectionID
)."'";
133 if ($this->replaceQuote
[0] == '\\'){
134 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
136 return "'".str_replace("'",$this->replaceQuote
,$s)."'";
139 // undo magic quotes for "
140 $s = str_replace('\\"','"',$s);
146 return mysql_insert_id($this->_connectionID
);
149 function GetOne($sql,$inputarr=false)
151 $rs =& $this->SelectLimit($sql,1,-1,$inputarr);
154 if ($rs->EOF
) return false;
155 return reset($rs->fields
);
161 function _affectedrows()
163 return mysql_affected_rows($this->_connectionID
);
166 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
167 // Reference on Last_Insert_ID on the recommended way to simulate sequences
168 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
169 var $_genSeqSQL = "create table %s (id int not null)";
170 var $_genSeq2SQL = "insert into %s values (%s)";
171 var $_dropSeqSQL = "drop table %s";
173 function CreateSequence($seqname='adodbseq',$startID=1)
175 if (empty($this->_genSeqSQL
)) return false;
176 $u = strtoupper($seqname);
178 $ok = $this->Execute(sprintf($this->_genSeqSQL
,$seqname));
179 if (!$ok) return false;
180 return $this->Execute(sprintf($this->_genSeq2SQL
,$seqname,$startID-1));
184 function GenID($seqname='adodbseq',$startID=1)
186 // post-nuke sets hasGenID to false
187 if (!$this->hasGenID
) return false;
189 $savelog = $this->_logsql
;
190 $this->_logsql
= false;
191 $getnext = sprintf($this->_genIDSQL
,$seqname);
192 $holdtransOK = $this->_transOK
; // save the current status
193 $rs = @$this->Execute($getnext);
195 if ($holdtransOK) $this->_transOK
= true; //if the status was ok before reset
196 $u = strtoupper($seqname);
197 $this->Execute(sprintf($this->_genSeqSQL
,$seqname));
198 $this->Execute(sprintf($this->_genSeq2SQL
,$seqname,$startID-1));
199 $rs = $this->Execute($getnext);
201 $this->genID
= mysql_insert_id($this->_connectionID
);
203 if ($rs) $rs->Close();
205 $this->_logsql
= $savelog;
207 // ViSolve : Sep 24,2010
208 // Instead of returning the generated LAST_INSERT_ID, the manipulated value
209 // from the $GLOBALS['lastidado'] is returned.
210 if($GLOBALS['lastidado'])
211 return $GLOBALS['lastidado'];
216 function &MetaDatabases()
218 $qid = mysql_list_dbs($this->_connectionID
);
221 $max = mysql_num_rows($qid);
223 $db = mysql_tablename($qid,$i);
224 if ($db != 'mysql') $arr[] = $db;
231 // Format date column in sql string given an input format that understands Y M D
232 function SQLDate($fmt, $col=false)
234 if (!$col) $col = $this->sysTimeStamp
;
235 $s = 'DATE_FORMAT('.$col.",'";
238 for ($i=0; $i < $len; $i++
) {
247 $s .= "'),Quarter($col)";
249 if ($len > $i+
1) $s .= ",DATE_FORMAT($col,'";
290 $ch = substr($fmt,$i,1);
297 if ($concat) $s = "CONCAT($s)";
302 // returns concatenated string
303 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
307 $arr = func_get_args();
309 // suggestion by andrew005@mnogo.ru
310 $s = implode(',',$arr);
311 if (strlen($s) > 0) return "CONCAT($s)";
315 function OffsetDate($dayFraction,$date=false)
317 if (!$date) $date = $this->sysDate
;
318 return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)";
321 // returns true or false
322 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
324 if (ADODB_PHPVER
>= 0x4300)
325 $this->_connectionID
= mysql_connect($argHostname,$argUsername,$argPassword,
326 $this->forceNewConnect
,$this->clientFlags
);
327 else if (ADODB_PHPVER
>= 0x4200)
328 $this->_connectionID
= mysql_connect($argHostname,$argUsername,$argPassword,
329 $this->forceNewConnect
);
331 $this->_connectionID
= mysql_connect($argHostname,$argUsername,$argPassword);
333 if ($this->_connectionID
=== false) return false;
334 if ($argDatabasename) return $this->SelectDB($argDatabasename);
338 // returns true or false
339 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
341 if (ADODB_PHPVER
>= 0x4300)
342 $this->_connectionID
= mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags
);
344 $this->_connectionID
= mysql_pconnect($argHostname,$argUsername,$argPassword);
345 if ($this->_connectionID
=== false) return false;
346 if ($this->autoRollback
) $this->RollbackTrans();
347 if ($argDatabasename) return $this->SelectDB($argDatabasename);
351 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
353 $this->forceNewConnect
= true;
354 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
357 function &MetaColumns($table)
360 if ($this->metaColumnsSQL
) {
361 global $ADODB_FETCH_MODE;
363 $save = $ADODB_FETCH_MODE;
364 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
365 if ($this->fetchMode
!== false) $savem = $this->SetFetchMode(false);
367 $rs = $this->Execute(sprintf($this->metaColumnsSQL
,$table));
369 if (isset($savem)) $this->SetFetchMode($savem);
370 $ADODB_FETCH_MODE = $save;
372 if ($rs === false) return false;
376 $fld = new ADOFieldObject();
377 $fld->name
= $rs->fields
[0];
378 $type = $rs->fields
[1];
381 // split type into type(length):
383 if (strpos($type,',') && preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
384 $fld->type
= $query_array[1];
385 $fld->max_length
= is_numeric($query_array[2]) ?
$query_array[2] : -1;
386 $fld->scale
= is_numeric($query_array[3]) ?
$query_array[3] : -1;
387 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
388 $fld->type
= $query_array[1];
389 $fld->max_length
= is_numeric($query_array[2]) ?
$query_array[2] : -1;
391 $fld->max_length
= -1;
395 // split type into type(length):
396 if (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
397 $fld->type = $query_array[1];
398 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
400 $fld->max_length = -1;
403 $fld->not_null
= ($rs->fields
[2] != 'YES');
404 $fld->primary_key
= ($rs->fields
[3] == 'PRI');
405 $fld->auto_increment
= (strpos($rs->fields
[5], 'auto_increment') !== false);
406 $fld->binary
= (strpos($fld->type
,'blob') !== false);
410 if ($d != "" && $d != "NULL") {
411 $fld->has_default
= true;
412 $fld->default_value
= $d;
414 $fld->has_default
= false;
417 if ($save == ADODB_FETCH_NUM
) $retarr[] = $fld;
418 else $retarr[strtoupper($fld->name
)] = $fld;
427 // returns true or false
428 function SelectDB($dbName)
430 $this->databaseName
= $dbName;
431 if ($this->_connectionID
) {
432 return @mysql_select_db
($dbName,$this->_connectionID
);
437 // parameters use PostgreSQL convention, not MySQL
438 function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
440 $offsetStr =($offset>=0) ?
"$offset," : '';
443 $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr);
445 $rs =& $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr);
450 // returns queryID or false
451 function _query($sql,$inputarr)
453 //global $ADODB_COUNTRECS;
454 //if($ADODB_COUNTRECS)
455 return mysql_query($sql,$this->_connectionID
);
456 //else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
459 /* Returns: the last error message from previous database operation */
463 if ($this->_logsql
) return $this->_errorMsg
;
464 if (empty($this->_connectionID
)) $this->_errorMsg
= @mysql_error
();
465 else $this->_errorMsg
= @mysql_error
($this->_connectionID
);
466 return $this->_errorMsg
;
469 /* Returns: the last error number from previous database operation */
472 if ($this->_logsql
) return $this->_errorCode
;
473 if (empty($this->_connectionID
)) return @mysql_errno
();
474 else return @mysql_errno
($this->_connectionID
);
479 // returns true or false
482 @mysql_close
($this->_connectionID
);
483 $this->_connectionID
= false;
488 * Maximum size of C field
496 * Maximum size of X field
505 /*--------------------------------------------------------------------------------------
506 Class Name: Recordset
507 --------------------------------------------------------------------------------------*/
509 class ADORecordSet_mysql
extends ADORecordSet
{
511 var $databaseType = "mysql";
514 function ADORecordSet_mysql($queryID,$mode=false)
516 if ($mode === false) {
517 global $ADODB_FETCH_MODE;
518 $mode = $ADODB_FETCH_MODE;
522 case ADODB_FETCH_NUM
: $this->fetchMode
= MYSQL_NUM
; break;
523 case ADODB_FETCH_ASSOC
:$this->fetchMode
= MYSQL_ASSOC
; break;
525 case ADODB_FETCH_DEFAULT
:
526 case ADODB_FETCH_BOTH
:$this->fetchMode
= MYSQL_BOTH
; break;
529 $this->ADORecordSet($queryID);
534 //GLOBAL $ADODB_COUNTRECS;
535 // $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
536 $this->_numOfRows
= @mysql_num_rows
($this->_queryID
);
537 $this->_numOfFields
= @mysql_num_fields
($this->_queryID
);
540 function &FetchField($fieldOffset = -1)
543 if ($fieldOffset != -1) {
544 $o = @mysql_fetch_field
($this->_queryID
, $fieldOffset);
545 $f = @mysql_field_flags
($this->_queryID
,$fieldOffset);
546 $o->max_length
= @mysql_field_len
($this->_queryID
,$fieldOffset); // suggested by: Jim Nicholson (jnich@att.com)
547 //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
548 $o->binary
= (strpos($f,'binary')!== false);
550 else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
551 $o = @mysql_fetch_field
($this->_queryID
);
552 $o->max_length
= @mysql_field_len
($this->_queryID
); // suggested by: Jim Nicholson (jnich@att.com)
553 //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
559 function &GetRowAssoc($upper=true)
561 if ($this->fetchMode
== MYSQL_ASSOC
&& !$upper) return $this->fields
;
562 $row =& ADORecordSet
::GetRowAssoc($upper);
566 /* Use associative array to get fields array */
567 function Fields($colname)
569 // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
570 if ($this->fetchMode
!= MYSQL_NUM
) return @$this->fields
[$colname];
573 $this->bind
= array();
574 for ($i=0; $i < $this->_numOfFields
; $i++
) {
575 $o = $this->FetchField($i);
576 $this->bind
[strtoupper($o->name
)] = $i;
579 return $this->fields
[$this->bind
[strtoupper($colname)]];
584 if ($this->_numOfRows
== 0) return false;
585 return @mysql_data_seek
($this->_queryID
,$row);
589 // 10% speedup to move MoveNext to child class
592 //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return adodb_movenext($this);
594 if ($this->EOF
) return false;
596 $this->_currentRow++
;
597 $this->fields
= @mysql_fetch_array
($this->_queryID
,$this->fetchMode
);
598 if (is_array($this->fields
)) return true;
602 /* -- tested raising an error -- appears pointless
603 $conn = $this->connection;
604 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
605 $fn = $conn->raiseErrorFn;
606 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
614 $this->fields
= @mysql_fetch_array
($this->_queryID
,$this->fetchMode
);
615 return is_array($this->fields
);
619 @mysql_free_result
($this->_queryID
);
620 $this->_queryID
= false;
623 function MetaType($t,$len=-1,$fieldobj=false)
627 $t = $fieldobj->type
;
628 $len = $fieldobj->max_length
;
631 $len = -1; // mysql max_length is not accurate
632 switch (strtoupper($t)) {
640 if ($len <= $this->blobSize
) return 'C';
647 // php_mysql extension always returns 'blob' even if 'text'
648 // so we have to check whether binary...
653 return !empty($fieldobj->binary
) ?
'B' : 'X';
656 case 'DATE': return 'D';
660 case 'TIMESTAMP': return 'T';
669 if (!empty($fieldobj->primary_key
)) return 'R';