C:/lib/adodb/drivers/adodb-mysqli.inc.php Quellcode

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




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.