Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

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

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