Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 39 and 311]

   1  <?php
   2  /*
   3  @version   v5.21.0  2021-02-27
   4  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   5  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   6    Released under both BSD license and Lesser GPL library license.
   7    Whenever there is any discrepancy between the two licenses,
   8    the BSD license will take precedence.
   9    Set tabs to 8.
  10  
  11    This driver only supports the original non-transactional MySQL driver. It
  12    is deprecated in PHP version 5.5 and removed in PHP version 7. It is deprecated
  13    as of ADOdb version 5.20.0. Use the mysqli driver instead, which supports both
  14    transactional and non-transactional updates
  15  
  16    Requires mysql client. Works on Windows and Unix.
  17  
  18   28 Feb 2001: MetaColumns bug fix - suggested by  Freek Dijkstra (phpeverywhere@macfreek.com)
  19  */
  20  
  21  // security - hide paths
  22  if (!defined('ADODB_DIR')) die();
  23  
  24  if (! defined("_ADODB_MYSQL_LAYER")) {
  25  	 define("_ADODB_MYSQL_LAYER", 1 );
  26  
  27  class ADODB_mysql extends ADOConnection {
  28  	 var $databaseType = 'mysql';
  29  	 var $dataProvider = 'mysql';
  30  	 var $hasInsertID = true;
  31  	 var $hasAffectedRows = true;
  32  	 var $metaTablesSQL = "SELECT
  33  	 	 	 TABLE_NAME,
  34  	 	 	 CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END
  35  	 	 FROM INFORMATION_SCHEMA.TABLES
  36  	 	 WHERE TABLE_SCHEMA=";
  37  	 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
  38  	 var $fmtTimeStamp = "'Y-m-d H:i:s'";
  39  	 var $hasLimit = true;
  40  	 var $hasMoveFirst = true;
  41  	 var $hasGenID = true;
  42  	 var $isoDates = true; // accepts dates in ISO format
  43  	 var $sysDate = 'CURDATE()';
  44  	 var $sysTimeStamp = 'NOW()';
  45  	 var $hasTransactions = false;
  46  	 var $forceNewConnect = false;
  47  	 var $poorAffectedRows = true;
  48  	 var $clientFlags = 0;
  49  	 var $charSet = '';
  50  	 var $substr = "substring";
  51  	 var $nameQuote = '`';	 	 /// string to use to quote identifiers and names
  52  	 var $compat323 = false; 	 	 // true if compat with mysql 3.23
  53  
  54  	 /**
  55  	  * ADODB_mysql constructor.
  56  	  */
  57  	public function __construct() {
  58  	 	 if(version_compare(PHP_VERSION, '7.0.0', '>=')) {
  59  	 	 	 $this->outp_throw(
  60  	 	 	 	 'mysql extension is not supported since PHP 7.0.0, use mysqli instead',
  61  	 	 	 	 __METHOD__
  62  	 	 	 );
  63  	 	 	 die(1); // Stop execution even if not using Exceptions
  64  	 	 } elseif(version_compare(PHP_VERSION, '5.5.0', '>=')) {
  65  	 	 	 // If mysql extension is available just print a warning,
  66  	 	 	 // otherwise die with an error message
  67  	 	 	 if(function_exists('mysql_connect')) {
  68  	 	 	 	 $this->outp('mysql extension is deprecated since PHP 5.5.0, consider using mysqli');
  69  	 	 	 } else {
  70  	 	 	 	 $this->outp_throw(
  71  	 	 	 	 	 'mysql extension is not available, use mysqli instead',
  72  	 	 	 	 	 __METHOD__
  73  	 	 	 	 );
  74  	 	 	 	 die(1); // Stop execution even if not using Exceptions
  75  	 	 	 }
  76  	 	 }
  77  	 }
  78  
  79  	 // SetCharSet - switch the client encoding
  80  	function setCharSet($charset_name)
  81  	 {
  82  	 	 if (!function_exists('mysql_set_charset')) {
  83  	 	 	 return false;
  84  	 	 }
  85  
  86  	 	 if ($this->charSet !== $charset_name) {
  87  	 	 	 $ok = @mysql_set_charset($charset_name,$this->_connectionID);
  88  	 	 	 if ($ok) {
  89  	 	 	 	 $this->charSet = $charset_name;
  90  	 	 	 	 return true;
  91  	 	 	 }
  92  	 	 	 return false;
  93  	 	 }
  94  	 	 return true;
  95  	 }
  96  
  97  	function serverInfo()
  98  	 {
  99  	 	 $arr['description'] = ADOConnection::GetOne("select version()");
 100  	 	 $arr['version'] = ADOConnection::_findvers($arr['description']);
 101  	 	 return $arr;
 102  	 }
 103  
 104  	function ifNull( $field, $ifNull )
 105  	 {
 106  	 	 return " IFNULL($field, $ifNull) "; // if MySQL
 107  	 }
 108  
 109  	function metaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null)
 110  	 {
 111  	 	 // save old fetch mode
 112  	 	 global $ADODB_FETCH_MODE;
 113  
 114  	 	 $false = false;
 115  	 	 $save = $ADODB_FETCH_MODE;
 116  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 117  
 118  	 	 if ($this->fetchMode !== FALSE) {
 119  	 	 	 $savem = $this->SetFetchMode(FALSE);
 120  	 	 }
 121  
 122  	 	 $procedures = array ();
 123  
 124  	 	 // get index details
 125  
 126  	 	 $likepattern = '';
 127  	 	 if ($NamePattern) {
 128  	 	 	 $likepattern = " LIKE '".$NamePattern."'";
 129  	 	 }
 130  	 	 $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern);
 131  	 	 if (is_object($rs)) {
 132  
 133  	 	 	 // parse index data into array
 134  	 	 	 while ($row = $rs->FetchRow()) {
 135  	 	 	 	 $procedures[$row[1]] = array(
 136  	 	 	 	 	 'type' => 'PROCEDURE',
 137  	 	 	 	 	 'catalog' => '',
 138  	 	 	 	 	 'schema' => '',
 139  	 	 	 	 	 'remarks' => $row[7],
 140  	 	 	 	 );
 141  	 	 	 }
 142  	 	 }
 143  
 144  	 	 $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern);
 145  	 	 if (is_object($rs)) {
 146  	 	 	 // parse index data into array
 147  	 	 	 while ($row = $rs->FetchRow()) {
 148  	 	 	 	 $procedures[$row[1]] = array(
 149  	 	 	 	 	 'type' => 'FUNCTION',
 150  	 	 	 	 	 'catalog' => '',
 151  	 	 	 	 	 'schema' => '',
 152  	 	 	 	 	 'remarks' => $row[7]
 153  	 	 	 	 );
 154  	 	 	 }
 155  	 	 }
 156  
 157  	 	 // restore fetchmode
 158  	 	 if (isset($savem)) {
 159  	 	 	 $this->SetFetchMode($savem);
 160  	 	 }
 161  	 	 $ADODB_FETCH_MODE = $save;
 162  
 163  	 	 return $procedures;
 164  	 }
 165  
 166  	 /**
 167  	  * Retrieves a list of tables based on given criteria
 168  	  *
 169  	  * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default)
 170  	  * @param string $showSchema schema name, false = current schema (default)
 171  	  * @param string $mask filters the table by name
 172  	  *
 173  	  * @return array list of tables
 174  	  */
 175  	function metaTables($ttype=false,$showSchema=false,$mask=false)
 176  	 {
 177  	 	 $save = $this->metaTablesSQL;
 178  	 	 if ($showSchema && is_string($showSchema)) {
 179  	 	 	 $this->metaTablesSQL .= $this->qstr($showSchema);
 180  	 	 } else {
 181  	 	 	 $this->metaTablesSQL .= "schema()";
 182  	 	 }
 183  
 184  	 	 if ($mask) {
 185  	 	 	 $mask = $this->qstr($mask);
 186  	 	 	 $this->metaTablesSQL .= " AND table_name LIKE $mask";
 187  	 	 }
 188  	 	 $ret = ADOConnection::MetaTables($ttype,$showSchema);
 189  
 190  	 	 $this->metaTablesSQL = $save;
 191  	 	 return $ret;
 192  	 }
 193  
 194  
 195  	function metaIndexes ($table, $primary = FALSE, $owner=false)
 196  	 {
 197  	 	 // save old fetch mode
 198  	 	 global $ADODB_FETCH_MODE;
 199  
 200  	 	 $false = false;
 201  	 	 $save = $ADODB_FETCH_MODE;
 202  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 203  	 	 if ($this->fetchMode !== FALSE) {
 204  	 	 	 $savem = $this->SetFetchMode(FALSE);
 205  	 	 }
 206  
 207  	 	 // get index details
 208  	 	 $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table));
 209  
 210  	 	 // restore fetchmode
 211  	 	 if (isset($savem)) {
 212  	 	 	 $this->SetFetchMode($savem);
 213  	 	 }
 214  	 	 $ADODB_FETCH_MODE = $save;
 215  
 216  	 	 if (!is_object($rs)) {
 217  	 	 	 return $false;
 218  	 	 }
 219  
 220  	 	 $indexes = array ();
 221  
 222  	 	 // parse index data into array
 223  	 	 while ($row = $rs->FetchRow()) {
 224  	 	 	 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
 225  	 	 	 	 continue;
 226  	 	 	 }
 227  
 228  	 	 	 if (!isset($indexes[$row[2]])) {
 229  	 	 	 	 $indexes[$row[2]] = array(
 230  	 	 	 	 	 'unique' => ($row[1] == 0),
 231  	 	 	 	 	 'columns' => array()
 232  	 	 	 	 );
 233  	 	 	 }
 234  
 235  	 	 	 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
 236  	 	 }
 237  
 238  	 	 // sort columns by order in the index
 239  	 	 foreach ( array_keys ($indexes) as $index )
 240  	 	 {
 241  	 	 	 ksort ($indexes[$index]['columns']);
 242  	 	 }
 243  
 244  	 	 return $indexes;
 245  	 }
 246  
 247  
 248  	 /**
 249  	  * Appropriately quotes strings with ' characters for insertion into the database.
 250  	  *
 251  	  * Relies on mysql_real_escape_string()
 252  	  * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr
 253  	  *
 254  	  * @param string $s            The string to quote
 255  	  * @param bool   $magic_quotes This param is not used since 5.21.0.
 256  	  *                             It remains for backwards compatibility.
 257  	  *
 258  	  * @return string Quoted string
 259  	  */
 260  	function qStr($s, $magic_quotes=false)
 261  	 {
 262  	 	 if (is_null($s)) {
 263  	 	 	 return 'NULL';
 264  	 	 }
 265  
 266  	 	 if (is_resource($this->_connectionID)) {
 267  	 	 	 return "'" . mysql_real_escape_string($s, $this->_connectionID) . "'";
 268  	 	 }
 269  
 270  	 	 if ($this->replaceQuote[0] == '\\') {
 271  	 	 	 $s = str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
 272  	 	 }
 273  	 	 return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
 274  	 }
 275  
 276  	function _insertid()
 277  	 {
 278  	 	 return ADOConnection::GetOne('SELECT LAST_INSERT_ID()');
 279  	 	 //return mysql_insert_id($this->_connectionID);
 280  	 }
 281  
 282  	function getOne($sql,$inputarr=false)
 283  	 {
 284  	 global $ADODB_GETONE_EOF;
 285  	 	 if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) {
 286  	 	 	 $rs = $this->SelectLimit($sql,1,-1,$inputarr);
 287  	 	 	 if ($rs) {
 288  	 	 	 	 $rs->Close();
 289  	 	 	 	 if ($rs->EOF) return $ADODB_GETONE_EOF;
 290  	 	 	 	 return reset($rs->fields);
 291  	 	 	 }
 292  	 	 } else {
 293  	 	 	 return ADOConnection::GetOne($sql,$inputarr);
 294  	 	 }
 295  	 	 return false;
 296  	 }
 297  
 298  	function beginTrans()
 299  	 {
 300  	 	 if ($this->debug) ADOConnection::outp("Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver");
 301  	 }
 302  
 303  	function _affectedrows()
 304  	 {
 305  	 	 	 return mysql_affected_rows($this->_connectionID);
 306  	 }
 307  
 308  	  // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
 309  	 // Reference on Last_Insert_ID on the recommended way to simulate sequences
 310  	 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
 311  	 var $_genSeqSQL = "create table if not exists %s (id int not null)";
 312  	 var $_genSeqCountSQL = "select count(*) from %s";
 313  	 var $_genSeq2SQL = "insert into %s values (%s)";
 314  	 var $_dropSeqSQL = "drop table if exists %s";
 315  
 316  	function createSequence($seqname='adodbseq',$startID=1)
 317  	 {
 318  	 	 if (empty($this->_genSeqSQL)) return false;
 319  	 	 $u = strtoupper($seqname);
 320  
 321  	 	 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
 322  	 	 if (!$ok) return false;
 323  	 	 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
 324  	 }
 325  
 326  
 327  	function genID($seqname='adodbseq',$startID=1)
 328  	 {
 329  	 	 // post-nuke sets hasGenID to false
 330  	 	 if (!$this->hasGenID) return false;
 331  
 332  	 	 $savelog = $this->_logsql;
 333  	 	 $this->_logsql = false;
 334  	 	 $getnext = sprintf($this->_genIDSQL,$seqname);
 335  	 	 $holdtransOK = $this->_transOK; // save the current status
 336  	 	 $rs = @$this->Execute($getnext);
 337  	 	 if (!$rs) {
 338  	 	 	 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
 339  	 	 	 $u = strtoupper($seqname);
 340  	 	 	 $this->Execute(sprintf($this->_genSeqSQL,$seqname));
 341  	 	 	 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
 342  	 	 	 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
 343  	 	 	 $rs = $this->Execute($getnext);
 344  	 	 }
 345  
 346  	 	 if ($rs) {
 347  	 	 	 $this->genID = mysql_insert_id($this->_connectionID);
 348  	 	 	 $rs->Close();
 349  	 	 } else
 350  	 	 	 $this->genID = 0;
 351  
 352  	 	 $this->_logsql = $savelog;
 353  	 	 return $this->genID;
 354  	 }
 355  
 356  	function metaDatabases()
 357  	 {
 358  	 	 $qid = mysql_list_dbs($this->_connectionID);
 359  	 	 $arr = array();
 360  	 	 $i = 0;
 361  	 	 $max = mysql_num_rows($qid);
 362  	 	 while ($i < $max) {
 363  	 	 	 $db = mysql_tablename($qid,$i);
 364  	 	 	 if ($db != 'mysql') $arr[] = $db;
 365  	 	 	 $i += 1;
 366  	 	 }
 367  	 	 return $arr;
 368  	 }
 369  
 370  
 371  	 // Format date column in sql string given an input format that understands Y M D
 372  	function sqlDate($fmt, $col=false)
 373  	 {
 374  	 	 if (!$col) $col = $this->sysTimeStamp;
 375  	 	 $s = 'DATE_FORMAT('.$col.",'";
 376  	 	 $concat = false;
 377  	 	 $len = strlen($fmt);
 378  	 	 for ($i=0; $i < $len; $i++) {
 379  	 	 	 $ch = $fmt[$i];
 380  	 	 	 switch($ch) {
 381  
 382  	 	 	 default:
 383  	 	 	 	 if ($ch == '\\') {
 384  	 	 	 	 	 $i++;
 385  	 	 	 	 	 $ch = substr($fmt,$i,1);
 386  	 	 	 	 }
 387  	 	 	 	 /** FALL THROUGH */
 388  	 	 	 case '-':
 389  	 	 	 case '/':
 390  	 	 	 	 $s .= $ch;
 391  	 	 	 	 break;
 392  
 393  	 	 	 case 'Y':
 394  	 	 	 case 'y':
 395  	 	 	 	 $s .= '%Y';
 396  	 	 	 	 break;
 397  	 	 	 case 'M':
 398  	 	 	 	 $s .= '%b';
 399  	 	 	 	 break;
 400  
 401  	 	 	 case 'm':
 402  	 	 	 	 $s .= '%m';
 403  	 	 	 	 break;
 404  	 	 	 case 'D':
 405  	 	 	 case 'd':
 406  	 	 	 	 $s .= '%d';
 407  	 	 	 	 break;
 408  
 409  	 	 	 case 'Q':
 410  	 	 	 case 'q':
 411  	 	 	 	 $s .= "'),Quarter($col)";
 412  
 413  	 	 	 	 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
 414  	 	 	 	 else $s .= ",('";
 415  	 	 	 	 $concat = true;
 416  	 	 	 	 break;
 417  
 418  	 	 	 case 'H':
 419  	 	 	 	 $s .= '%H';
 420  	 	 	 	 break;
 421  
 422  	 	 	 case 'h':
 423  	 	 	 	 $s .= '%I';
 424  	 	 	 	 break;
 425  
 426  	 	 	 case 'i':
 427  	 	 	 	 $s .= '%i';
 428  	 	 	 	 break;
 429  
 430  	 	 	 case 's':
 431  	 	 	 	 $s .= '%s';
 432  	 	 	 	 break;
 433  
 434  	 	 	 case 'a':
 435  	 	 	 case 'A':
 436  	 	 	 	 $s .= '%p';
 437  	 	 	 	 break;
 438  
 439  	 	 	 case 'w':
 440  	 	 	 	 $s .= '%w';
 441  	 	 	 	 break;
 442  
 443  	 	 	  case 'W':
 444  	 	 	 	 $s .= '%U';
 445  	 	 	 	 break;
 446  
 447  	 	 	 case 'l':
 448  	 	 	 	 $s .= '%W';
 449  	 	 	 	 break;
 450  	 	 	 }
 451  	 	 }
 452  	 	 $s.="')";
 453  	 	 if ($concat) $s = "CONCAT($s)";
 454  	 	 return $s;
 455  	 }
 456  
 457  
 458  	 // returns concatenated string
 459  	 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
 460  	function concat()
 461  	 {
 462  	 	 $s = "";
 463  	 	 $arr = func_get_args();
 464  
 465  	 	 // suggestion by andrew005@mnogo.ru
 466  	 	 $s = implode(',',$arr);
 467  	 	 if (strlen($s) > 0) return "CONCAT($s)";
 468  	 	 else return '';
 469  	 }
 470  
 471  	function offsetDate($dayFraction,$date=false)
 472  	 {
 473  	 	 if (!$date) $date = $this->sysDate;
 474  
 475  	 	 $fraction = $dayFraction * 24 * 3600;
 476  	 	 return '('. $date . ' + INTERVAL ' .	  $fraction.' SECOND)';
 477  
 478  //	 	 return "from_unixtime(unix_timestamp($date)+$fraction)";
 479  	 }
 480  
 481  	 // returns true or false
 482  	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
 483  	 {
 484  	 	 if (!empty($this->port)) 
 485  	 	 	 $argHostname .= ":".$this->port;
 486  
 487  	 	 $this->_connectionID = 
 488  	 	 	 mysql_connect($argHostname,
 489  	 	 	 	 	 	   $argUsername,
 490  	 	 	 	 	 	   $argPassword,
 491  	 	 	 	 	 	   $this->forceNewConnect,
 492  	 	 	 	 	 	   $this->clientFlags
 493  	 	 	 	 	 	   );
 494  	 	 
 495  
 496  	 	 if ($this->_connectionID === false) 
 497  	 	 	 return false;
 498  	 	 if ($argDatabasename) 
 499  	 	 	 return $this->SelectDB($argDatabasename);
 500  	 	 
 501  	 	 return true;
 502  	 }
 503  
 504  	 // returns true or false
 505  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 506  	 {
 507  	 	 if (!empty($this->port)) $argHostname .= ":".$this->port;
 508  
 509  	 	 $this->_connectionID = 
 510  	 	 	 mysql_pconnect($argHostname,
 511  	 	 	 	 	 	    $argUsername,
 512  	 	 	 	 	 	    $argPassword,
 513  	 	 	 	 	 	    $this->clientFlags);
 514  	 	 
 515  	 	 if ($this->_connectionID === false) 
 516  	 	 	 return false;
 517  	 	 if ($this->autoRollback) 
 518  	 	 	 $this->RollbackTrans();
 519  	 	 if ($argDatabasename) 
 520  	 	 	 return $this->SelectDB($argDatabasename);
 521  	 	 return true;
 522  	 }
 523  
 524  	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 525  	 {
 526  	 	 $this->forceNewConnect = true;
 527  	 	 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
 528  	 }
 529  
 530  	function metaColumns($table, $normalize=true)
 531  	 {
 532  	 	 $this->_findschema($table,$schema);
 533  	 	 if ($schema) {
 534  	 	 	 $dbName = $this->database;
 535  	 	 	 $this->SelectDB($schema);
 536  	 	 }
 537  	 	 global $ADODB_FETCH_MODE;
 538  	 	 $save = $ADODB_FETCH_MODE;
 539  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 540  
 541  	 	 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
 542  	 	 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
 543  
 544  	 	 if ($schema) {
 545  	 	 	 $this->SelectDB($dbName);
 546  	 	 }
 547  
 548  	 	 if (isset($savem)) $this->SetFetchMode($savem);
 549  	 	 $ADODB_FETCH_MODE = $save;
 550  	 	 if (!is_object($rs)) {
 551  	 	 	 $false = false;
 552  	 	 	 return $false;
 553  	 	 }
 554  
 555  	 	 $retarr = array();
 556  	 	 while (!$rs->EOF){
 557  	 	 	 $fld = new ADOFieldObject();
 558  	 	 	 $fld->name = $rs->fields[0];
 559  	 	 	 $type = $rs->fields[1];
 560  
 561  	 	 	 // split type into type(length):
 562  	 	 	 $fld->scale = null;
 563  	 	 	 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
 564  	 	 	 	 $fld->type = $query_array[1];
 565  	 	 	 	 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
 566  	 	 	 	 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
 567  	 	 	 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
 568  	 	 	 	 $fld->type = $query_array[1];
 569  	 	 	 	 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
 570  	 	 	 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
 571  	 	 	 	 $fld->type = $query_array[1];
 572  	 	 	 	 $arr = explode(",",$query_array[2]);
 573  	 	 	 	 $fld->enums = $arr;
 574  	 	 	 	 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
 575  	 	 	 	 $fld->max_length = ($zlen > 0) ? $zlen : 1;
 576  	 	 	 } else {
 577  	 	 	 	 $fld->type = $type;
 578  	 	 	 	 $fld->max_length = -1;
 579  	 	 	 }
 580  	 	 	 $fld->not_null = ($rs->fields[2] != 'YES');
 581  	 	 	 $fld->primary_key = ($rs->fields[3] == 'PRI');
 582  	 	 	 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
 583  	 	 	 $fld->binary = (strpos($type,'blob') !== false || strpos($type,'binary') !== false);
 584  	 	 	 $fld->unsigned = (strpos($type,'unsigned') !== false);
 585  	 	 	 $fld->zerofill = (strpos($type,'zerofill') !== false);
 586  
 587  	 	 	 if (!$fld->binary) {
 588  	 	 	 	 $d = $rs->fields[4];
 589  	 	 	 	 if ($d != '' && $d != 'NULL') {
 590  	 	 	 	 	 $fld->has_default = true;
 591  	 	 	 	 	 $fld->default_value = $d;
 592  	 	 	 	 } else {
 593  	 	 	 	 	 $fld->has_default = false;
 594  	 	 	 	 }
 595  	 	 	 }
 596  
 597  	 	 	 if ($save == ADODB_FETCH_NUM) {
 598  	 	 	 	 $retarr[] = $fld;
 599  	 	 	 } else {
 600  	 	 	 	 $retarr[strtoupper($fld->name)] = $fld;
 601  	 	 	 }
 602  	 	 	 	 $rs->MoveNext();
 603  	 	 	 }
 604  
 605  	 	 	 $rs->Close();
 606  	 	 	 return $retarr;
 607  	 }
 608  
 609  	 // returns true or false
 610  	function selectDB($dbName)
 611  	 {
 612  	 	 $this->database = $dbName;
 613  	 	 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
 614  	 	 if ($this->_connectionID) {
 615  	 	 	 return @mysql_select_db($dbName,$this->_connectionID);
 616  	 	 }
 617  	 	 else return false;
 618  	 }
 619  
 620  	 // parameters use PostgreSQL convention, not MySQL
 621  	function selectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
 622  	 {
 623  	 	 $nrows = (int) $nrows;
 624  	 	 $offset = (int) $offset;
 625  	 	 $offsetStr =($offset>=0) ? ((integer)$offset)."," : '';
 626  	 	 // jason judge, see PHPLens Issue No: 9220
 627  	 	 if ($nrows < 0) $nrows = '18446744073709551615';
 628  
 629  	 	 if ($secs)
 630  	 	 	 $rs = $this->CacheExecute($secs,$sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
 631  	 	 else
 632  	 	 	 $rs = $this->Execute($sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
 633  	 	 return $rs;
 634  	 }
 635  
 636  	 // returns queryID or false
 637  	function _query($sql,$inputarr=false)
 638  	 {
 639  
 640  	 return mysql_query($sql,$this->_connectionID);
 641  	 /*
 642  	 global $ADODB_COUNTRECS;
 643  	 	 if($ADODB_COUNTRECS)
 644  	 	 	 return mysql_query($sql,$this->_connectionID);
 645  	 	 else
 646  	 	 	 return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
 647  	 */
 648  	 }
 649  
 650  	 /*	 Returns: the last error message from previous database operation	 */
 651  	function errorMsg()
 652  	 {
 653  
 654  	 	 if ($this->_logsql) return $this->_errorMsg;
 655  	 	 if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
 656  	 	 else $this->_errorMsg = @mysql_error($this->_connectionID);
 657  	 	 return $this->_errorMsg;
 658  	 }
 659  
 660  	 /*	 Returns: the last error number from previous database operation	 */
 661  	function errorNo()
 662  	 {
 663  	 	 if ($this->_logsql) return $this->_errorCode;
 664  	 	 if (empty($this->_connectionID)) return @mysql_errno();
 665  	 	 else return @mysql_errno($this->_connectionID);
 666  	 }
 667  
 668  	 // returns true or false
 669  	function _close()
 670  	 {
 671  	 	 @mysql_close($this->_connectionID);
 672  
 673  	 	 $this->charSet = '';
 674  	 	 $this->_connectionID = false;
 675  	 }
 676  
 677  
 678  	 /*
 679  	 * Maximum size of C field
 680  	 */
 681  	function charMax()
 682  	 {
 683  	 	 return 255;
 684  	 }
 685  
 686  	 /*
 687  	 * Maximum size of X field
 688  	 */
 689  	function textMax()
 690  	 {
 691  	 	 return 4294967295;
 692  	 }
 693  
 694  	 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
 695  	function metaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
 696  	 {
 697  	  global $ADODB_FETCH_MODE;
 698  	 	 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
 699  
 700  	 	 if ( !empty($owner) ) {
 701  	 	 	 $table = "$owner.$table";
 702  	 	 }
 703  	 	 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
 704  	 	 if ($associative) {
 705  	 	 	 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
 706  	 	 } else {
 707  	 	 	 $create_sql = $a_create_table[1];
 708  	 	 }
 709  
 710  	 	 $matches = array();
 711  
 712  	 	 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
 713  	 	 $foreign_keys = array();
 714  	 	 $num_keys = count($matches[0]);
 715  	 	 for ( $i = 0; $i < $num_keys; $i ++ ) {
 716  	 	 	 $my_field  = explode('`, `', $matches[1][$i]);
 717  	 	 	 $ref_table = $matches[2][$i];
 718  	 	 	 $ref_field = explode('`, `', $matches[3][$i]);
 719  
 720  	 	 	 if ( $upper ) {
 721  	 	 	 	 $ref_table = strtoupper($ref_table);
 722  	 	 	 }
 723  
 724  	 	 	 // see https://sourceforge.net/p/adodb/bugs/100/
 725  	 	 	 if (!isset($foreign_keys[$ref_table])) {
 726  	 	 	 	 $foreign_keys[$ref_table] = array();
 727  	 	 	 }
 728  	 	 	 $num_fields = count($my_field);
 729  	 	 	 for ( $j = 0; $j < $num_fields; $j ++ ) {
 730  	 	 	 	 if ( $associative ) {
 731  	 	 	 	 	 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
 732  	 	 	 	 } else {
 733  	 	 	 	 	 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
 734  	 	 	 	 }
 735  	 	 	 }
 736  	 	 }
 737  
 738  	 	 return $foreign_keys;
 739  	 }
 740  
 741  
 742  }
 743  
 744  /*--------------------------------------------------------------------------------------
 745  	  Class Name: Recordset
 746  --------------------------------------------------------------------------------------*/
 747  
 748  
 749  class ADORecordSet_mysql extends ADORecordSet{
 750  
 751  	 var $databaseType = "mysql";
 752  	 var $canSeek = true;
 753  
 754  	function __construct($queryID,$mode=false)
 755  	 {
 756  	 	 if ($mode === false) {
 757  	 	 	 global $ADODB_FETCH_MODE;
 758  	 	 	 $mode = $ADODB_FETCH_MODE;
 759  	 	 }
 760  	 	 switch ($mode)
 761  	 	 {
 762  	 	 case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
 763  	 	 case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
 764  	 	 case ADODB_FETCH_DEFAULT:
 765  	 	 case ADODB_FETCH_BOTH:
 766  	 	 default:
 767  	 	 	 $this->fetchMode = MYSQL_BOTH; break;
 768  	 	 }
 769  	 	 $this->adodbFetchMode = $mode;
 770  	 	 parent::__construct($queryID);
 771  	 }
 772  
 773  	function _initrs()
 774  	 {
 775  	 //GLOBAL $ADODB_COUNTRECS;
 776  	 //	 $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
 777  	 	 $this->_numOfRows = @mysql_num_rows($this->_queryID);
 778  	 	 $this->_numOfFields = @mysql_num_fields($this->_queryID);
 779  	 }
 780  
 781  	function fetchField($fieldOffset = -1)
 782  	 {
 783  	 	 if ($fieldOffset != -1) {
 784  	 	 	 $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
 785  	 	 	 $f = @mysql_field_flags($this->_queryID,$fieldOffset);
 786  	 	 	 if ($o) $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich#att.com)
 787  	 	 	 //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
 788  	 	 	 if ($o) $o->binary = (strpos($f,'binary')!== false);
 789  	 	 }
 790  	 	 else {	 /*	 The $fieldOffset argument is not provided thus its -1 	 */
 791  	 	 	 $o = @mysql_fetch_field($this->_queryID);
 792  	 	 	 //if ($o) $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich#att.com)
 793  	 	 	 $o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
 794  	 	 }
 795  
 796  	 	 return $o;
 797  	 }
 798  
 799  	function getRowAssoc($upper = ADODB_ASSOC_CASE)
 800  	 {
 801  	 	 if ($this->fetchMode == MYSQL_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
 802  	 	 	 $row = $this->fields;
 803  	 	 }
 804  	 	 else {
 805  	 	 	 $row = ADORecordSet::GetRowAssoc($upper);
 806  	 	 }
 807  	 	 return $row;
 808  	 }
 809  
 810  	 /* Use associative array to get fields array */
 811  	function fields($colname)
 812  	 {
 813  	 	 // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
 814  	 	 if ($this->fetchMode != MYSQL_NUM) return @$this->fields[$colname];
 815  
 816  	 	 if (!$this->bind) {
 817  	 	 	 $this->bind = array();
 818  	 	 	 for ($i=0; $i < $this->_numOfFields; $i++) {
 819  	 	 	 	 $o = $this->FetchField($i);
 820  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 821  	 	 	 }
 822  	 	 }
 823  	 	  return $this->fields[$this->bind[strtoupper($colname)]];
 824  	 }
 825  
 826  	function _seek($row)
 827  	 {
 828  	 	 if ($this->_numOfRows == 0) return false;
 829  	 	 return @mysql_data_seek($this->_queryID,$row);
 830  	 }
 831  
 832  	function moveNext()
 833  	 {
 834  	 	 if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
 835  	 	 	 $this->_updatefields();
 836  	 	 	 $this->_currentRow += 1;
 837  	 	 	 return true;
 838  	 	 }
 839  	 	 if (!$this->EOF) {
 840  	 	 	 $this->_currentRow += 1;
 841  	 	 	 $this->EOF = true;
 842  	 	 }
 843  	 	 return false;
 844  	 }
 845  
 846  	function _fetch()
 847  	 {
 848  	 	 $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
 849  	 	 $this->_updatefields();
 850  	 	 return is_array($this->fields);
 851  	 }
 852  
 853  	function _close() {
 854  	 	 @mysql_free_result($this->_queryID);
 855  	 	 $this->_queryID = false;
 856  	 }
 857  
 858  	function metaType($t,$len=-1,$fieldobj=false)
 859  	 {
 860  	 	 if (is_object($t)) {
 861  	 	 	 $fieldobj = $t;
 862  	 	 	 $t = $fieldobj->type;
 863  	 	 	 $len = $fieldobj->max_length;
 864  	 	 }
 865  
 866  	 	 $len = -1; // mysql max_length is not accurate
 867  	 	 switch (strtoupper($t)) {
 868  	 	 case 'STRING':
 869  	 	 case 'CHAR':
 870  	 	 case 'VARCHAR':
 871  	 	 case 'TINYBLOB':
 872  	 	 case 'TINYTEXT':
 873  	 	 case 'ENUM':
 874  	 	 case 'SET':
 875  	 	 	 if ($len <= $this->blobSize) return 'C';
 876  
 877  	 	 case 'TEXT':
 878  	 	 case 'LONGTEXT':
 879  	 	 case 'MEDIUMTEXT':
 880  	 	 	 return 'X';
 881  
 882  	 	 // php_mysql extension always returns 'blob' even if 'text'
 883  	 	 // so we have to check whether binary...
 884  	 	 case 'IMAGE':
 885  	 	 case 'LONGBLOB':
 886  	 	 case 'BLOB':
 887  	 	 case 'MEDIUMBLOB':
 888  	 	 case 'BINARY':
 889  	 	 	 return !empty($fieldobj->binary) ? 'B' : 'X';
 890  
 891  	 	 case 'YEAR':
 892  	 	 case 'DATE': return 'D';
 893  
 894  	 	 case 'TIME':
 895  	 	 case 'DATETIME':
 896  	 	 case 'TIMESTAMP': return 'T';
 897  
 898  	 	 case 'INT':
 899  	 	 case 'INTEGER':
 900  	 	 case 'BIGINT':
 901  	 	 case 'TINYINT':
 902  	 	 case 'MEDIUMINT':
 903  	 	 case 'SMALLINT':
 904  
 905  	 	 	 if (!empty($fieldobj->primary_key)) return 'R';
 906  	 	 	 else return 'I';
 907  
 908  	 	 default: return ADODB_DEFAULT_METATYPE;
 909  	 	 }
 910  	 }
 911  
 912  }
 913  
 914  /**
 915   * Class ADORecordSet_ext_mysql
 916   */
 917  class ADORecordSet_ext_mysql extends ADORecordSet_mysql {
 918  
 919  	function moveNext()
 920  	 {
 921  	 	 return @adodb_movenext($this);
 922  	 }
 923  }
 924  
 925  }