TYPO3 CMS  TYPO3_7-6
adodb-mysqli.inc.php
Go to the documentation of this file.
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 = '`';
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 
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 
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 }
MetaType($t, $len=-1, $fieldobj=false)
if(isset($_REQUEST['nrows'])) else $rs
Definition: server.php:94
debug($variable='', $name=' *variable *', $line=' *line *', $file=' *file *', $recursiveDepth=3, $debugLevel='E_DEBUG')
__construct($id=-1, $mode=false)
$sql
Definition: server.php:84