Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  /*
   3  @version   v5.20.16  12-Jan-2020
   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 is the preferred driver for MySQL connections, and supports both transactional
  12    and non-transactional table types. You can use this as a drop-in replacement for both
  13    the mysql and mysqlt drivers. As of ADOdb Version 5.20.0, all other native MySQL drivers
  14    are deprecated
  15    
  16    Requires mysql client. Works on Windows and Unix.
  17  
  18  21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
  19  Based on adodb 3.40
  20  */
  21  
  22  // security - hide paths
  23  if (!defined('ADODB_DIR')) die();
  24  
  25  if (! defined("_ADODB_MYSQLI_LAYER")) {
  26   define("_ADODB_MYSQLI_LAYER", 1 );
  27  
  28   // PHP5 compat...
  29   if (! defined("MYSQLI_BINARY_FLAG"))  define("MYSQLI_BINARY_FLAG", 128);
  30   if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1);
  31  
  32   // disable adodb extension - currently incompatible.
  33   global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
  34  
  35  class ADODB_mysqli extends ADOConnection {
  36  	 var $databaseType = 'mysqli';
  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 = true;
  54  	 var $forceNewConnect = false;
  55  	 var $poorAffectedRows = true;
  56  	 var $clientFlags = 0;
  57  	 var $substr = "substring";
  58  	 var $port = 3306; //Default to 3306 to fix HHVM bug
  59  	 var $socket = ''; //Default to empty string to fix HHVM bug
  60  	 var $_bindInputArray = false;
  61  	 var $nameQuote = '`';	 	 /// string to use to quote identifiers and names
  62  	 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0));
  63  	 var $arrayClass = 'ADORecordSet_array_mysqli';
  64  	 var $multiQuery = false;
  65  
  66  	function __construct()
  67  	 {
  68  	 	 // if(!extension_loaded("mysqli"))
  69  	 	 //trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
  70  	 }
  71  
  72  	function SetTransactionMode( $transaction_mode )
  73  	 {
  74  	 	 $this->_transmode = $transaction_mode;
  75  	 	 if (empty($transaction_mode)) {
  76  	 	 	 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
  77  	 	 	 return;
  78  	 	 }
  79  	 	 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
  80  	 	 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
  81  	 }
  82  
  83  	 // returns true or false
  84  	 // To add: parameter int $port,
  85  	 //         parameter string $socket
  86  	function _connect($argHostname = NULL,
  87  	 	 	 	 $argUsername = NULL,
  88  	 	 	 	 $argPassword = NULL,
  89  	 	 	 	 $argDatabasename = NULL, $persist=false)
  90  	 {
  91  	 	 if(!extension_loaded("mysqli")) {
  92  	 	 	 return null;
  93  	 	 }
  94  	 	 $this->_connectionID = @mysqli_init();
  95  
  96  	 	 if (is_null($this->_connectionID)) {
  97  	 	 	 // mysqli_init only fails if insufficient memory
  98  	 	 	 if ($this->debug) {
  99  	 	 	 	 ADOConnection::outp("mysqli_init() failed : "  . $this->ErrorMsg());
 100  	 	 	 }
 101  	 	 	 return false;
 102  	 	 }
 103  	 	 /*
 104  	 	 I suggest a simple fix which would enable adodb and mysqli driver to
 105  	 	 read connection options from the standard mysql configuration file
 106  	 	 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
 107  	 	 */
 108  	 	 foreach($this->optionFlags as $arr) {
 109  	 	 	 mysqli_options($this->_connectionID,$arr[0],$arr[1]);
 110  	 	 }
 111  
 112  	 	 //http ://php.net/manual/en/mysqli.persistconns.php
 113  	 	 if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname,'p:',2) != 0) $argHostname = 'p:'.$argHostname;
 114  
 115  	 	 #if (!empty($this->port)) $argHostname .= ":".$this->port;
 116  	 	 $ok = @mysqli_real_connect($this->_connectionID,
 117  	 	 	 	 	 $argHostname,
 118  	 	 	 	 	 $argUsername,
 119  	 	 	 	 	 $argPassword,
 120  	 	 	 	 	 $argDatabasename,
 121  	 	 	 	 	 # PHP7 compat: port must be int. Use default port if cast yields zero
 122  	 	 	 	 	 (int)$this->port != 0 ? (int)$this->port : 3306,
 123  	 	 	 	 	 $this->socket,
 124  	 	 	 	 	 $this->clientFlags);
 125  
 126  	 	 if ($ok) {
 127  	 	 	 if ($argDatabasename)  return $this->SelectDB($argDatabasename);
 128  	 	 	 return true;
 129  	 	 } else {
 130  	 	 	 if ($this->debug) {
 131  	 	 	 	 ADOConnection::outp("Could not connect : "  . $this->ErrorMsg());
 132  	 	 	 }
 133  	 	 	 $this->_connectionID = null;
 134  	 	 	 return false;
 135  	 	 }
 136  	 }
 137  
 138  	 // returns true or false
 139  	 // How to force a persistent connection
 140  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 141  	 {
 142  	 	 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
 143  	 }
 144  
 145  	 // When is this used? Close old connection first?
 146  	 // In _connect(), check $this->forceNewConnect?
 147  	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 148  	 {
 149  	 	 $this->forceNewConnect = true;
 150  	 	 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
 151  	 }
 152  
 153  	function IfNull( $field, $ifNull )
 154  	 {
 155  	 	 return " IFNULL($field, $ifNull) "; // if MySQL
 156  	 }
 157  
 158  	 // do not use $ADODB_COUNTRECS
 159  	function GetOne($sql,$inputarr=false)
 160  	 {
 161  	 	 global $ADODB_GETONE_EOF;
 162  
 163  	 	 $ret = false;
 164  	 	 $rs = $this->Execute($sql,$inputarr);
 165  	 	 if ($rs) {
 166  	 	 	 if ($rs->EOF) $ret = $ADODB_GETONE_EOF;
 167  	 	 	 else $ret = reset($rs->fields);
 168  	 	 	 $rs->Close();
 169  	 	 }
 170  	 	 return $ret;
 171  	 }
 172  
 173  	function ServerInfo()
 174  	 {
 175  	 	 $arr['description'] = $this->GetOne("select version()");
 176  	 	 $arr['version'] = ADOConnection::_findvers($arr['description']);
 177  	 	 return $arr;
 178  	 }
 179  
 180  
 181  	function BeginTrans()
 182  	 {
 183  	 	 if ($this->transOff) return true;
 184  	 	 $this->transCnt += 1;
 185  
 186  	 	 //$this->Execute('SET AUTOCOMMIT=0');
 187  	 	 mysqli_autocommit($this->_connectionID, false);
 188  	 	 $this->Execute('BEGIN');
 189  	 	 return true;
 190  	 }
 191  
 192  	function CommitTrans($ok=true)
 193  	 {
 194  	 	 if ($this->transOff) return true;
 195  	 	 if (!$ok) return $this->RollbackTrans();
 196  
 197  	 	 if ($this->transCnt) $this->transCnt -= 1;
 198  	 	 $this->Execute('COMMIT');
 199  
 200  	 	 //$this->Execute('SET AUTOCOMMIT=1');
 201  	 	 mysqli_autocommit($this->_connectionID, true);
 202  	 	 return true;
 203  	 }
 204  
 205  	function RollbackTrans()
 206  	 {
 207  	 	 if ($this->transOff) return true;
 208  	 	 if ($this->transCnt) $this->transCnt -= 1;
 209  	 	 $this->Execute('ROLLBACK');
 210  	 	 //$this->Execute('SET AUTOCOMMIT=1');
 211  	 	 mysqli_autocommit($this->_connectionID, true);
 212  	 	 return true;
 213  	 }
 214  
 215  	function RowLock($tables,$where='',$col='1 as adodbignore')
 216  	 {
 217  	 	 if ($this->transCnt==0) $this->BeginTrans();
 218  	 	 if ($where) $where = ' where '.$where;
 219  	 	 $rs = $this->Execute("select $col from $tables $where for update");
 220  	 	 return !empty($rs);
 221  	 }
 222  
 223  	 /**
 224  	  * Quotes a string to be sent to the database
 225  	  * When there is no active connection,
 226  	  * @param string $s The string to quote
 227  	  * @param boolean $magic_quotes If false, use mysqli_real_escape_string()
 228  	  *     if you are quoting a string extracted from a POST/GET variable,
 229  	  *     then pass get_magic_quotes_gpc() as the second parameter. This will
 230  	  *     ensure that the variable is not quoted twice, once by qstr() and
 231  	  *     once by the magic_quotes_gpc.
 232  	  *     Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
 233  	  * @return string Quoted string
 234  	  */
 235  	function qstr($s, $magic_quotes = false)
 236  	 {
 237  	 	 if (is_null($s)) return 'NULL';
 238  	 	 if (!$magic_quotes) {
 239  	 	 	 // mysqli_real_escape_string() throws a warning when the given
 240  	 	 	 // connection is invalid
 241  	 	 	 if (PHP_VERSION >= 5 && $this->_connectionID) {
 242  	 	 	 	 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
 243  	 	 	 }
 244  
 245  	 	 	 if ($this->replaceQuote[0] == '\\') {
 246  	 	 	 	 $s = adodb_str_replace(array('\\',"\0"), array('\\\\',"\\\0") ,$s);
 247  	 	 	 }
 248  	 	 	 return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
 249  	 	 }
 250  	 	 // undo magic quotes for "
 251  	 	 $s = str_replace('\\"','"',$s);
 252  	 	 return "'$s'";
 253  	 }
 254  
 255  	function _insertid()
 256  	 {
 257  	 	 $result = @mysqli_insert_id($this->_connectionID);
 258  	 	 if ($result == -1) {
 259  	 	 	 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : "  . $this->ErrorMsg());
 260  	 	 }
 261  	 	 return $result;
 262  	 }
 263  
 264  	 // Only works for INSERT, UPDATE and DELETE query's
 265  	function _affectedrows()
 266  	 {
 267  	 	 $result =  @mysqli_affected_rows($this->_connectionID);
 268  	 	 if ($result == -1) {
 269  	 	 	 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : "  . $this->ErrorMsg());
 270  	 	 }
 271  	 	 return $result;
 272  	 }
 273  
 274  	 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
 275  	 // Reference on Last_Insert_ID on the recommended way to simulate sequences
 276  	 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
 277  	 var $_genSeqSQL = "create table if not exists %s (id int not null)";
 278  	 var $_genSeqCountSQL = "select count(*) from %s";
 279  	 var $_genSeq2SQL = "insert into %s values (%s)";
 280  	 var $_dropSeqSQL = "drop table if exists %s";
 281  
 282  	function CreateSequence($seqname='adodbseq',$startID=1)
 283  	 {
 284  	 	 if (empty($this->_genSeqSQL)) return false;
 285  	 	 $u = strtoupper($seqname);
 286  
 287  	 	 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
 288  	 	 if (!$ok) return false;
 289  	 	 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
 290  	 }
 291  
 292  	function GenID($seqname='adodbseq',$startID=1)
 293  	 {
 294  	 	 // post-nuke sets hasGenID to false
 295  	 	 if (!$this->hasGenID) return false;
 296  
 297  	 	 $getnext = sprintf($this->_genIDSQL,$seqname);
 298  	 	 $holdtransOK = $this->_transOK; // save the current status
 299  	 	 $rs = @$this->Execute($getnext);
 300  	 	 if (!$rs) {
 301  	 	 	 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
 302  	 	 	 $u = strtoupper($seqname);
 303  	 	 	 $this->Execute(sprintf($this->_genSeqSQL,$seqname));
 304  	 	 	 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
 305  	 	 	 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
 306  	 	 	 $rs = $this->Execute($getnext);
 307  	 	 }
 308  
 309  	 	 if ($rs) {
 310  	 	 	 $this->genID = mysqli_insert_id($this->_connectionID);
 311  	 	 	 $rs->Close();
 312  	 	 } else
 313  	 	 	 $this->genID = 0;
 314  
 315  	 	 return $this->genID;
 316  	 }
 317  
 318  	function MetaDatabases()
 319  	 {
 320  	 	 $query = "SHOW DATABASES";
 321  	 	 $ret = $this->Execute($query);
 322  	 	 if ($ret && is_object($ret)){
 323  	 	 	 $arr = array();
 324  	 	 	 while (!$ret->EOF){
 325  	 	 	 	 $db = $ret->Fields('Database');
 326  	 	 	 	 if ($db != 'mysql') $arr[] = $db;
 327  	 	 	 	 $ret->MoveNext();
 328  	 	 	 }
 329  	 	 	 return $arr;
 330  	 	 }
 331  	 	 return $ret;
 332  	 }
 333  
 334  
 335  	function MetaIndexes ($table, $primary = FALSE, $owner = false)
 336  	 {
 337  	 	 // save old fetch mode
 338  	 	 global $ADODB_FETCH_MODE;
 339  
 340  	 	 $false = false;
 341  	 	 $save = $ADODB_FETCH_MODE;
 342  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 343  	 	 if ($this->fetchMode !== FALSE) {
 344  	 	 	 $savem = $this->SetFetchMode(FALSE);
 345  	 	 }
 346  
 347  	 	 // get index details
 348  	 	 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table));
 349  
 350  	 	 // restore fetchmode
 351  	 	 if (isset($savem)) {
 352  	 	 	 $this->SetFetchMode($savem);
 353  	 	 }
 354  	 	 $ADODB_FETCH_MODE = $save;
 355  
 356  	 	 if (!is_object($rs)) {
 357  	 	 	 return $false;
 358  	 	 }
 359  
 360  	 	 $indexes = array ();
 361  
 362  	 	 // parse index data into array
 363  	 	 while ($row = $rs->FetchRow()) {
 364  	 	 	 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
 365  	 	 	 	 continue;
 366  	 	 	 }
 367  
 368  	 	 	 if (!isset($indexes[$row[2]])) {
 369  	 	 	 	 $indexes[$row[2]] = array(
 370  	 	 	 	 	 'unique' => ($row[1] == 0),
 371  	 	 	 	 	 'columns' => array()
 372  	 	 	 	 );
 373  	 	 	 }
 374  
 375  	 	 	 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
 376  	 	 }
 377  
 378  	 	 // sort columns by order in the index
 379  	 	 foreach ( array_keys ($indexes) as $index )
 380  	 	 {
 381  	 	 	 ksort ($indexes[$index]['columns']);
 382  	 	 }
 383  
 384  	 	 return $indexes;
 385  	 }
 386  
 387  
 388  	 // Format date column in sql string given an input format that understands Y M D
 389  	function SQLDate($fmt, $col=false)
 390  	 {
 391  	 	 if (!$col) $col = $this->sysTimeStamp;
 392  	 	 $s = 'DATE_FORMAT('.$col.",'";
 393  	 	 $concat = false;
 394  	 	 $len = strlen($fmt);
 395  	 	 for ($i=0; $i < $len; $i++) {
 396  	 	 	 $ch = $fmt[$i];
 397  	 	 	 switch($ch) {
 398  	 	 	 case 'Y':
 399  	 	 	 case 'y':
 400  	 	 	 	 $s .= '%Y';
 401  	 	 	 	 break;
 402  	 	 	 case 'Q':
 403  	 	 	 case 'q':
 404  	 	 	 	 $s .= "'),Quarter($col)";
 405  
 406  	 	 	 	 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
 407  	 	 	 	 else $s .= ",('";
 408  	 	 	 	 $concat = true;
 409  	 	 	 	 break;
 410  	 	 	 case 'M':
 411  	 	 	 	 $s .= '%b';
 412  	 	 	 	 break;
 413  
 414  	 	 	 case 'm':
 415  	 	 	 	 $s .= '%m';
 416  	 	 	 	 break;
 417  	 	 	 case 'D':
 418  	 	 	 case 'd':
 419  	 	 	 	 $s .= '%d';
 420  	 	 	 	 break;
 421  
 422  	 	 	 case 'H':
 423  	 	 	 	 $s .= '%H';
 424  	 	 	 	 break;
 425  
 426  	 	 	 case 'h':
 427  	 	 	 	 $s .= '%I';
 428  	 	 	 	 break;
 429  
 430  	 	 	 case 'i':
 431  	 	 	 	 $s .= '%i';
 432  	 	 	 	 break;
 433  
 434  	 	 	 case 's':
 435  	 	 	 	 $s .= '%s';
 436  	 	 	 	 break;
 437  
 438  	 	 	 case 'a':
 439  	 	 	 case 'A':
 440  	 	 	 	 $s .= '%p';
 441  	 	 	 	 break;
 442  
 443  	 	 	 case 'w':
 444  	 	 	 	 $s .= '%w';
 445  	 	 	 	 break;
 446  
 447  	 	 	 case 'l':
 448  	 	 	 	 $s .= '%W';
 449  	 	 	 	 break;
 450  
 451  	 	 	 default:
 452  
 453  	 	 	 	 if ($ch == '\\') {
 454  	 	 	 	 	 $i++;
 455  	 	 	 	 	 $ch = substr($fmt,$i,1);
 456  	 	 	 	 }
 457  	 	 	 	 $s .= $ch;
 458  	 	 	 	 break;
 459  	 	 	 }
 460  	 	 }
 461  	 	 $s.="')";
 462  	 	 if ($concat) $s = "CONCAT($s)";
 463  	 	 return $s;
 464  	 }
 465  
 466  	 // returns concatenated string
 467  	 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
 468  	function Concat()
 469  	 {
 470  	 	 $s = "";
 471  	 	 $arr = func_get_args();
 472  
 473  	 	 // suggestion by andrew005@mnogo.ru
 474  	 	 $s = implode(',',$arr);
 475  	 	 if (strlen($s) > 0) return "CONCAT($s)";
 476  	 	 else return '';
 477  	 }
 478  
 479  	 // dayFraction is a day in floating point
 480  	function OffsetDate($dayFraction,$date=false)
 481  	 {
 482  	 	 if (!$date) $date = $this->sysDate;
 483  
 484  	 	 $fraction = $dayFraction * 24 * 3600;
 485  	 	 return $date . ' + INTERVAL ' .	  $fraction.' SECOND';
 486  
 487  //	 	 return "from_unixtime(unix_timestamp($date)+$fraction)";
 488  	 }
 489  
 490  	function MetaProcedures($NamePattern = false, $catalog  = null, $schemaPattern  = null)
 491  	 {
 492  	 	 // save old fetch mode
 493  	 	 global $ADODB_FETCH_MODE;
 494  
 495  	 	 $false = false;
 496  	 	 $save = $ADODB_FETCH_MODE;
 497  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 498  
 499  	 	 if ($this->fetchMode !== FALSE) {
 500  	 	 	 $savem = $this->SetFetchMode(FALSE);
 501  	 	 }
 502  
 503  	 	 $procedures = array ();
 504  
 505  	 	 // get index details
 506  
 507  	 	 $likepattern = '';
 508  	 	 if ($NamePattern) {
 509  	 	 	 $likepattern = " LIKE '".$NamePattern."'";
 510  	 	 }
 511  	 	 $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern);
 512  	 	 if (is_object($rs)) {
 513  
 514  	 	 	 // parse index data into array
 515  	 	 	 while ($row = $rs->FetchRow()) {
 516  	 	 	 	 $procedures[$row[1]] = array(
 517  	 	 	 	 	 'type' => 'PROCEDURE',
 518  	 	 	 	 	 'catalog' => '',
 519  	 	 	 	 	 'schema' => '',
 520  	 	 	 	 	 'remarks' => $row[7],
 521  	 	 	 	 );
 522  	 	 	 }
 523  	 	 }
 524  
 525  	 	 $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern);
 526  	 	 if (is_object($rs)) {
 527  	 	 	 // parse index data into array
 528  	 	 	 while ($row = $rs->FetchRow()) {
 529  	 	 	 	 $procedures[$row[1]] = array(
 530  	 	 	 	 	 'type' => 'FUNCTION',
 531  	 	 	 	 	 'catalog' => '',
 532  	 	 	 	 	 'schema' => '',
 533  	 	 	 	 	 'remarks' => $row[7]
 534  	 	 	 	 );
 535  	 	 	 }
 536  	 	 }
 537  
 538  	 	 // restore fetchmode
 539  	 	 if (isset($savem)) {
 540  	 	 	 	 $this->SetFetchMode($savem);
 541  	 	 }
 542  	 	 $ADODB_FETCH_MODE = $save;
 543  
 544  	 	 return $procedures;
 545  	 }
 546  
 547  	 /**
 548  	  * Retrieves a list of tables based on given criteria
 549  	  *
 550  	  * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default)
 551  	  * @param string $showSchema schema name, false = current schema (default)
 552  	  * @param string $mask filters the table by name
 553  	  *
 554  	  * @return array list of tables
 555  	  */
 556  	function MetaTables($ttype=false,$showSchema=false,$mask=false)
 557  	 {
 558  	 	 $save = $this->metaTablesSQL;
 559  	 	 if ($showSchema && is_string($showSchema)) {
 560  	 	 	 $this->metaTablesSQL .= $this->qstr($showSchema);
 561  	 	 } else {
 562  	 	 	 $this->metaTablesSQL .= "schema()";
 563  	 	 }
 564  
 565  	 	 if ($mask) {
 566  	 	 	 $mask = $this->qstr($mask);
 567  	 	 	 $this->metaTablesSQL .= " AND table_name LIKE $mask";
 568  	 	 }
 569  	 	 $ret = ADOConnection::MetaTables($ttype,$showSchema);
 570  
 571  	 	 $this->metaTablesSQL = $save;
 572  	 	 return $ret;
 573  	 }
 574  
 575  	 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
 576  	function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
 577  	 {
 578  	  global $ADODB_FETCH_MODE;
 579  
 580  	 	 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
 581  
 582  	 	 if ( !empty($owner) ) {
 583  	 	 	 $table = "$owner.$table";
 584  	 	 }
 585  	 	 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
 586  	 	 if ($associative) {
 587  	 	 	 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
 588  	 	 } else $create_sql = $a_create_table[1];
 589  
 590  	 	 $matches = array();
 591  
 592  	 	 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
 593  	 	 $foreign_keys = array();
 594  	 	 $num_keys = count($matches[0]);
 595  	 	 for ( $i = 0; $i < $num_keys; $i ++ ) {
 596  	 	 	 $my_field  = explode('`, `', $matches[1][$i]);
 597  	 	 	 $ref_table = $matches[2][$i];
 598  	 	 	 $ref_field = explode('`, `', $matches[3][$i]);
 599  
 600  	 	 	 if ( $upper ) {
 601  	 	 	 	 $ref_table = strtoupper($ref_table);
 602  	 	 	 }
 603  
 604  	 	 	 // see https://sourceforge.net/p/adodb/bugs/100/
 605  	 	 	 if (!isset($foreign_keys[$ref_table])) {
 606  	 	 	 	 $foreign_keys[$ref_table] = array();
 607  	 	 	 }
 608  	 	 	 $num_fields = count($my_field);
 609  	 	 	 for ( $j = 0; $j < $num_fields; $j ++ ) {
 610  	 	 	 	 if ( $associative ) {
 611  	 	 	 	 	 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
 612  	 	 	 	 } else {
 613  	 	 	 	 	 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
 614  	 	 	 	 }
 615  	 	 	 }
 616  	 	 }
 617  
 618  	 	 return $foreign_keys;
 619  	 }
 620  
 621  	function MetaColumns($table, $normalize=true)
 622  	 {
 623  	 	 $false = false;
 624  	 	 if (!$this->metaColumnsSQL)
 625  	 	 	 return $false;
 626  
 627  	 	 global $ADODB_FETCH_MODE;
 628  	 	 $save = $ADODB_FETCH_MODE;
 629  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 630  	 	 if ($this->fetchMode !== false)
 631  	 	 	 $savem = $this->SetFetchMode(false);
 632  	 	 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
 633  	 	 if (isset($savem)) $this->SetFetchMode($savem);
 634  	 	 $ADODB_FETCH_MODE = $save;
 635  	 	 if (!is_object($rs))
 636  	 	 	 return $false;
 637  
 638  	 	 $retarr = array();
 639  	 	 while (!$rs->EOF) {
 640  	 	 	 $fld = new ADOFieldObject();
 641  	 	 	 $fld->name = $rs->fields[0];
 642  	 	 	 $type = $rs->fields[1];
 643  
 644  	 	 	 // split type into type(length):
 645  	 	 	 $fld->scale = null;
 646  	 	 	 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
 647  	 	 	 	 $fld->type = $query_array[1];
 648  	 	 	 	 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
 649  	 	 	 	 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
 650  	 	 	 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
 651  	 	 	 	 $fld->type = $query_array[1];
 652  	 	 	 	 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
 653  	 	 	 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
 654  	 	 	 	 $fld->type = $query_array[1];
 655  	 	 	 	 $arr = explode(",",$query_array[2]);
 656  	 	 	 	 $fld->enums = $arr;
 657  	 	 	 	 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
 658  	 	 	 	 $fld->max_length = ($zlen > 0) ? $zlen : 1;
 659  	 	 	 } else {
 660  	 	 	 	 $fld->type = $type;
 661  	 	 	 	 $fld->max_length = -1;
 662  	 	 	 }
 663  	 	 	 $fld->not_null = ($rs->fields[2] != 'YES');
 664  	 	 	 $fld->primary_key = ($rs->fields[3] == 'PRI');
 665  	 	 	 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
 666  	 	 	 $fld->binary = (strpos($type,'blob') !== false);
 667  	 	 	 $fld->unsigned = (strpos($type,'unsigned') !== false);
 668  	 	 	 $fld->zerofill = (strpos($type,'zerofill') !== false);
 669  
 670  	 	 	 if (!$fld->binary) {
 671  	 	 	 	 $d = $rs->fields[4];
 672  	 	 	 	 if ($d != '' && $d != 'NULL') {
 673  	 	 	 	 	 $fld->has_default = true;
 674  	 	 	 	 	 $fld->default_value = $d;
 675  	 	 	 	 } else {
 676  	 	 	 	 	 $fld->has_default = false;
 677  	 	 	 	 }
 678  	 	 	 }
 679  
 680  	 	 	 if ($save == ADODB_FETCH_NUM) {
 681  	 	 	 	 $retarr[] = $fld;
 682  	 	 	 } else {
 683  	 	 	 	 $retarr[strtoupper($fld->name)] = $fld;
 684  	 	 	 }
 685  	 	 	 $rs->MoveNext();
 686  	 	 }
 687  
 688  	 	 $rs->Close();
 689  	 	 return $retarr;
 690  	 }
 691  
 692  	 // returns true or false
 693  	function SelectDB($dbName)
 694  	 {
 695  //	 	 $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
 696  	 	 $this->database = $dbName;
 697  	 	 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
 698  
 699  	 	 if ($this->_connectionID) {
 700  	 	 	 $result = @mysqli_select_db($this->_connectionID, $dbName);
 701  	 	 	 if (!$result) {
 702  	 	 	 	 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
 703  	 	 	 }
 704  	 	 	 return $result;
 705  	 	 }
 706  	 	 return false;
 707  	 }
 708  
 709  	 // parameters use PostgreSQL convention, not MySQL
 710  	function SelectLimit($sql,
 711  	 	 	 	 $nrows = -1,
 712  	 	 	 	 $offset = -1,
 713  	 	 	 	 $inputarr = false,
 714  	 	 	 	 $secs = 0)
 715  	 {
 716  	 	 $nrows = (int) $nrows;
 717  	 	 $offset = (int) $offset;
 718  	 	 $offsetStr = ($offset >= 0) ? "$offset," : '';
 719  	 	 if ($nrows < 0) $nrows = '18446744073709551615';
 720  
 721  	 	 if ($secs)
 722  	 	 	 $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr );
 723  	 	 else
 724  	 	 	 $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr );
 725  
 726  	 	 return $rs;
 727  	 }
 728  
 729  
 730  	function Prepare($sql)
 731  	 {
 732  	 	 return $sql;
 733  	 	 $stmt = $this->_connectionID->prepare($sql);
 734  	 	 if (!$stmt) {
 735  	 	 	 echo $this->ErrorMsg();
 736  	 	 	 return $sql;
 737  	 	 }
 738  	 	 return array($sql,$stmt);
 739  	 }
 740  
 741  
 742  	 // returns queryID or false
 743  	function _query($sql, $inputarr)
 744  	 {
 745  	 global $ADODB_COUNTRECS;
 746  	 	 // Move to the next recordset, or return false if there is none. In a stored proc
 747  	 	 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
 748  	 	 // returns false. I think this is because the last "recordset" is actually just the
 749  	 	 // return value of the stored proc (ie the number of rows affected).
 750  	 	 // Commented out for reasons of performance. You should retrieve every recordset yourself.
 751  	 	 //	 if (!mysqli_next_result($this->connection->_connectionID))	 return false;
 752  
 753  	 	 if (is_array($sql)) {
 754  
 755  	 	 	 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but
 756  	 	 	 // returns as bound variables.
 757  
 758  	 	 	 $stmt = $sql[1];
 759  	 	 	 $a = '';
 760  	 	 	 foreach($inputarr as $k => $v) {
 761  	 	 	 	 if (is_string($v)) $a .= 's';
 762  	 	 	 	 else if (is_integer($v)) $a .= 'i';
 763  	 	 	 	 else $a .= 'd';
 764  	 	 	 }
 765  
 766  	 	 	 $fnarr = array_merge( array($stmt,$a) , $inputarr);
 767  	 	 	 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr);
 768  	 	 	 $ret = mysqli_stmt_execute($stmt);
 769  	 	 	 return $ret;
 770  	 	 }
 771  
 772  	 	 /*
 773  	 	 if (!$mysql_res =  mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
 774  	 	 	 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
 775  	 	 	 return false;
 776  	 	 }
 777  
 778  	 	 return $mysql_res;
 779  	 	 */
 780  
 781  	 	 if ($this->multiQuery) {
 782  	 	 	 $rs = mysqli_multi_query($this->_connectionID, $sql.';');
 783  	 	 	 if ($rs) {
 784  	 	 	 	 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID );
 785  	 	 	 	 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID )
 786  	 	 	 }
 787  	 	 } else {
 788  	 	 	 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
 789  
 790  	 	 	 if ($rs) return $rs;
 791  	 	 }
 792  
 793  	 	 if($this->debug)
 794  	 	 	 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
 795  
 796  	 	 return false;
 797  
 798  	 }
 799  
 800  	 /*	 Returns: the last error message from previous database operation	 */
 801  	function ErrorMsg()
 802  	 {
 803  	 	 if (empty($this->_connectionID))
 804  	 	 	 $this->_errorMsg = @mysqli_connect_error();
 805  	 	 else
 806  	 	 	 $this->_errorMsg = @mysqli_error($this->_connectionID);
 807  	 	 return $this->_errorMsg;
 808  	 }
 809  
 810  	 /*	 Returns: the last error number from previous database operation	 */
 811  	function ErrorNo()
 812  	 {
 813  	 	 if (empty($this->_connectionID))
 814  	 	 	 return @mysqli_connect_errno();
 815  	 	 else
 816  	 	 	 return @mysqli_errno($this->_connectionID);
 817  	 }
 818  
 819  	 // returns true or false
 820  	function _close()
 821  	 {
 822  	 	 @mysqli_close($this->_connectionID);
 823  	 	 $this->_connectionID = false;
 824  	 }
 825  
 826  	 /*
 827  	 * Maximum size of C field
 828  	 */
 829  	function CharMax()
 830  	 {
 831  	 	 return 255;
 832  	 }
 833  
 834  	 /*
 835  	 * Maximum size of X field
 836  	 */
 837  	function TextMax()
 838  	 {
 839  	 	 return 4294967295;
 840  	 }
 841  
 842  
 843  	 // this is a set of functions for managing client encoding - very important if the encodings
 844  	 // of your database and your output target (i.e. HTML) don't match
 845  	 // for instance, you may have UTF8 database and server it on-site as latin1 etc.
 846  	 // GetCharSet - get the name of the character set the client is using now
 847  	 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
 848  	 // depends on compile flags of mysql distribution
 849  
 850  	function GetCharSet()
 851  	 {
 852  	 	 //we will use ADO's builtin property charSet
 853  	 	 if (!method_exists($this->_connectionID,'character_set_name'))
 854  	 	 	 return false;
 855  
 856  	 	 $this->charSet = @$this->_connectionID->character_set_name();
 857  	 	 if (!$this->charSet) {
 858  	 	 	 return false;
 859  	 	 } else {
 860  	 	 	 return $this->charSet;
 861  	 	 }
 862  	 }
 863  
 864  	 // SetCharSet - switch the client encoding
 865  	function SetCharSet($charset_name)
 866  	 {
 867  	 	 if (!method_exists($this->_connectionID,'set_charset')) {
 868  	 	 	 return false;
 869  	 	 }
 870  
 871  	 	 if ($this->charSet !== $charset_name) {
 872  	 	 	 $if = @$this->_connectionID->set_charset($charset_name);
 873  	 	 	 return ($if === true & $this->GetCharSet() == $charset_name);
 874  	 	 } else {
 875  	 	 	 return true;
 876  	 	 }
 877  	 }
 878  
 879  }
 880  
 881  /*--------------------------------------------------------------------------------------
 882  	  Class Name: Recordset
 883  --------------------------------------------------------------------------------------*/
 884  
 885  class ADORecordSet_mysqli extends ADORecordSet{
 886  
 887  	 var $databaseType = "mysqli";
 888  	 var $canSeek = true;
 889  
 890  	function __construct($queryID, $mode = false)
 891  	 {
 892  	 	 if ($mode === false) {
 893  	 	 	 global $ADODB_FETCH_MODE;
 894  	 	 	 $mode = $ADODB_FETCH_MODE;
 895  	 	 }
 896  
 897  	 	 switch ($mode) {
 898  	 	 	 case ADODB_FETCH_NUM:
 899  	 	 	 	 $this->fetchMode = MYSQLI_NUM;
 900  	 	 	 	 break;
 901  	 	 	 case ADODB_FETCH_ASSOC:
 902  	 	 	 	 $this->fetchMode = MYSQLI_ASSOC;
 903  	 	 	 	 break;
 904  	 	 	 case ADODB_FETCH_DEFAULT:
 905  	 	 	 case ADODB_FETCH_BOTH:
 906  	 	 	 default:
 907  	 	 	 	 $this->fetchMode = MYSQLI_BOTH;
 908  	 	 	 	 break;
 909  	 	 }
 910  	 	 $this->adodbFetchMode = $mode;
 911  	 	 parent::__construct($queryID);
 912  	 }
 913  
 914  	function _initrs()
 915  	 {
 916  	 global $ADODB_COUNTRECS;
 917  
 918  	 	 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
 919  	 	 $this->_numOfFields = @mysqli_num_fields($this->_queryID);
 920  	 }
 921  
 922  /*
 923  1      = MYSQLI_NOT_NULL_FLAG
 924  2      = MYSQLI_PRI_KEY_FLAG
 925  4      = MYSQLI_UNIQUE_KEY_FLAG
 926  8      = MYSQLI_MULTIPLE_KEY_FLAG
 927  16     = MYSQLI_BLOB_FLAG
 928  32     = MYSQLI_UNSIGNED_FLAG
 929  64     = MYSQLI_ZEROFILL_FLAG
 930  128    = MYSQLI_BINARY_FLAG
 931  256    = MYSQLI_ENUM_FLAG
 932  512    = MYSQLI_AUTO_INCREMENT_FLAG
 933  1024   = MYSQLI_TIMESTAMP_FLAG
 934  2048   = MYSQLI_SET_FLAG
 935  32768  = MYSQLI_NUM_FLAG
 936  16384  = MYSQLI_PART_KEY_FLAG
 937  32768  = MYSQLI_GROUP_FLAG
 938  65536  = MYSQLI_UNIQUE_FLAG
 939  131072 = MYSQLI_BINCMP_FLAG
 940  */
 941  
 942  	function FetchField($fieldOffset = -1)
 943  	 {
 944  	 	 $fieldnr = $fieldOffset;
 945  	 	 if ($fieldOffset != -1) {
 946  	 	 	 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr);
 947  	 	 }
 948  	 	 $o = @mysqli_fetch_field($this->_queryID);
 949  	 	 if (!$o) return false;
 950  
 951  	 	 //Fix for HHVM
 952  	 	 if ( !isset($o->flags) ) {
 953  	 	 	 $o->flags = 0;
 954  	 	 }
 955  	 	 /* Properties of an ADOFieldObject as set by MetaColumns */
 956  	 	 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
 957  	 	 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
 958  	 	 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
 959  	 	 $o->binary = $o->flags & MYSQLI_BINARY_FLAG;
 960  	 	 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
 961  	 	 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
 962  
 963  	 	 return $o;
 964  	 }
 965  
 966  	function GetRowAssoc($upper = ADODB_ASSOC_CASE)
 967  	 {
 968  	 	 if ($this->fetchMode == MYSQLI_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
 969  	 	 	 return $this->fields;
 970  	 	 }
 971  	 	 $row = ADORecordSet::GetRowAssoc($upper);
 972  	 	 return $row;
 973  	 }
 974  
 975  	 /* Use associative array to get fields array */
 976  	function Fields($colname)
 977  	 {
 978  	 	 if ($this->fetchMode != MYSQLI_NUM) {
 979  	 	 	 return @$this->fields[$colname];
 980  	 	 }
 981  
 982  	 	 if (!$this->bind) {
 983  	 	 	 $this->bind = array();
 984  	 	 	 for ($i = 0; $i < $this->_numOfFields; $i++) {
 985  	 	 	 	 $o = $this->FetchField($i);
 986  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 987  	 	 	 }
 988  	 	 }
 989  	 	 return $this->fields[$this->bind[strtoupper($colname)]];
 990  	 }
 991  
 992  	function _seek($row)
 993  	 {
 994  	 	 if ($this->_numOfRows == 0 || $row < 0) {
 995  	 	 	 return false;
 996  	 	 }
 997  
 998  	 	 mysqli_data_seek($this->_queryID, $row);
 999  	 	 $this->EOF = false;
1000  	 	 return true;
1001  	 }
1002  
1003  
1004  	function NextRecordSet()
1005  	 {
1006  	 global $ADODB_COUNTRECS;
1007  
1008  	 	 mysqli_free_result($this->_queryID);
1009  	 	 $this->_queryID = -1;
1010  	 	 // Move to the next recordset, or return false if there is none. In a stored proc
1011  	 	 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
1012  	 	 // returns false. I think this is because the last "recordset" is actually just the
1013  	 	 // return value of the stored proc (ie the number of rows affected).
1014  	 	 if(!mysqli_next_result($this->connection->_connectionID)) {
1015  	 	 return false;
1016  	 	 }
1017  	 	 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using
1018  	 	 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID )
1019  	 	 	 	 	 	 : @mysqli_use_result( $this->connection->_connectionID );
1020  	 	 if(!$this->_queryID) {
1021  	 	 	 return false;
1022  	 	 }
1023  	 	 $this->_inited = false;
1024  	 	 $this->bind = false;
1025  	 	 $this->_currentRow = -1;
1026  	 	 $this->Init();
1027  	 	 return true;
1028  	 }
1029  
1030  	 // 10% speedup to move MoveNext to child class
1031  	 // This is the only implementation that works now (23-10-2003).
1032  	 // Other functions return no or the wrong results.
1033  	function MoveNext()
1034  	 {
1035  	 	 if ($this->EOF) return false;
1036  	 	 $this->_currentRow++;
1037  	 	 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode);
1038  
1039  	 	 if (is_array($this->fields)) {
1040  	 	 	 $this->_updatefields();
1041  	 	 	 return true;
1042  	 	 }
1043  	 	 $this->EOF = true;
1044  	 	 return false;
1045  	 }
1046  
1047  	function _fetch()
1048  	 {
1049  	 	 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode);
1050  	 	 $this->_updatefields();
1051  	 	 return is_array($this->fields);
1052  	 }
1053  
1054  	function _close()
1055  	 {
1056  	 	 //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014
1057  	 	 //only a problem with persistant connections
1058  
1059  	 	 if(isset($this->connection->_connectionID) && $this->connection->_connectionID) {
1060  	 	 	 while(mysqli_more_results($this->connection->_connectionID)){
1061  	 	 	 	 mysqli_next_result($this->connection->_connectionID);
1062  	 	 	 }
1063  	 	 }
1064  
1065  	 	 if($this->_queryID instanceof mysqli_result) {
1066  	 	 	 mysqli_free_result($this->_queryID);
1067  	 	 }
1068  	 	 $this->_queryID = false;
1069  	 }
1070  
1071  /*
1072  
1073  0 = MYSQLI_TYPE_DECIMAL
1074  1 = MYSQLI_TYPE_CHAR
1075  1 = MYSQLI_TYPE_TINY
1076  2 = MYSQLI_TYPE_SHORT
1077  3 = MYSQLI_TYPE_LONG
1078  4 = MYSQLI_TYPE_FLOAT
1079  5 = MYSQLI_TYPE_DOUBLE
1080  6 = MYSQLI_TYPE_NULL
1081  7 = MYSQLI_TYPE_TIMESTAMP
1082  8 = MYSQLI_TYPE_LONGLONG
1083  9 = MYSQLI_TYPE_INT24
1084  10 = MYSQLI_TYPE_DATE
1085  11 = MYSQLI_TYPE_TIME
1086  12 = MYSQLI_TYPE_DATETIME
1087  13 = MYSQLI_TYPE_YEAR
1088  14 = MYSQLI_TYPE_NEWDATE
1089  247 = MYSQLI_TYPE_ENUM
1090  248 = MYSQLI_TYPE_SET
1091  249 = MYSQLI_TYPE_TINY_BLOB
1092  250 = MYSQLI_TYPE_MEDIUM_BLOB
1093  251 = MYSQLI_TYPE_LONG_BLOB
1094  252 = MYSQLI_TYPE_BLOB
1095  253 = MYSQLI_TYPE_VAR_STRING
1096  254 = MYSQLI_TYPE_STRING
1097  255 = MYSQLI_TYPE_GEOMETRY
1098  */
1099  
1100  	function MetaType($t, $len = -1, $fieldobj = false)
1101  	 {
1102  	 	 if (is_object($t)) {
1103  	 	 	 $fieldobj = $t;
1104  	 	 	 $t = $fieldobj->type;
1105  	 	 	 $len = $fieldobj->max_length;
1106  	 	 }
1107  
1108  
1109  	 	 $len = -1; // mysql max_length is not accurate
1110  	 	 switch (strtoupper($t)) {
1111  	 	 case 'STRING':
1112  	 	 case 'CHAR':
1113  	 	 case 'VARCHAR':
1114  	 	 case 'TINYBLOB':
1115  	 	 case 'TINYTEXT':
1116  	 	 case 'ENUM':
1117  	 	 case 'SET':
1118  
1119  	 	 case MYSQLI_TYPE_TINY_BLOB :
1120  	 	 #case MYSQLI_TYPE_CHAR :
1121  	 	 case MYSQLI_TYPE_STRING :
1122  	 	 case MYSQLI_TYPE_ENUM :
1123  	 	 case MYSQLI_TYPE_SET :
1124  	 	 case 253 :
1125  	 	 	 if ($len <= $this->blobSize) return 'C';
1126  
1127  	 	 case 'TEXT':
1128  	 	 case 'LONGTEXT':
1129  	 	 case 'MEDIUMTEXT':
1130  	 	 	 return 'X';
1131  
1132  	 	 // php_mysql extension always returns 'blob' even if 'text'
1133  	 	 // so we have to check whether binary...
1134  	 	 case 'IMAGE':
1135  	 	 case 'LONGBLOB':
1136  	 	 case 'BLOB':
1137  	 	 case 'MEDIUMBLOB':
1138  
1139  	 	 case MYSQLI_TYPE_BLOB :
1140  	 	 case MYSQLI_TYPE_LONG_BLOB :
1141  	 	 case MYSQLI_TYPE_MEDIUM_BLOB :
1142  	 	 	 return !empty($fieldobj->binary) ? 'B' : 'X';
1143  
1144  	 	 case 'YEAR':
1145  	 	 case 'DATE':
1146  	 	 case MYSQLI_TYPE_DATE :
1147  	 	 case MYSQLI_TYPE_YEAR :
1148  	 	 	 return 'D';
1149  
1150  	 	 case 'TIME':
1151  	 	 case 'DATETIME':
1152  	 	 case 'TIMESTAMP':
1153  
1154  	 	 case MYSQLI_TYPE_DATETIME :
1155  	 	 case MYSQLI_TYPE_NEWDATE :
1156  	 	 case MYSQLI_TYPE_TIME :
1157  	 	 case MYSQLI_TYPE_TIMESTAMP :
1158  	 	 	 return 'T';
1159  
1160  	 	 case 'INT':
1161  	 	 case 'INTEGER':
1162  	 	 case 'BIGINT':
1163  	 	 case 'TINYINT':
1164  	 	 case 'MEDIUMINT':
1165  	 	 case 'SMALLINT':
1166  
1167  	 	 case MYSQLI_TYPE_INT24 :
1168  	 	 case MYSQLI_TYPE_LONG :
1169  	 	 case MYSQLI_TYPE_LONGLONG :
1170  	 	 case MYSQLI_TYPE_SHORT :
1171  	 	 case MYSQLI_TYPE_TINY :
1172  	 	 	 if (!empty($fieldobj->primary_key)) return 'R';
1173  	 	 	 return 'I';
1174  
1175  	 	 // Added floating-point types
1176  	 	 // Maybe not necessery.
1177  	 	 case 'FLOAT':
1178  	 	 case 'DOUBLE':
1179  //	 	 case 'DOUBLE PRECISION':
1180  	 	 case 'DECIMAL':
1181  	 	 case 'DEC':
1182  	 	 case 'FIXED':
1183  	 	 default:
1184  	 	 	 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1185  	 	 	 return 'N';
1186  	 	 }
1187  	 } // function
1188  
1189  
1190  } // rs class
1191  
1192  }
1193  
1194  class ADORecordSet_array_mysqli extends ADORecordSet_array {
1195  
1196  	function __construct($id=-1,$mode=false)
1197  	 {
1198  	 	 parent::__construct($id,$mode);
1199  	 }
1200  
1201  	function MetaType($t, $len = -1, $fieldobj = false)
1202  	 {
1203  	 	 if (is_object($t)) {
1204  	 	 	 $fieldobj = $t;
1205  	 	 	 $t = $fieldobj->type;
1206  	 	 	 $len = $fieldobj->max_length;
1207  	 	 }
1208  
1209  
1210  	 	 $len = -1; // mysql max_length is not accurate
1211  	 	 switch (strtoupper($t)) {
1212  	 	 case 'STRING':
1213  	 	 case 'CHAR':
1214  	 	 case 'VARCHAR':
1215  	 	 case 'TINYBLOB':
1216  	 	 case 'TINYTEXT':
1217  	 	 case 'ENUM':
1218  	 	 case 'SET':
1219  
1220  	 	 case MYSQLI_TYPE_TINY_BLOB :
1221  	 	 #case MYSQLI_TYPE_CHAR :
1222  	 	 case MYSQLI_TYPE_STRING :
1223  	 	 case MYSQLI_TYPE_ENUM :
1224  	 	 case MYSQLI_TYPE_SET :
1225  	 	 case 253 :
1226  	 	 	 if ($len <= $this->blobSize) return 'C';
1227  
1228  	 	 case 'TEXT':
1229  	 	 case 'LONGTEXT':
1230  	 	 case 'MEDIUMTEXT':
1231  	 	 	 return 'X';
1232  
1233  	 	 // php_mysql extension always returns 'blob' even if 'text'
1234  	 	 // so we have to check whether binary...
1235  	 	 case 'IMAGE':
1236  	 	 case 'LONGBLOB':
1237  	 	 case 'BLOB':
1238  	 	 case 'MEDIUMBLOB':
1239  
1240  	 	 case MYSQLI_TYPE_BLOB :
1241  	 	 case MYSQLI_TYPE_LONG_BLOB :
1242  	 	 case MYSQLI_TYPE_MEDIUM_BLOB :
1243  
1244  	 	 	 return !empty($fieldobj->binary) ? 'B' : 'X';
1245  	 	 case 'YEAR':
1246  	 	 case 'DATE':
1247  	 	 case MYSQLI_TYPE_DATE :
1248  	 	 case MYSQLI_TYPE_YEAR :
1249  
1250  	 	 	 return 'D';
1251  
1252  	 	 case 'TIME':
1253  	 	 case 'DATETIME':
1254  	 	 case 'TIMESTAMP':
1255  
1256  	 	 case MYSQLI_TYPE_DATETIME :
1257  	 	 case MYSQLI_TYPE_NEWDATE :
1258  	 	 case MYSQLI_TYPE_TIME :
1259  	 	 case MYSQLI_TYPE_TIMESTAMP :
1260  
1261  	 	 	 return 'T';
1262  
1263  	 	 case 'INT':
1264  	 	 case 'INTEGER':
1265  	 	 case 'BIGINT':
1266  	 	 case 'TINYINT':
1267  	 	 case 'MEDIUMINT':
1268  	 	 case 'SMALLINT':
1269  
1270  	 	 case MYSQLI_TYPE_INT24 :
1271  	 	 case MYSQLI_TYPE_LONG :
1272  	 	 case MYSQLI_TYPE_LONGLONG :
1273  	 	 case MYSQLI_TYPE_SHORT :
1274  	 	 case MYSQLI_TYPE_TINY :
1275  
1276  	 	 	 if (!empty($fieldobj->primary_key)) return 'R';
1277  
1278  	 	 	 return 'I';
1279  
1280  
1281  	 	 // Added floating-point types
1282  	 	 // Maybe not necessery.
1283  	 	 case 'FLOAT':
1284  	 	 case 'DOUBLE':
1285  //	 	 case 'DOUBLE PRECISION':
1286  	 	 case 'DECIMAL':
1287  	 	 case 'DEC':
1288  	 	 case 'FIXED':
1289  	 	 default:
1290  	 	 	 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1291  	 	 	 return 'N';
1292  	 	 }
1293  	 } // function
1294  
1295  }