3 @version v5.20.19 13-Dec-2020
4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
6 Released under both BSD license and Lesser GPL library license.
7 Whenever there is any discrepancy between the two licenses,
8 the BSD license will take precedence.
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
16 Requires mysql client. Works on Windows and Unix.
18 21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
22 // security - hide paths
23 if (!defined('ADODB_DIR')) die();
25 if (! defined("_ADODB_MYSQLI_LAYER")) {
26 define("_ADODB_MYSQLI_LAYER", 1 );
29 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128);
30 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1);
32 // disable adodb extension - currently incompatible.
33 global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
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
42 CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END
43 FROM INFORMATION_SCHEMA.TABLES
45 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
46 var $fmtTimeStamp = "'Y-m-d H:i:s'";
48 var $hasMoveFirst = 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;
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;
66 function __construct()
68 // if(!extension_loaded("mysqli"))
69 //trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
72 function SetTransactionMode( $transaction_mode )
74 $this->_transmode = $transaction_mode;
75 if (empty($transaction_mode)) {
76 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
79 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
80 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
83 // returns true or false
84 // To add: parameter int $port,
85 // parameter string $socket
86 function _connect($argHostname = NULL,
89 $argDatabasename = NULL, $persist=false)
91 if(!extension_loaded("mysqli")) {
94 $this->_connectionID = @mysqli_init();
96 if (is_null($this->_connectionID)) {
97 // mysqli_init only fails if insufficient memory
99 ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg());
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>
108 foreach($this->optionFlags as $arr) {
109 mysqli_options($this->_connectionID,$arr[0],$arr[1]);
112 //http ://php.net/manual/en/mysqli.persistconns.php
113 if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname,'p:',2) != 0) $argHostname = 'p:'.$argHostname;
115 #if (!empty($this->port)) $argHostname .= ":".$this->port;
116 $ok = @mysqli_real_connect($this->_connectionID,
121 # PHP7 compat: port must be int. Use default port if cast yields zero
122 (int)$this->port != 0 ? (int)$this->port : 3306,
127 if ($argDatabasename) return $this->SelectDB($argDatabasename);
131 ADOConnection::outp("Could not connect : " . $this->ErrorMsg());
133 $this->_connectionID = null;
138 // returns true or false
139 // How to force a persistent connection
140 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
142 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
145 // When is this used? Close old connection first?
146 // In _connect(), check $this->forceNewConnect?
147 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
149 $this->forceNewConnect = true;
150 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
153 function IfNull( $field, $ifNull )
155 return " IFNULL($field, $ifNull) "; // if MySQL
158 // do not use $ADODB_COUNTRECS
159 function GetOne($sql,$inputarr=false)
161 global $ADODB_GETONE_EOF;
164 $rs = $this->Execute($sql,$inputarr);
166 if ($rs->EOF) $ret = $ADODB_GETONE_EOF;
167 else $ret = reset($rs->fields);
173 function ServerInfo()
175 $arr['description'] = $this->GetOne("select version()");
176 $arr['version'] = ADOConnection::_findvers($arr['description']);
181 function BeginTrans()
183 if ($this->transOff) return true;
184 $this->transCnt += 1;
186 //$this->Execute('SET AUTOCOMMIT=0');
187 mysqli_autocommit($this->_connectionID, false);
188 $this->Execute('BEGIN');
192 function CommitTrans($ok=true)
194 if ($this->transOff) return true;
195 if (!$ok) return $this->RollbackTrans();
197 if ($this->transCnt) $this->transCnt -= 1;
198 $this->Execute('COMMIT');
200 //$this->Execute('SET AUTOCOMMIT=1');
201 mysqli_autocommit($this->_connectionID, true);
205 function RollbackTrans()
207 if ($this->transOff) return true;
208 if ($this->transCnt) $this->transCnt -= 1;
209 $this->Execute('ROLLBACK');
210 //$this->Execute('SET AUTOCOMMIT=1');
211 mysqli_autocommit($this->_connectionID, true);
215 function RowLock($tables,$where='',$col='1 as adodbignore')
217 if ($this->transCnt==0) $this->BeginTrans();
218 if ($where) $where = ' where '.$where;
219 $rs = $this->Execute("select $col from $tables $where for update");
224 * Quotes a string to be sent to the database
225 * When there is no active connection,
226 * @param string $s The string to quote
227 * @param boolean $magic_quotes If false, use mysqli_real_escape_string()
228 * if you are quoting a string extracted from a POST/GET variable,
229 * then pass get_magic_quotes_gpc() as the second parameter. This will
230 * ensure that the variable is not quoted twice, once by qstr() and
231 * once by the magic_quotes_gpc.
232 * Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
233 * @return string Quoted string
235 function qstr($s, $magic_quotes = false)
237 if (is_null($s)) return 'NULL';
238 if (!$magic_quotes) {
239 // mysqli_real_escape_string() throws a warning when the given
240 // connection is invalid
241 if (PHP_VERSION >= 5 && $this->_connectionID) {
242 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
245 if ($this->replaceQuote[0] == '\\') {
246 $s = adodb_str_replace(array('\\',"\0"), array('\\\\',"\\\0") ,$s);
248 return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
250 // undo magic quotes for "
251 $s = str_replace('\\"','"',$s);
257 $result = @mysqli_insert_id($this->_connectionID);
259 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg());
264 // Only works for INSERT, UPDATE and DELETE query's
265 function _affectedrows()
267 $result = @mysqli_affected_rows($this->_connectionID);
269 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg());
274 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
275 // Reference on Last_Insert_ID on the recommended way to simulate sequences
276 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
277 var $_genSeqSQL = "create table if not exists %s (id int not null)";
278 var $_genSeqCountSQL = "select count(*) from %s";
279 var $_genSeq2SQL = "insert into %s values (%s)";
280 var $_dropSeqSQL = "drop table if exists %s";
282 function CreateSequence($seqname='adodbseq',$startID=1)
284 if (empty($this->_genSeqSQL)) return false;
285 $u = strtoupper($seqname);
287 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
288 if (!$ok) return false;
289 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
292 function GenID($seqname='adodbseq',$startID=1)
294 // post-nuke sets hasGenID to false
295 if (!$this->hasGenID) return false;
297 $getnext = sprintf($this->_genIDSQL,$seqname);
298 $holdtransOK = $this->_transOK; // save the current status
299 $rs = @$this->Execute($getnext);
301 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
302 $u = strtoupper($seqname);
303 $this->Execute(sprintf($this->_genSeqSQL,$seqname));
304 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
305 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
306 $rs = $this->Execute($getnext);
310 $this->genID = mysqli_insert_id($this->_connectionID);
318 function MetaDatabases()
320 $query = "SHOW DATABASES";
321 $ret = $this->Execute($query);
322 if ($ret && is_object($ret)){
325 $db = $ret->Fields('Database');
326 if ($db != 'mysql') $arr[] = $db;
335 function MetaIndexes ($table, $primary = FALSE, $owner = false)
337 // save old fetch mode
338 global $ADODB_FETCH_MODE;
341 $save = $ADODB_FETCH_MODE;
342 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
343 if ($this->fetchMode !== FALSE) {
344 $savem = $this->SetFetchMode(FALSE);
348 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table));
352 $this->SetFetchMode($savem);
354 $ADODB_FETCH_MODE = $save;
356 if (!is_object($rs)) {
362 // parse index data into array
363 while ($row = $rs->FetchRow()) {
364 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
368 if (!isset($indexes[$row[2]])) {
369 $indexes[$row[2]] = array(
370 'unique' => ($row[1] == 0),
375 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
378 // sort columns by order in the index
379 foreach ( array_keys ($indexes) as $index )
381 ksort ($indexes[$index]['columns']);
388 // Format date column in sql string given an input format that understands Y M D
389 function SQLDate($fmt, $col=false)
391 if (!$col) $col = $this->sysTimeStamp;
392 $s = 'DATE_FORMAT('.$col.",'";
395 for ($i=0; $i < $len; $i++) {
404 $s .= "'),Quarter($col)";
406 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
455 $ch = substr($fmt,$i,1);
462 if ($concat) $s = "CONCAT($s)";
466 // returns concatenated string
467 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
471 $arr = func_get_args();
473 // suggestion by andrew005@mnogo.ru
474 $s = implode(',',$arr);
475 if (strlen($s) > 0) return "CONCAT($s)";
479 // dayFraction is a day in floating point
480 function OffsetDate($dayFraction,$date=false)
482 if (!$date) $date = $this->sysDate;
484 $fraction = $dayFraction * 24 * 3600;
485 return $date . ' + INTERVAL ' . $fraction.' SECOND';
487 // return "from_unixtime(unix_timestamp($date)+$fraction)";
490 function MetaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null)
492 // save old fetch mode
493 global $ADODB_FETCH_MODE;
496 $save = $ADODB_FETCH_MODE;
497 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
499 if ($this->fetchMode !== FALSE) {
500 $savem = $this->SetFetchMode(FALSE);
503 $procedures = array ();
509 $likepattern = " LIKE '".$NamePattern."'";
511 $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern);
512 if (is_object($rs)) {
514 // parse index data into array
515 while ($row = $rs->FetchRow()) {
516 $procedures[$row[1]] = array(
517 'type' => 'PROCEDURE',
520 'remarks' => $row[7],
525 $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern);
526 if (is_object($rs)) {
527 // parse index data into array
528 while ($row = $rs->FetchRow()) {
529 $procedures[$row[1]] = array(
530 'type' => 'FUNCTION',
540 $this->SetFetchMode($savem);
542 $ADODB_FETCH_MODE = $save;
548 * Retrieves a list of tables based on given criteria
550 * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default)
551 * @param string $showSchema schema name, false = current schema (default)
552 * @param string $mask filters the table by name
554 * @return array list of tables
556 function MetaTables($ttype=false,$showSchema=false,$mask=false)
558 $save = $this->metaTablesSQL;
559 if ($showSchema && is_string($showSchema)) {
560 $this->metaTablesSQL .= $this->qstr($showSchema);
562 $this->metaTablesSQL .= "schema()";
566 $mask = $this->qstr($mask);
567 $this->metaTablesSQL .= " AND table_name LIKE $mask";
569 $ret = ADOConnection::MetaTables($ttype,$showSchema);
571 $this->metaTablesSQL = $save;
575 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
576 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
578 global $ADODB_FETCH_MODE;
580 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
582 if ( !empty($owner) ) {
583 $table = "$owner.$table";
585 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
587 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
588 } else $create_sql = $a_create_table[1];
592 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
593 $foreign_keys = array();
594 $num_keys = count($matches[0]);
595 for ( $i = 0; $i < $num_keys; $i ++ ) {
596 $my_field = explode('`, `', $matches[1][$i]);
597 $ref_table = $matches[2][$i];
598 $ref_field = explode('`, `', $matches[3][$i]);
601 $ref_table = strtoupper($ref_table);
604 // see https://sourceforge.net/p/adodb/bugs/100/
605 if (!isset($foreign_keys[$ref_table])) {
606 $foreign_keys[$ref_table] = array();
608 $num_fields = count($my_field);
609 for ( $j = 0; $j < $num_fields; $j ++ ) {
610 if ( $associative ) {
611 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
613 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
618 return $foreign_keys;
621 function MetaColumns($table, $normalize=true)
624 if (!$this->metaColumnsSQL)
627 global $ADODB_FETCH_MODE;
628 $save = $ADODB_FETCH_MODE;
629 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
630 if ($this->fetchMode !== false)
631 $savem = $this->SetFetchMode(false);
633 * Return assoc array where key is column name, value is column type
634 * [1] => int unsigned
637 $SQL = "SELECT column_name, column_type
638 FROM information_schema.columns
639 WHERE table_schema='{$this->databaseName}'
640 AND table_name='$table'";
642 $schemaArray = $this->getAssoc($SQL);
643 $schemaArray = array_change_key_case($schemaArray,CASE_LOWER);
645 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
646 if (isset($savem)) $this->SetFetchMode($savem);
647 $ADODB_FETCH_MODE = $save;
653 $fld = new ADOFieldObject();
654 $fld->name = $rs->fields[0];
655 $type = $rs->fields[1];
658 * Type from information_schema returns
659 * the same format in V8 mysql as V5
661 $type = $schemaArray[strtolower($fld->name)];
663 // split type into type(length):
665 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
666 $fld->type = $query_array[1];
667 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
668 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
669 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
670 $fld->type = $query_array[1];
671 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
672 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
673 $fld->type = $query_array[1];
674 $arr = explode(",",$query_array[2]);
676 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
677 $fld->max_length = ($zlen > 0) ? $zlen : 1;
680 $fld->max_length = -1;
683 $fld->not_null = ($rs->fields[2] != 'YES');
684 $fld->primary_key = ($rs->fields[3] == 'PRI');
685 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
686 $fld->binary = (strpos($type,'blob') !== false);
687 $fld->unsigned = (strpos($type,'unsigned') !== false);
688 $fld->zerofill = (strpos($type,'zerofill') !== false);
692 if ($d != '' && $d != 'NULL') {
693 $fld->has_default = true;
694 $fld->default_value = $d;
696 $fld->has_default = false;
700 if ($save == ADODB_FETCH_NUM) {
703 $retarr[strtoupper($fld->name)] = $fld;
712 // returns true or false
713 function SelectDB($dbName)
715 // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
716 $this->database = $dbName;
717 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
719 if ($this->_connectionID) {
720 $result = @mysqli_select_db($this->_connectionID, $dbName);
722 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
729 // parameters use PostgreSQL convention, not MySQL
730 function SelectLimit($sql,
736 $nrows = (int) $nrows;
737 $offset = (int) $offset;
738 $offsetStr = ($offset >= 0) ? "$offset," : '';
739 if ($nrows < 0) $nrows = '18446744073709551615';
742 $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr );
744 $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr );
750 function Prepare($sql)
753 $stmt = $this->_connectionID->prepare($sql);
755 echo $this->ErrorMsg();
758 return array($sql,$stmt);
762 // returns queryID or false
763 function _query($sql, $inputarr)
765 global $ADODB_COUNTRECS;
766 // Move to the next recordset, or return false if there is none. In a stored proc
767 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
768 // returns false. I think this is because the last "recordset" is actually just the
769 // return value of the stored proc (ie the number of rows affected).
770 // Commented out for reasons of performance. You should retrieve every recordset yourself.
771 // if (!mysqli_next_result($this->connection->_connectionID)) return false;
773 if (is_array($sql)) {
775 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but
776 // returns as bound variables.
780 foreach($inputarr as $k => $v) {
781 if (is_string($v)) $a .= 's';
782 else if (is_integer($v)) $a .= 'i';
786 $fnarr = array_merge( array($stmt,$a) , $inputarr);
787 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr);
788 $ret = mysqli_stmt_execute($stmt);
793 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
794 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
801 if ($this->multiQuery) {
802 $rs = mysqli_multi_query($this->_connectionID, $sql.';');
804 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID );
805 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID )
808 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
814 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
820 /* Returns: the last error message from previous database operation */
823 if (empty($this->_connectionID))
824 $this->_errorMsg = @mysqli_connect_error();
826 $this->_errorMsg = @mysqli_error($this->_connectionID);
827 return $this->_errorMsg;
830 /* Returns: the last error number from previous database operation */
833 if (empty($this->_connectionID))
834 return @mysqli_connect_errno();
836 return @mysqli_errno($this->_connectionID);
839 // returns true or false
842 @mysqli_close($this->_connectionID);
843 $this->_connectionID = false;
847 * Maximum size of C field
855 * Maximum size of X field
863 // this is a set of functions for managing client encoding - very important if the encodings
864 // of your database and your output target (i.e. HTML) don't match
865 // for instance, you may have UTF8 database and server it on-site as latin1 etc.
866 // GetCharSet - get the name of the character set the client is using now
867 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
868 // depends on compile flags of mysql distribution
870 function GetCharSet()
872 //we will use ADO's builtin property charSet
873 if (!method_exists($this->_connectionID,'character_set_name'))
876 $this->charSet = @$this->_connectionID->character_set_name();
877 if (!$this->charSet) {
880 return $this->charSet;
884 // SetCharSet - switch the client encoding
885 function SetCharSet($charset_name)
887 if (!method_exists($this->_connectionID,'set_charset')) {
891 if ($this->charSet !== $charset_name) {
892 $if = @$this->_connectionID->set_charset($charset_name);
893 return ($if === true & $this->GetCharSet() == $charset_name);
901 /*--------------------------------------------------------------------------------------
902 Class Name: Recordset
903 --------------------------------------------------------------------------------------*/
905 class ADORecordSet_mysqli extends ADORecordSet{
907 var $databaseType = "mysqli";
910 function __construct($queryID, $mode = false)
912 if ($mode === false) {
913 global $ADODB_FETCH_MODE;
914 $mode = $ADODB_FETCH_MODE;
918 case ADODB_FETCH_NUM:
919 $this->fetchMode = MYSQLI_NUM;
921 case ADODB_FETCH_ASSOC:
922 $this->fetchMode = MYSQLI_ASSOC;
924 case ADODB_FETCH_DEFAULT:
925 case ADODB_FETCH_BOTH:
927 $this->fetchMode = MYSQLI_BOTH;
930 $this->adodbFetchMode = $mode;
931 parent::__construct($queryID);
936 global $ADODB_COUNTRECS;
938 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
939 $this->_numOfFields = @mysqli_num_fields($this->_queryID);
943 1 = MYSQLI_NOT_NULL_FLAG
944 2 = MYSQLI_PRI_KEY_FLAG
945 4 = MYSQLI_UNIQUE_KEY_FLAG
946 8 = MYSQLI_MULTIPLE_KEY_FLAG
947 16 = MYSQLI_BLOB_FLAG
948 32 = MYSQLI_UNSIGNED_FLAG
949 64 = MYSQLI_ZEROFILL_FLAG
950 128 = MYSQLI_BINARY_FLAG
951 256 = MYSQLI_ENUM_FLAG
952 512 = MYSQLI_AUTO_INCREMENT_FLAG
953 1024 = MYSQLI_TIMESTAMP_FLAG
954 2048 = MYSQLI_SET_FLAG
955 32768 = MYSQLI_NUM_FLAG
956 16384 = MYSQLI_PART_KEY_FLAG
957 32768 = MYSQLI_GROUP_FLAG
958 65536 = MYSQLI_UNIQUE_FLAG
959 131072 = MYSQLI_BINCMP_FLAG
962 function FetchField($fieldOffset = -1)
964 $fieldnr = $fieldOffset;
965 if ($fieldOffset != -1) {
966 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr);
968 $o = @mysqli_fetch_field($this->_queryID);
969 if (!$o) return false;
972 if ( !isset($o->flags) ) {
975 /* Properties of an ADOFieldObject as set by MetaColumns */
976 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
977 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
978 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
979 $o->binary = $o->flags & MYSQLI_BINARY_FLAG;
980 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
981 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
986 function GetRowAssoc($upper = ADODB_ASSOC_CASE)
988 if ($this->fetchMode == MYSQLI_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
989 return $this->fields;
991 $row = ADORecordSet::GetRowAssoc($upper);
995 /* Use associative array to get fields array */
996 function Fields($colname)
998 if ($this->fetchMode != MYSQLI_NUM) {
999 return @$this->fields[$colname];
1003 $this->bind = array();
1004 for ($i = 0; $i < $this->_numOfFields; $i++) {
1005 $o = $this->FetchField($i);
1006 $this->bind[strtoupper($o->name)] = $i;
1009 return $this->fields[$this->bind[strtoupper($colname)]];
1012 function _seek($row)
1014 if ($this->_numOfRows == 0 || $row < 0) {
1018 mysqli_data_seek($this->_queryID, $row);
1024 function NextRecordSet()
1026 global $ADODB_COUNTRECS;
1028 mysqli_free_result($this->_queryID);
1029 $this->_queryID = -1;
1030 // Move to the next recordset, or return false if there is none. In a stored proc
1031 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
1032 // returns false. I think this is because the last "recordset" is actually just the
1033 // return value of the stored proc (ie the number of rows affected).
1034 if(!mysqli_next_result($this->connection->_connectionID)) {
1037 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using
1038 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID )
1039 : @mysqli_use_result( $this->connection->_connectionID );
1040 if(!$this->_queryID) {
1043 $this->_inited = false;
1044 $this->bind = false;
1045 $this->_currentRow = -1;
1050 // 10% speedup to move MoveNext to child class
1051 // This is the only implementation that works now (23-10-2003).
1052 // Other functions return no or the wrong results.
1055 if ($this->EOF) return false;
1056 $this->_currentRow++;
1057 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode);
1059 if (is_array($this->fields)) {
1060 $this->_updatefields();
1069 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode);
1070 $this->_updatefields();
1071 return is_array($this->fields);
1076 //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014
1077 //only a problem with persistant connections
1079 if(isset($this->connection->_connectionID) && $this->connection->_connectionID) {
1080 while(mysqli_more_results($this->connection->_connectionID)){
1081 mysqli_next_result($this->connection->_connectionID);
1085 if($this->_queryID instanceof mysqli_result) {
1086 mysqli_free_result($this->_queryID);
1088 $this->_queryID = false;
1093 0 = MYSQLI_TYPE_DECIMAL
1094 1 = MYSQLI_TYPE_CHAR
1095 1 = MYSQLI_TYPE_TINY
1096 2 = MYSQLI_TYPE_SHORT
1097 3 = MYSQLI_TYPE_LONG
1098 4 = MYSQLI_TYPE_FLOAT
1099 5 = MYSQLI_TYPE_DOUBLE
1100 6 = MYSQLI_TYPE_NULL
1101 7 = MYSQLI_TYPE_TIMESTAMP
1102 8 = MYSQLI_TYPE_LONGLONG
1103 9 = MYSQLI_TYPE_INT24
1104 10 = MYSQLI_TYPE_DATE
1105 11 = MYSQLI_TYPE_TIME
1106 12 = MYSQLI_TYPE_DATETIME
1107 13 = MYSQLI_TYPE_YEAR
1108 14 = MYSQLI_TYPE_NEWDATE
1109 247 = MYSQLI_TYPE_ENUM
1110 248 = MYSQLI_TYPE_SET
1111 249 = MYSQLI_TYPE_TINY_BLOB
1112 250 = MYSQLI_TYPE_MEDIUM_BLOB
1113 251 = MYSQLI_TYPE_LONG_BLOB
1114 252 = MYSQLI_TYPE_BLOB
1115 253 = MYSQLI_TYPE_VAR_STRING
1116 254 = MYSQLI_TYPE_STRING
1117 255 = MYSQLI_TYPE_GEOMETRY
1120 function MetaType($t, $len = -1, $fieldobj = false)
1122 if (is_object($t)) {
1124 $t = $fieldobj->type;
1125 $len = $fieldobj->max_length;
1129 $len = -1; // mysql max_length is not accurate
1130 switch (strtoupper($t)) {
1139 case MYSQLI_TYPE_TINY_BLOB :
1140 #case MYSQLI_TYPE_CHAR :
1141 case MYSQLI_TYPE_STRING :
1142 case MYSQLI_TYPE_ENUM :
1143 case MYSQLI_TYPE_SET :
1145 if ($len <= $this->blobSize) return 'C';
1152 // php_mysql extension always returns 'blob' even if 'text'
1153 // so we have to check whether binary...
1159 case MYSQLI_TYPE_BLOB :
1160 case MYSQLI_TYPE_LONG_BLOB :
1161 case MYSQLI_TYPE_MEDIUM_BLOB :
1162 return !empty($fieldobj->binary) ? 'B' : 'X';
1166 case MYSQLI_TYPE_DATE :
1167 case MYSQLI_TYPE_YEAR :
1174 case MYSQLI_TYPE_DATETIME :
1175 case MYSQLI_TYPE_NEWDATE :
1176 case MYSQLI_TYPE_TIME :
1177 case MYSQLI_TYPE_TIMESTAMP :
1187 case MYSQLI_TYPE_INT24 :
1188 case MYSQLI_TYPE_LONG :
1189 case MYSQLI_TYPE_LONGLONG :
1190 case MYSQLI_TYPE_SHORT :
1191 case MYSQLI_TYPE_TINY :
1192 if (!empty($fieldobj->primary_key)) return 'R';
1195 // Added floating-point types
1196 // Maybe not necessery.
1199 // case 'DOUBLE PRECISION':
1204 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1214 class ADORecordSet_array_mysqli extends ADORecordSet_array {
1216 function __construct($id=-1,$mode=false)
1218 parent::__construct($id,$mode);
1221 function MetaType($t, $len = -1, $fieldobj = false)
1223 if (is_object($t)) {
1225 $t = $fieldobj->type;
1226 $len = $fieldobj->max_length;
1230 $len = -1; // mysql max_length is not accurate
1231 switch (strtoupper($t)) {
1240 case MYSQLI_TYPE_TINY_BLOB :
1241 #case MYSQLI_TYPE_CHAR :
1242 case MYSQLI_TYPE_STRING :
1243 case MYSQLI_TYPE_ENUM :
1244 case MYSQLI_TYPE_SET :
1246 if ($len <= $this->blobSize) return 'C';
1253 // php_mysql extension always returns 'blob' even if 'text'
1254 // so we have to check whether binary...
1260 case MYSQLI_TYPE_BLOB :
1261 case MYSQLI_TYPE_LONG_BLOB :
1262 case MYSQLI_TYPE_MEDIUM_BLOB :
1264 return !empty($fieldobj->binary) ? 'B' : 'X';
1267 case MYSQLI_TYPE_DATE :
1268 case MYSQLI_TYPE_YEAR :
1276 case MYSQLI_TYPE_DATETIME :
1277 case MYSQLI_TYPE_NEWDATE :
1278 case MYSQLI_TYPE_TIME :
1279 case MYSQLI_TYPE_TIMESTAMP :
1290 case MYSQLI_TYPE_INT24 :
1291 case MYSQLI_TYPE_LONG :
1292 case MYSQLI_TYPE_LONGLONG :
1293 case MYSQLI_TYPE_SHORT :
1294 case MYSQLI_TYPE_TINY :
1296 if (!empty($fieldobj->primary_key)) return 'R';
1301 // Added floating-point types
1302 // Maybe not necessery.
1305 // case 'DOUBLE PRECISION':
1310 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";