[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/adodb/drivers/ -> adodb-mysqli.inc.php (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1