Separate Display and Search of Organization, and person names
[openemr.git] / library / adodb / drivers / adodb-mysqli.inc.php
blob4ba3f10ab084a98a41af06ac298516c190c53f7c
1 <?php
2 /*
3 V5.14 8 Sept 2011 (c) 2000-2011 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.
9 MySQL code that does not support transactions. Use mysqlt if you need transactions.
10 Requires mysql client. Works on Windows and Unix.
12 21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
13 Based on adodb 3.40
14 */
16 // security - hide paths
17 if (!defined('ADODB_DIR')) die();
19 if (! defined("_ADODB_MYSQLI_LAYER")) {
20 define("_ADODB_MYSQLI_LAYER", 1 );
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);
26 // disable adodb extension - currently incompatible.
27 global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
29 class ADODB_mysqli extends ADOConnection {
30 var $databaseType = 'mysqli';
31 var $dataProvider = 'native';
32 var $hasInsertID = true;
33 var $hasAffectedRows = true;
34 var $metaTablesSQL = "SHOW TABLES";
35 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
36 var $fmtTimeStamp = "'Y-m-d H:i:s'";
37 var $hasLimit = true;
38 var $hasMoveFirst = true;
39 var $hasGenID = true;
40 var $isoDates = true; // accepts dates in ISO format
41 var $sysDate = 'CURDATE()';
42 var $sysTimeStamp = 'NOW()';
43 var $hasTransactions = true;
44 var $forceNewConnect = false;
45 var $poorAffectedRows = true;
46 var $clientFlags = 0;
47 var $substr = "substring";
48 var $port = false;
49 var $socket = false;
50 var $_bindInputArray = false;
51 var $nameQuote = '`'; /// string to use to quote identifiers and names
52 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0));
53 var $arrayClass = 'ADORecordSet_array_mysqli';
54 var $multiQuery = false;
56 function ADODB_mysqli()
58 // if(!extension_loaded("mysqli"))
59 ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
63 function SetTransactionMode( $transaction_mode )
65 $this->_transmode = $transaction_mode;
66 if (empty($transaction_mode)) {
67 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
68 return;
70 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
71 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
74 // returns true or false
75 // To add: parameter int $port,
76 // parameter string $socket
77 function _connect($argHostname = NULL,
78 $argUsername = NULL,
79 $argPassword = NULL,
80 $argDatabasename = NULL, $persist=false)
82 if(!extension_loaded("mysqli")) {
83 return null;
85 $this->_connectionID = @mysqli_init();
87 if (is_null($this->_connectionID)) {
88 // mysqli_init only fails if insufficient memory
89 if ($this->debug)
90 ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg());
91 return false;
94 I suggest a simple fix which would enable adodb and mysqli driver to
95 read connection options from the standard mysql configuration file
96 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
98 foreach($this->optionFlags as $arr) {
99 mysqli_options($this->_connectionID,$arr[0],$arr[1]);
102 //http ://php.net/manual/en/mysqli.persistconns.php
103 if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname,'p:',2) != 0) $argHostname = 'p:'.$argHostname;
105 #if (!empty($this->port)) $argHostname .= ":".$this->port;
106 $ok = mysqli_real_connect($this->_connectionID,
107 $argHostname,
108 $argUsername,
109 $argPassword,
110 $argDatabasename,
111 $this->port,
112 $this->socket,
113 $this->clientFlags);
115 if ($ok) {
116 if ($argDatabasename) return $this->SelectDB($argDatabasename);
117 return true;
118 } else {
119 if ($this->debug)
120 ADOConnection::outp("Could't connect : " . $this->ErrorMsg());
121 $this->_connectionID = null;
122 return false;
126 // returns true or false
127 // How to force a persistent connection
128 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
130 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
134 // When is this used? Close old connection first?
135 // In _connect(), check $this->forceNewConnect?
136 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
138 $this->forceNewConnect = true;
139 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
142 function IfNull( $field, $ifNull )
144 return " IFNULL($field, $ifNull) "; // if MySQL
147 // do not use $ADODB_COUNTRECS
148 function GetOne($sql,$inputarr=false)
150 global $ADODB_GETONE_EOF;
152 $ret = false;
153 $rs = $this->Execute($sql,$inputarr);
154 if ($rs) {
155 if ($rs->EOF) $ret = $ADODB_GETONE_EOF;
156 else $ret = reset($rs->fields);
157 $rs->Close();
159 return $ret;
162 function ServerInfo()
164 $arr['description'] = $this->GetOne("select version()");
165 $arr['version'] = ADOConnection::_findvers($arr['description']);
166 return $arr;
170 function BeginTrans()
172 if ($this->transOff) return true;
173 $this->transCnt += 1;
175 //$this->Execute('SET AUTOCOMMIT=0');
176 mysqli_autocommit($this->_connectionID, false);
177 $this->Execute('BEGIN');
178 return true;
181 function CommitTrans($ok=true)
183 if ($this->transOff) return true;
184 if (!$ok) return $this->RollbackTrans();
186 if ($this->transCnt) $this->transCnt -= 1;
187 $this->Execute('COMMIT');
189 //$this->Execute('SET AUTOCOMMIT=1');
190 mysqli_autocommit($this->_connectionID, true);
191 return true;
194 function RollbackTrans()
196 if ($this->transOff) return true;
197 if ($this->transCnt) $this->transCnt -= 1;
198 $this->Execute('ROLLBACK');
199 //$this->Execute('SET AUTOCOMMIT=1');
200 mysqli_autocommit($this->_connectionID, true);
201 return true;
204 function RowLock($tables,$where='',$col='1 as adodbignore')
206 if ($this->transCnt==0) $this->BeginTrans();
207 if ($where) $where = ' where '.$where;
208 $rs = $this->Execute("select $col from $tables $where for update");
209 return !empty($rs);
212 // if magic quotes disabled, use mysql_real_escape_string()
213 // From readme.htm:
214 // Quotes a string to be sent to the database. The $magic_quotes_enabled
215 // parameter may look funny, but the idea is if you are quoting a
216 // string extracted from a POST/GET variable, then
217 // pass get_magic_quotes_gpc() as the second parameter. This will
218 // ensure that the variable is not quoted twice, once by qstr and once
219 // by the magic_quotes_gpc.
221 //Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
222 function qstr($s, $magic_quotes = false)
224 if (is_null($s)) return 'NULL';
225 if (!$magic_quotes) {
226 if (PHP_VERSION >= 5)
227 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
229 if ($this->replaceQuote[0] == '\\')
230 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
231 return "'".str_replace("'",$this->replaceQuote,$s)."'";
233 // undo magic quotes for "
234 $s = str_replace('\\"','"',$s);
235 return "'$s'";
238 function _insertid()
240 $result = @mysqli_insert_id($this->_connectionID);
241 if ($result == -1){
242 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg());
244 return $result;
247 // Only works for INSERT, UPDATE and DELETE query's
248 function _affectedrows()
250 $result = @mysqli_affected_rows($this->_connectionID);
251 if ($result == -1) {
252 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg());
254 return $result;
257 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
258 // Reference on Last_Insert_ID on the recommended way to simulate sequences
259 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
260 var $_genSeqSQL = "create table %s (id int not null)";
261 var $_genSeqCountSQL = "select count(*) from %s";
262 var $_genSeq2SQL = "insert into %s values (%s)";
263 var $_dropSeqSQL = "drop table %s";
265 function CreateSequence($seqname='adodbseq',$startID=1)
267 if (empty($this->_genSeqSQL)) return false;
268 $u = strtoupper($seqname);
270 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
271 if (!$ok) return false;
272 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
275 function GenID($seqname='adodbseq',$startID=1)
277 // post-nuke sets hasGenID to false
278 if (!$this->hasGenID) return false;
280 $getnext = sprintf($this->_genIDSQL,$seqname);
281 $holdtransOK = $this->_transOK; // save the current status
282 $rs = @$this->Execute($getnext);
283 if (!$rs) {
284 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
285 $u = strtoupper($seqname);
286 $this->Execute(sprintf($this->_genSeqSQL,$seqname));
287 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
288 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
289 $rs = $this->Execute($getnext);
292 if ($rs) {
293 $this->genID = mysqli_insert_id($this->_connectionID);
294 $rs->Close();
295 } else
296 $this->genID = 0;
298 return $this->genID;
301 function MetaDatabases()
303 $query = "SHOW DATABASES";
304 $ret = $this->Execute($query);
305 if ($ret && is_object($ret)){
306 $arr = array();
307 while (!$ret->EOF){
308 $db = $ret->Fields('Database');
309 if ($db != 'mysql') $arr[] = $db;
310 $ret->MoveNext();
312 return $arr;
314 return $ret;
318 function MetaIndexes ($table, $primary = FALSE, $owner = false)
320 // save old fetch mode
321 global $ADODB_FETCH_MODE;
323 $false = false;
324 $save = $ADODB_FETCH_MODE;
325 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
326 if ($this->fetchMode !== FALSE) {
327 $savem = $this->SetFetchMode(FALSE);
330 // get index details
331 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table));
333 // restore fetchmode
334 if (isset($savem)) {
335 $this->SetFetchMode($savem);
337 $ADODB_FETCH_MODE = $save;
339 if (!is_object($rs)) {
340 return $false;
343 $indexes = array ();
345 // parse index data into array
346 while ($row = $rs->FetchRow()) {
347 if ($primary == FALSE AND $row[2] == 'PRIMARY') {
348 continue;
351 if (!isset($indexes[$row[2]])) {
352 $indexes[$row[2]] = array(
353 'unique' => ($row[1] == 0),
354 'columns' => array()
358 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
361 // sort columns by order in the index
362 foreach ( array_keys ($indexes) as $index )
364 ksort ($indexes[$index]['columns']);
367 return $indexes;
371 // Format date column in sql string given an input format that understands Y M D
372 function SQLDate($fmt, $col=false)
374 if (!$col) $col = $this->sysTimeStamp;
375 $s = 'DATE_FORMAT('.$col.",'";
376 $concat = false;
377 $len = strlen($fmt);
378 for ($i=0; $i < $len; $i++) {
379 $ch = $fmt[$i];
380 switch($ch) {
381 case 'Y':
382 case 'y':
383 $s .= '%Y';
384 break;
385 case 'Q':
386 case 'q':
387 $s .= "'),Quarter($col)";
389 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
390 else $s .= ",('";
391 $concat = true;
392 break;
393 case 'M':
394 $s .= '%b';
395 break;
397 case 'm':
398 $s .= '%m';
399 break;
400 case 'D':
401 case 'd':
402 $s .= '%d';
403 break;
405 case 'H':
406 $s .= '%H';
407 break;
409 case 'h':
410 $s .= '%I';
411 break;
413 case 'i':
414 $s .= '%i';
415 break;
417 case 's':
418 $s .= '%s';
419 break;
421 case 'a':
422 case 'A':
423 $s .= '%p';
424 break;
426 case 'w':
427 $s .= '%w';
428 break;
430 case 'l':
431 $s .= '%W';
432 break;
434 default:
436 if ($ch == '\\') {
437 $i++;
438 $ch = substr($fmt,$i,1);
440 $s .= $ch;
441 break;
444 $s.="')";
445 if ($concat) $s = "CONCAT($s)";
446 return $s;
449 // returns concatenated string
450 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
451 function Concat()
453 $s = "";
454 $arr = func_get_args();
456 // suggestion by andrew005@mnogo.ru
457 $s = implode(',',$arr);
458 if (strlen($s) > 0) return "CONCAT($s)";
459 else return '';
462 // dayFraction is a day in floating point
463 function OffsetDate($dayFraction,$date=false)
465 if (!$date) $date = $this->sysDate;
467 $fraction = $dayFraction * 24 * 3600;
468 return $date . ' + INTERVAL ' . $fraction.' SECOND';
470 // return "from_unixtime(unix_timestamp($date)+$fraction)";
473 function MetaTables($ttype=false,$showSchema=false,$mask=false)
475 $save = $this->metaTablesSQL;
476 if ($showSchema && is_string($showSchema)) {
477 $this->metaTablesSQL .= " from $showSchema";
480 if ($mask) {
481 $mask = $this->qstr($mask);
482 $this->metaTablesSQL .= " like $mask";
484 $ret = ADOConnection::MetaTables($ttype,$showSchema);
486 $this->metaTablesSQL = $save;
487 return $ret;
490 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
491 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
493 global $ADODB_FETCH_MODE;
495 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
497 if ( !empty($owner) ) {
498 $table = "$owner.$table";
500 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
501 if ($associative) {
502 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
503 } else $create_sql = $a_create_table[1];
505 $matches = array();
507 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
508 $foreign_keys = array();
509 $num_keys = count($matches[0]);
510 for ( $i = 0; $i < $num_keys; $i ++ ) {
511 $my_field = explode('`, `', $matches[1][$i]);
512 $ref_table = $matches[2][$i];
513 $ref_field = explode('`, `', $matches[3][$i]);
515 if ( $upper ) {
516 $ref_table = strtoupper($ref_table);
519 // see https://sourceforge.net/tracker/index.php?func=detail&aid=2287278&group_id=42718&atid=433976
520 if (!isset($foreign_keys[$ref_table])) {
521 $foreign_keys[$ref_table] = array();
523 $num_fields = count($my_field);
524 for ( $j = 0; $j < $num_fields; $j ++ ) {
525 if ( $associative ) {
526 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
527 } else {
528 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
533 return $foreign_keys;
536 function MetaColumns($table, $normalize=true)
538 $false = false;
539 if (!$this->metaColumnsSQL)
540 return $false;
542 global $ADODB_FETCH_MODE;
543 $save = $ADODB_FETCH_MODE;
544 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
545 if ($this->fetchMode !== false)
546 $savem = $this->SetFetchMode(false);
547 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
548 if (isset($savem)) $this->SetFetchMode($savem);
549 $ADODB_FETCH_MODE = $save;
550 if (!is_object($rs))
551 return $false;
553 $retarr = array();
554 while (!$rs->EOF) {
555 $fld = new ADOFieldObject();
556 $fld->name = $rs->fields[0];
557 $type = $rs->fields[1];
559 // split type into type(length):
560 $fld->scale = null;
561 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
562 $fld->type = $query_array[1];
563 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
564 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
565 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
566 $fld->type = $query_array[1];
567 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
568 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
569 $fld->type = $query_array[1];
570 $arr = explode(",",$query_array[2]);
571 $fld->enums = $arr;
572 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
573 $fld->max_length = ($zlen > 0) ? $zlen : 1;
574 } else {
575 $fld->type = $type;
576 $fld->max_length = -1;
578 $fld->not_null = ($rs->fields[2] != 'YES');
579 $fld->primary_key = ($rs->fields[3] == 'PRI');
580 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
581 $fld->binary = (strpos($type,'blob') !== false);
582 $fld->unsigned = (strpos($type,'unsigned') !== false);
583 $fld->zerofill = (strpos($type,'zerofill') !== false);
585 if (!$fld->binary) {
586 $d = $rs->fields[4];
587 if ($d != '' && $d != 'NULL') {
588 $fld->has_default = true;
589 $fld->default_value = $d;
590 } else {
591 $fld->has_default = false;
595 if ($save == ADODB_FETCH_NUM) {
596 $retarr[] = $fld;
597 } else {
598 $retarr[strtoupper($fld->name)] = $fld;
600 $rs->MoveNext();
603 $rs->Close();
604 return $retarr;
607 // returns true or false
608 function SelectDB($dbName)
610 // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
611 $this->database = $dbName;
612 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
614 if ($this->_connectionID) {
615 $result = @mysqli_select_db($this->_connectionID, $dbName);
616 if (!$result) {
617 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
619 return $result;
621 return false;
624 // parameters use PostgreSQL convention, not MySQL
625 function SelectLimit($sql,
626 $nrows = -1,
627 $offset = -1,
628 $inputarr = false,
629 $secs = 0)
631 $offsetStr = ($offset >= 0) ? "$offset," : '';
632 if ($nrows < 0) $nrows = '18446744073709551615';
634 if ($secs)
635 $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr );
636 else
637 $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr );
639 return $rs;
643 function Prepare($sql)
645 return $sql;
646 $stmt = $this->_connectionID->prepare($sql);
647 if (!$stmt) {
648 echo $this->ErrorMsg();
649 return $sql;
651 return array($sql,$stmt);
655 // returns queryID or false
656 function _query($sql, $inputarr)
658 global $ADODB_COUNTRECS;
659 // Move to the next recordset, or return false if there is none. In a stored proc
660 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
661 // returns false. I think this is because the last "recordset" is actually just the
662 // return value of the stored proc (ie the number of rows affected).
663 // Commented out for reasons of performance. You should retrieve every recordset yourself.
664 // if (!mysqli_next_result($this->connection->_connectionID)) return false;
666 if (is_array($sql)) {
668 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but
669 // returns as bound variables.
671 $stmt = $sql[1];
672 $a = '';
673 foreach($inputarr as $k => $v) {
674 if (is_string($v)) $a .= 's';
675 else if (is_integer($v)) $a .= 'i';
676 else $a .= 'd';
679 $fnarr = array_merge( array($stmt,$a) , $inputarr);
680 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr);
681 $ret = mysqli_stmt_execute($stmt);
682 return $ret;
686 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
687 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
688 return false;
691 return $mysql_res;
694 if ($this->multiQuery) {
695 $rs = mysqli_multi_query($this->_connectionID, $sql.';');
696 if ($rs) {
697 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID );
698 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID )
700 } else {
701 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
703 if ($rs) return $rs;
706 if($this->debug)
707 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
709 return false;
713 /* Returns: the last error message from previous database operation */
714 function ErrorMsg()
716 if (empty($this->_connectionID))
717 $this->_errorMsg = @mysqli_connect_error();
718 else
719 $this->_errorMsg = @mysqli_error($this->_connectionID);
720 return $this->_errorMsg;
723 /* Returns: the last error number from previous database operation */
724 function ErrorNo()
726 if (empty($this->_connectionID))
727 return @mysqli_connect_errno();
728 else
729 return @mysqli_errno($this->_connectionID);
732 // returns true or false
733 function _close()
735 @mysqli_close($this->_connectionID);
736 $this->_connectionID = false;
740 * Maximum size of C field
742 function CharMax()
744 return 255;
748 * Maximum size of X field
750 function TextMax()
752 return 4294967295;
757 // this is a set of functions for managing client encoding - very important if the encodings
758 // of your database and your output target (i.e. HTML) don't match
759 // for instance, you may have UTF8 database and server it on-site as latin1 etc.
760 // GetCharSet - get the name of the character set the client is using now
761 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
762 // depends on compile flags of mysql distribution
764 function GetCharSet()
766 //we will use ADO's builtin property charSet
767 if (!method_exists($this->_connectionID,'character_set_name'))
768 return false;
770 $this->charSet = @$this->_connectionID->character_set_name();
771 if (!$this->charSet) {
772 return false;
773 } else {
774 return $this->charSet;
778 // SetCharSet - switch the client encoding
779 function SetCharSet($charset_name)
781 if (!method_exists($this->_connectionID,'set_charset'))
782 return false;
784 if ($this->charSet !== $charset_name) {
785 $if = @$this->_connectionID->set_charset($charset_name);
786 if ($if == "0" & $this->GetCharSet() == $charset_name) {
787 return true;
788 } else return false;
789 } else return true;
797 /*--------------------------------------------------------------------------------------
798 Class Name: Recordset
799 --------------------------------------------------------------------------------------*/
801 class ADORecordSet_mysqli extends ADORecordSet{
803 var $databaseType = "mysqli";
804 var $canSeek = true;
806 function ADORecordSet_mysqli($queryID, $mode = false)
808 if ($mode === false)
810 global $ADODB_FETCH_MODE;
811 $mode = $ADODB_FETCH_MODE;
814 switch ($mode)
816 case ADODB_FETCH_NUM:
817 $this->fetchMode = MYSQLI_NUM;
818 break;
819 case ADODB_FETCH_ASSOC:
820 $this->fetchMode = MYSQLI_ASSOC;
821 break;
822 case ADODB_FETCH_DEFAULT:
823 case ADODB_FETCH_BOTH:
824 default:
825 $this->fetchMode = MYSQLI_BOTH;
826 break;
828 $this->adodbFetchMode = $mode;
829 $this->ADORecordSet($queryID);
832 function _initrs()
834 global $ADODB_COUNTRECS;
836 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
837 $this->_numOfFields = @mysqli_num_fields($this->_queryID);
841 1 = MYSQLI_NOT_NULL_FLAG
842 2 = MYSQLI_PRI_KEY_FLAG
843 4 = MYSQLI_UNIQUE_KEY_FLAG
844 8 = MYSQLI_MULTIPLE_KEY_FLAG
845 16 = MYSQLI_BLOB_FLAG
846 32 = MYSQLI_UNSIGNED_FLAG
847 64 = MYSQLI_ZEROFILL_FLAG
848 128 = MYSQLI_BINARY_FLAG
849 256 = MYSQLI_ENUM_FLAG
850 512 = MYSQLI_AUTO_INCREMENT_FLAG
851 1024 = MYSQLI_TIMESTAMP_FLAG
852 2048 = MYSQLI_SET_FLAG
853 32768 = MYSQLI_NUM_FLAG
854 16384 = MYSQLI_PART_KEY_FLAG
855 32768 = MYSQLI_GROUP_FLAG
856 65536 = MYSQLI_UNIQUE_FLAG
857 131072 = MYSQLI_BINCMP_FLAG
860 function FetchField($fieldOffset = -1)
862 $fieldnr = $fieldOffset;
863 if ($fieldOffset != -1) {
864 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr);
866 $o = @mysqli_fetch_field($this->_queryID);
867 if (!$o) return false;
868 /* Properties of an ADOFieldObject as set by MetaColumns */
869 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
870 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
871 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
872 $o->binary = $o->flags & MYSQLI_BINARY_FLAG;
873 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
874 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
876 return $o;
879 function GetRowAssoc($upper = true)
881 if ($this->fetchMode == MYSQLI_ASSOC && !$upper)
882 return $this->fields;
883 $row = ADORecordSet::GetRowAssoc($upper);
884 return $row;
887 /* Use associative array to get fields array */
888 function Fields($colname)
890 if ($this->fetchMode != MYSQLI_NUM)
891 return @$this->fields[$colname];
893 if (!$this->bind) {
894 $this->bind = array();
895 for ($i = 0; $i < $this->_numOfFields; $i++) {
896 $o = $this->FetchField($i);
897 $this->bind[strtoupper($o->name)] = $i;
900 return $this->fields[$this->bind[strtoupper($colname)]];
903 function _seek($row)
905 if ($this->_numOfRows == 0)
906 return false;
908 if ($row < 0)
909 return false;
911 mysqli_data_seek($this->_queryID, $row);
912 $this->EOF = false;
913 return true;
917 function NextRecordSet()
919 global $ADODB_COUNTRECS;
921 mysqli_free_result($this->_queryID);
922 $this->_queryID = -1;
923 // Move to the next recordset, or return false if there is none. In a stored proc
924 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
925 // returns false. I think this is because the last "recordset" is actually just the
926 // return value of the stored proc (ie the number of rows affected).
927 if(!mysqli_next_result($this->connection->_connectionID)) {
928 return false;
930 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using
931 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID )
932 : @mysqli_use_result( $this->connection->_connectionID );
933 if(!$this->_queryID) {
934 return false;
936 $this->_inited = false;
937 $this->bind = false;
938 $this->_currentRow = -1;
939 $this->Init();
940 return true;
943 // 10% speedup to move MoveNext to child class
944 // This is the only implementation that works now (23-10-2003).
945 // Other functions return no or the wrong results.
946 function MoveNext()
948 if ($this->EOF) return false;
949 $this->_currentRow++;
950 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode);
952 if (is_array($this->fields)) return true;
953 $this->EOF = true;
954 return false;
957 function _fetch()
959 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode);
960 return is_array($this->fields);
963 function _close()
965 //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014
966 //only a problem with persistant connections
968 //mysqli_next_result($this->connection->_connectionID); trashes the DB side attached results.
970 while(mysqli_more_results($this->connection->_connectionID)){
971 @mysqli_next_result($this->connection->_connectionID);
974 //Because you can have one attached result, without tripping mysqli_more_results
975 @mysqli_next_result($this->connection->_connectionID);
978 mysqli_free_result($this->_queryID);
979 $this->_queryID = false;
984 0 = MYSQLI_TYPE_DECIMAL
985 1 = MYSQLI_TYPE_CHAR
986 1 = MYSQLI_TYPE_TINY
987 2 = MYSQLI_TYPE_SHORT
988 3 = MYSQLI_TYPE_LONG
989 4 = MYSQLI_TYPE_FLOAT
990 5 = MYSQLI_TYPE_DOUBLE
991 6 = MYSQLI_TYPE_NULL
992 7 = MYSQLI_TYPE_TIMESTAMP
993 8 = MYSQLI_TYPE_LONGLONG
994 9 = MYSQLI_TYPE_INT24
995 10 = MYSQLI_TYPE_DATE
996 11 = MYSQLI_TYPE_TIME
997 12 = MYSQLI_TYPE_DATETIME
998 13 = MYSQLI_TYPE_YEAR
999 14 = MYSQLI_TYPE_NEWDATE
1000 247 = MYSQLI_TYPE_ENUM
1001 248 = MYSQLI_TYPE_SET
1002 249 = MYSQLI_TYPE_TINY_BLOB
1003 250 = MYSQLI_TYPE_MEDIUM_BLOB
1004 251 = MYSQLI_TYPE_LONG_BLOB
1005 252 = MYSQLI_TYPE_BLOB
1006 253 = MYSQLI_TYPE_VAR_STRING
1007 254 = MYSQLI_TYPE_STRING
1008 255 = MYSQLI_TYPE_GEOMETRY
1011 function MetaType($t, $len = -1, $fieldobj = false)
1013 if (is_object($t)) {
1014 $fieldobj = $t;
1015 $t = $fieldobj->type;
1016 $len = $fieldobj->max_length;
1020 $len = -1; // mysql max_length is not accurate
1021 switch (strtoupper($t)) {
1022 case 'STRING':
1023 case 'CHAR':
1024 case 'VARCHAR':
1025 case 'TINYBLOB':
1026 case 'TINYTEXT':
1027 case 'ENUM':
1028 case 'SET':
1030 case MYSQLI_TYPE_TINY_BLOB :
1031 #case MYSQLI_TYPE_CHAR :
1032 case MYSQLI_TYPE_STRING :
1033 case MYSQLI_TYPE_ENUM :
1034 case MYSQLI_TYPE_SET :
1035 case 253 :
1036 if ($len <= $this->blobSize) return 'C';
1038 case 'TEXT':
1039 case 'LONGTEXT':
1040 case 'MEDIUMTEXT':
1041 return 'X';
1044 // php_mysql extension always returns 'blob' even if 'text'
1045 // so we have to check whether binary...
1046 case 'IMAGE':
1047 case 'LONGBLOB':
1048 case 'BLOB':
1049 case 'MEDIUMBLOB':
1051 case MYSQLI_TYPE_BLOB :
1052 case MYSQLI_TYPE_LONG_BLOB :
1053 case MYSQLI_TYPE_MEDIUM_BLOB :
1055 return !empty($fieldobj->binary) ? 'B' : 'X';
1056 case 'YEAR':
1057 case 'DATE':
1058 case MYSQLI_TYPE_DATE :
1059 case MYSQLI_TYPE_YEAR :
1061 return 'D';
1063 case 'TIME':
1064 case 'DATETIME':
1065 case 'TIMESTAMP':
1067 case MYSQLI_TYPE_DATETIME :
1068 case MYSQLI_TYPE_NEWDATE :
1069 case MYSQLI_TYPE_TIME :
1070 case MYSQLI_TYPE_TIMESTAMP :
1072 return 'T';
1074 case 'INT':
1075 case 'INTEGER':
1076 case 'BIGINT':
1077 case 'TINYINT':
1078 case 'MEDIUMINT':
1079 case 'SMALLINT':
1081 case MYSQLI_TYPE_INT24 :
1082 case MYSQLI_TYPE_LONG :
1083 case MYSQLI_TYPE_LONGLONG :
1084 case MYSQLI_TYPE_SHORT :
1085 case MYSQLI_TYPE_TINY :
1087 if (!empty($fieldobj->primary_key)) return 'R';
1089 return 'I';
1092 // Added floating-point types
1093 // Maybe not necessery.
1094 case 'FLOAT':
1095 case 'DOUBLE':
1096 // case 'DOUBLE PRECISION':
1097 case 'DECIMAL':
1098 case 'DEC':
1099 case 'FIXED':
1100 default:
1101 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1102 return 'N';
1104 } // function
1107 } // rs class
1111 class ADORecordSet_array_mysqli extends ADORecordSet_array {
1113 function ADORecordSet_array_mysqli($id=-1,$mode=false)
1115 $this->ADORecordSet_array($id,$mode);
1118 function MetaType($t, $len = -1, $fieldobj = false)
1120 if (is_object($t)) {
1121 $fieldobj = $t;
1122 $t = $fieldobj->type;
1123 $len = $fieldobj->max_length;
1127 $len = -1; // mysql max_length is not accurate
1128 switch (strtoupper($t)) {
1129 case 'STRING':
1130 case 'CHAR':
1131 case 'VARCHAR':
1132 case 'TINYBLOB':
1133 case 'TINYTEXT':
1134 case 'ENUM':
1135 case 'SET':
1137 case MYSQLI_TYPE_TINY_BLOB :
1138 #case MYSQLI_TYPE_CHAR :
1139 case MYSQLI_TYPE_STRING :
1140 case MYSQLI_TYPE_ENUM :
1141 case MYSQLI_TYPE_SET :
1142 case 253 :
1143 if ($len <= $this->blobSize) return 'C';
1145 case 'TEXT':
1146 case 'LONGTEXT':
1147 case 'MEDIUMTEXT':
1148 return 'X';
1151 // php_mysql extension always returns 'blob' even if 'text'
1152 // so we have to check whether binary...
1153 case 'IMAGE':
1154 case 'LONGBLOB':
1155 case 'BLOB':
1156 case 'MEDIUMBLOB':
1158 case MYSQLI_TYPE_BLOB :
1159 case MYSQLI_TYPE_LONG_BLOB :
1160 case MYSQLI_TYPE_MEDIUM_BLOB :
1162 return !empty($fieldobj->binary) ? 'B' : 'X';
1163 case 'YEAR':
1164 case 'DATE':
1165 case MYSQLI_TYPE_DATE :
1166 case MYSQLI_TYPE_YEAR :
1168 return 'D';
1170 case 'TIME':
1171 case 'DATETIME':
1172 case 'TIMESTAMP':
1174 case MYSQLI_TYPE_DATETIME :
1175 case MYSQLI_TYPE_NEWDATE :
1176 case MYSQLI_TYPE_TIME :
1177 case MYSQLI_TYPE_TIMESTAMP :
1179 return 'T';
1181 case 'INT':
1182 case 'INTEGER':
1183 case 'BIGINT':
1184 case 'TINYINT':
1185 case 'MEDIUMINT':
1186 case 'SMALLINT':
1188 case MYSQLI_TYPE_INT24 :
1189 case MYSQLI_TYPE_LONG :
1190 case MYSQLI_TYPE_LONGLONG :
1191 case MYSQLI_TYPE_SHORT :
1192 case MYSQLI_TYPE_TINY :
1194 if (!empty($fieldobj->primary_key)) return 'R';
1196 return 'I';
1199 // Added floating-point types
1200 // Maybe not necessery.
1201 case 'FLOAT':
1202 case 'DOUBLE':
1203 // case 'DOUBLE PRECISION':
1204 case 'DECIMAL':
1205 case 'DEC':
1206 case 'FIXED':
1207 default:
1208 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1209 return 'N';
1211 } // function