Source for file adodb-mysqli.inc.php
Documentation is available at adodb-mysqli.inc.php
V4.97 22 Jan 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
MySQL code that does not support transactions. Use mysqlt if you need transactions.
Requires mysql client. Works on Windows and Unix.
21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
if (! defined("_ADODB_MYSQLI_LAYER")) {
define("_ADODB_MYSQLI_LAYER", 1 );
if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128);
if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1);
// disable adodb extension - currently incompatible.
global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
var $hasGenID = false; // Fix for PostNuke Pablo Roca / larsneo / Neo
var $isoDates = true; // accepts dates in ISO format
var $nameQuote = '`'; /// string to use to quote identifiers and names
var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0));
// if(!extension_loaded("mysqli"))
;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
if (empty($transaction_mode)) {
$this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '. $transaction_mode;
$this->Execute("SET SESSION TRANSACTION ". $transaction_mode);
// To add: parameter int $port,
// parameter string $socket
$argDatabasename = NULL, $persist= false)
// mysqli_init only fails if insufficient memory
I suggest a simple fix which would enable adodb and mysqli driver to
read connection options from the standard mysql configuration file
/etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
#if (!empty($this->port)) $argHostname .= ":".$this->port;
if ($argDatabasename) return $this->SelectDB($argDatabasename);
// How to force a persistent connection
function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
// When is this used? Close old connection first?
// In _connect(), check $this->forceNewConnect?
function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
function IfNull( $field, $ifNull )
return " IFNULL($field, $ifNull) "; // if MySQL
// do not use $ADODB_COUNTRECS
function GetOne($sql,$inputarr= false)
$rs = &$this->Execute($sql,$inputarr);
if (!$rs->EOF) $ret = reset($rs->fields);
$arr['description'] = $this->GetOne("select version()");
//$this->Execute('SET AUTOCOMMIT=0');
//$this->Execute('SET AUTOCOMMIT=1');
//$this->Execute('SET AUTOCOMMIT=1');
function RowLock($tables,$where= '',$flds= '1 as adodb_ignore')
if ($where) $where = ' where '. $where;
$rs = & $this->Execute("select $flds from $tables $where for update");
// if magic quotes disabled, use mysql_real_escape_string()
// Quotes a string to be sent to the database. The $magic_quotes_enabled
// parameter may look funny, but the idea is if you are quoting a
// string extracted from a POST/GET variable, then
// pass get_magic_quotes_gpc() as the second parameter. This will
// ensure that the variable is not quoted twice, once by qstr and once
// by the magic_quotes_gpc.
//Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
function qstr($s, $magic_quotes = false)
return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
$s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
// undo magic quotes for "
// Only works for INSERT, UPDATE and DELETE query's
// See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
// Reference on Last_Insert_ID on the recommended way to simulate sequences
var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
return $this->Execute(sprintf($this->_genSeqzikula. orgame,$startID- 1));
function GenID($seqname= 'adodbseq',$startID= 1)
// post-nuke sets hasGenID to false
// if (!$this->hasGenID) return false;
$holdtransOK = $this->_transOK; // save the current status
if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
if (!$cnt) $this->Execute(sprintf($this->_genSeqzikula. orgame,$startID- 1));
$query = "SHOW DATABASES";
$db = $ret->Fields('Database');
if ($db != 'mysql') $arr[] = $db;
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = $save;
// parse index data into array
while ($row = $rs->FetchRow()) {
if ($primary == FALSE AND $row[2] == 'PRIMARY') {
if (!isset ($indexes[$row[2]])) {
$indexes[$row[2]] = array(
'unique' => ($row[1] == 0),
$indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
// sort columns by order in the index
ksort ($indexes[$index]['columns']);
// Format date column in sql string given an input format that understands Y M D
$s = 'DATE_FORMAT('. $col. ",'";
for ($i= 0; $i < $len; $i++ ) {
$s .= "'),Quarter($col)";
if ($len > $i+ 1) $s .= ",DATE_FORMAT($col,'";
if ($concat) $s = "CONCAT($s)";
// returns concatenated string
// much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
// suggestion by andrew005@mnogo.ru
if (strlen($s) > 0) return "CONCAT($s)";
// dayFraction is a day in floating point
if (!$date) $date = $this->sysDate;
$fraction = $dayFraction * 24 * 3600;
return $date . ' + INTERVAL ' . $fraction. ' SECOND';
// return "from_unixtime(unix_timestamp($date)+$fraction)";
function &MetaTables($ttype= false,$showSchema= false,$mask= false)
$mask = $this->qstr($mask);
// "Innox - Juan Carlos Gonzalez" <jgonzikula.orgnox.com.mx>
function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
global $ADODB_FETCH_MODE;
$table = "$owner.$table";
$a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
if ($associative) $create_sql = $a_create_table["Create Table"];
else $create_sql = $a_create_table[1];
if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
$num_keys = count($matches[0]);
for ( $i = 0; $i < $num_keys; $i ++ ) {
$my_field = explode('`, `', $matches[1][$i]);
$ref_table = $matches[2][$i];
$ref_field = explode('`, `', $matches[3][$i]);
$foreign_keys[$ref_table] = array();
$num_fields = count($my_field);
for ( $j = 0; $j < $num_fields; $j ++ ) {
$foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
$foreign_keys[$ref_table][] = "{ $my_field[$j]}={ $ref_field[$j]}";
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = $save;
$fld->name = $rs->fields[0];
// split type into type(length):
if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
$fld->type = $query_array[1];
$fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : - 1;
$fld->scale = is_numeric($query_array[3]) ? $query_array[3] : - 1;
} elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
$fld->type = $query_array[1];
$fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : - 1;
} elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
$fld->type = $query_array[1];
$fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length);
$fld->not_null = ($rs->fields[2] != 'YES');
$fld->primary_key = ($rs->fields[3] == 'PRI');
$fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
if ($d != '' && $d != 'NULL') {
$fld->has_default = true;
$fld->default_value = $d;
$fld->has_default = false;
// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
$this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
// parameters use PostgreSQL convention, not MySQL
$offsetStr = ($offset >= 0) ? "$offset," : '';
if ($nrows < 0) $nrows = '18446744073709551615';
$rs = & $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr);
$rs = & $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr);
return array($sql,$stmt);
// returns queryID or false
function _query($sql, $inputarr)
foreach($inputarr as $k => $v) {
$ret = mysqli_stmt_execute($stmt);
if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
/* Returns: the last error message from previous database operation */
/* Returns: the last error number from previous database operation */
return @mysqli_connect_errno();
* Maximum size of C field
* Maximum size of X field
// this is a set of functions for managing client encoding - very important if the encodings
// of your database and your output target (i.e. HTML) don't match
// for instance, you may have UTF8 database and server it on-site as latin1 etc.
// GetCharSet - get the name of the character set the client is using now
// Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
// depends on compile flags of mysql distribution
//we will use ADO's builtin property charSet
// SetCharSet - switch the client encoding
if ($this->charSet !== $charset_name) {
if ($if == "0" & $this->GetCharSet() == $charset_name) {
/*--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------*/
global $ADODB_FETCH_MODE;
$mode = $ADODB_FETCH_MODE;
$this->adodbFetchMode = $mode;
4 = MYSQLI_UNIQUE_KEY_FLAG
8 = MYSQLI_MULTIPLE_KEY_FLAG
32 = MYSQLI_UNSIGNED_FLAG
64 = MYSQLI_ZEROFILL_FLAG
512 = MYSQLI_AUTO_INCREMENT_FLAG
1024 = MYSQLI_TIMESTAMP_FLAG
16384 = MYSQLI_PART_KEY_FLAG
32768 = MYSQLI_GROUP_FLAG
65536 = MYSQLI_UNIQUE_FLAG
131072 = MYSQLI_BINCMP_FLAG
if ($fieldOffset != - 1) {
$fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr);
$o = mysqli_fetch_field($this->_queryID);
/* Properties of an ADOFieldObject as set by MetaColumns */
$o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
$o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
$o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
// $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
$o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
if ($this->fetchMode == MYSQLI_ASSOC && !$upper)
/* Use associative array to get fields array */
return @$this->fields[$colname];
mysqli_data_seek($this->_queryID, $row);
// 10% speedup to move MoveNext to child class
// This is the only implementation that works now (23-10-2003).
// Other functions return no or the wrong results.
if ($this->EOF) return false;
7 = MYSQLI_TYPE_TIMESTAMP
12 = MYSQLI_TYPE_DATETIME
249 = MYSQLI_TYPE_TINY_BLOB
250 = MYSQLI_TYPE_MEDIUM_BLOB
251 = MYSQLI_TYPE_LONG_BLOB
253 = MYSQLI_TYPE_VAR_STRING
255 = MYSQLI_TYPE_GEOMETRY
function MetaType($t, $len = - 1, $fieldobj = false)
$len = $fieldobj->max_length;
$len = - 1; // mysql max_length is not accurate
case MYSQLI_TYPE_TINY_BLOB :
case MYSQLI_TYPE_STRING :
if ($len <= $this->blobSize) return 'C';
// php_mysql extension always returns 'blob' even if 'text'
// so we have to check whether binary...
case MYSQLI_TYPE_LONG_BLOB :
case MYSQLI_TYPE_MEDIUM_BLOB :
return !empty($fieldobj->binary) ? 'B' : 'X';
case MYSQLI_TYPE_DATETIME :
case MYSQLI_TYPE_NEWDATE :
case MYSQLI_TYPE_TIMESTAMP :
case MYSQLI_TYPE_LONGLONG :
if (!empty($fieldobj->primary_key)) return 'R';
// Added floating-point types
// case 'DOUBLE PRECISION':
//if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
function MetaType($t, $len = - 1, $fieldobj = false)
$len = $fieldobj->max_length;
$len = - 1; // mysql max_length is not accurate
case MYSQLI_TYPE_TINY_BLOB :
case MYSQLI_TYPE_STRING :
if ($len <= $this->blobSize) return 'C';
// php_mysql extension always returns 'blob' even if 'text'
// so we have to check whether binary...
case MYSQLI_TYPE_LONG_BLOB :
case MYSQLI_TYPE_MEDIUM_BLOB :
return !empty($fieldobj->binary) ? 'B' : 'X';
case MYSQLI_TYPE_DATETIME :
case MYSQLI_TYPE_NEWDATE :
case MYSQLI_TYPE_TIMESTAMP :
case MYSQLI_TYPE_LONGLONG :
if (!empty($fieldobj->primary_key)) return 'R';
// Added floating-point types
// case 'DOUBLE PRECISION':
//if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
|