1<?php
2/*
3V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). 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
1221 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
13Based on adodb 3.40
14*/
15
16// security - hide paths
17if (!defined('ADODB_DIR')) die();
18
19if (! 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
29class 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
54	function ADODB_mysqli()
55	{
56	 // if(!extension_loaded("mysqli"))
57	      ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
58
59	}
60
61	function SetTransactionMode( $transaction_mode )
62	{
63		$this->_transmode  = $transaction_mode;
64		if (empty($transaction_mode)) {
65			$this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
66			return;
67		}
68		if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
69		$this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
70	}
71
72	// returns true or false
73	// To add: parameter int $port,
74	//         parameter string $socket
75	function _connect($argHostname = NULL,
76			  $argUsername = NULL,
77			  $argPassword = NULL,
78			  $argDatabasename = NULL, $persist=false)
79	  {
80	  	 if(!extension_loaded("mysqli")) {
81			return null;
82		 }
83	    $this->_connectionID = @mysqli_init();
84
85	    if (is_null($this->_connectionID)) {
86	      // mysqli_init only fails if insufficient memory
87	      if ($this->debug)
88				ADOConnection::outp("mysqli_init() failed : "  . $this->ErrorMsg());
89	      return false;
90	    }
91		/*
92		I suggest a simple fix which would enable adodb and mysqli driver to
93		read connection options from the standard mysql configuration file
94		/etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
95		*/
96		foreach($this->optionFlags as $arr) {
97			mysqli_options($this->_connectionID,$arr[0],$arr[1]);
98		}
99
100		#if (!empty($this->port)) $argHostname .= ":".$this->port;
101		$ok = mysqli_real_connect($this->_connectionID,
102 				    $argHostname,
103 				    $argUsername,
104 				    $argPassword,
105 				    $argDatabasename,
106					$this->port,
107					$this->socket,
108					$this->clientFlags);
109
110		if ($ok) {
111	 		if ($argDatabasename)  return $this->SelectDB($argDatabasename);
112 			return true;
113 	   } else {
114			if ($this->debug)
115		  		ADOConnection::outp("Could't connect : "  . $this->ErrorMsg());
116			return false;
117	   }
118	}
119
120	// returns true or false
121	// How to force a persistent connection
122	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
123	{
124		return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
125
126	}
127
128	// When is this used? Close old connection first?
129	// In _connect(), check $this->forceNewConnect?
130	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
131	  {
132	    $this->forceNewConnect = true;
133	    return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
134	  }
135
136	function IfNull( $field, $ifNull )
137	{
138		return " IFNULL($field, $ifNull) "; // if MySQL
139	}
140
141	// do not use $ADODB_COUNTRECS
142	function GetOne($sql,$inputarr=false)
143	{
144		$ret = false;
145		$rs = &$this->Execute($sql,$inputarr);
146		if ($rs) {
147			if (!$rs->EOF) $ret = reset($rs->fields);
148			$rs->Close();
149		}
150		return $ret;
151	}
152
153	function ServerInfo()
154	{
155		$arr['description'] = $this->GetOne("select version()");
156		$arr['version'] = ADOConnection::_findvers($arr['description']);
157		return $arr;
158	}
159
160
161	function BeginTrans()
162	{
163		if ($this->transOff) return true;
164		$this->transCnt += 1;
165
166		//$this->Execute('SET AUTOCOMMIT=0');
167		mysqli_autocommit($this->_connectionID, false);
168		$this->Execute('BEGIN');
169		return true;
170	}
171
172	function CommitTrans($ok=true)
173	{
174		if ($this->transOff) return true;
175		if (!$ok) return $this->RollbackTrans();
176
177		if ($this->transCnt) $this->transCnt -= 1;
178		$this->Execute('COMMIT');
179
180		//$this->Execute('SET AUTOCOMMIT=1');
181		mysqli_autocommit($this->_connectionID, true);
182		return true;
183	}
184
185	function RollbackTrans()
186	{
187		if ($this->transOff) return true;
188		if ($this->transCnt) $this->transCnt -= 1;
189		$this->Execute('ROLLBACK');
190		//$this->Execute('SET AUTOCOMMIT=1');
191		mysqli_autocommit($this->_connectionID, true);
192		return true;
193	}
194
195	function RowLock($tables,$where='',$flds='1 as adodb_ignore')
196	{
197		if ($this->transCnt==0) $this->BeginTrans();
198		if ($where) $where = ' where '.$where;
199		$rs =& $this->Execute("select $flds from $tables $where for update");
200		return !empty($rs);
201	}
202
203	// if magic quotes disabled, use mysql_real_escape_string()
204	// From readme.htm:
205	// Quotes a string to be sent to the database. The $magic_quotes_enabled
206	// parameter may look funny, but the idea is if you are quoting a
207	// string extracted from a POST/GET variable, then
208	// pass get_magic_quotes_gpc() as the second parameter. This will
209	// ensure that the variable is not quoted twice, once by qstr and once
210	// by the magic_quotes_gpc.
211	//
212	//Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
213	function qstr($s, $magic_quotes = false)
214	{
215		if (!$magic_quotes) {
216	    	if (PHP_VERSION >= 5)
217	      		return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
218
219		if ($this->replaceQuote[0] == '\\')
220			$s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
221	    return  "'".str_replace("'",$this->replaceQuote,$s)."'";
222	  }
223	  // undo magic quotes for "
224	  $s = str_replace('\\"','"',$s);
225	  return "'$s'";
226	}
227
228	function _insertid()
229	{
230	  $result = @mysqli_insert_id($this->_connectionID);
231	  if ($result == -1){
232	      if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : "  . $this->ErrorMsg());
233	  }
234	  return $result;
235	}
236
237	// Only works for INSERT, UPDATE and DELETE query's
238	function _affectedrows()
239	{
240	  $result =  @mysqli_affected_rows($this->_connectionID);
241	  if ($result == -1) {
242	      if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : "  . $this->ErrorMsg());
243	  }
244	  return $result;
245	}
246
247 	// See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
248	// Reference on Last_Insert_ID on the recommended way to simulate sequences
249 	var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
250	var $_genSeqSQL = "create table %s (id int not null)";
251	var $_genSeq2SQL = "insert into %s values (%s)";
252	var $_dropSeqSQL = "drop table %s";
253
254	function CreateSequence($seqname='adodbseq',$startID=1)
255	{
256		if (empty($this->_genSeqSQL)) return false;
257		$u = strtoupper($seqname);
258
259		$ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
260		if (!$ok) return false;
261		return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
262	}
263
264	function GenID($seqname='adodbseq',$startID=1)
265	{
266		// post-nuke sets hasGenID to false
267		if (!$this->hasGenID) return false;
268
269		$getnext = sprintf($this->_genIDSQL,$seqname);
270		$holdtransOK = $this->_transOK; // save the current status
271		$rs = @$this->Execute($getnext);
272		if (!$rs) {
273			if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
274			$u = strtoupper($seqname);
275			$this->Execute(sprintf($this->_genSeqSQL,$seqname));
276			$this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
277			$rs = $this->Execute($getnext);
278		}
279		$this->genID = mysqli_insert_id($this->_connectionID);
280
281		if ($rs) $rs->Close();
282
283		return $this->genID;
284	}
285
286  	function &MetaDatabases()
287	{
288		$query = "SHOW DATABASES";
289		$ret =& $this->Execute($query);
290		if ($ret && is_object($ret)){
291		   $arr = array();
292			while (!$ret->EOF){
293				$db = $ret->Fields('Database');
294				if ($db != 'mysql') $arr[] = $db;
295				$ret->MoveNext();
296			}
297   		   return $arr;
298		}
299        return $ret;
300	}
301
302
303	function &MetaIndexes ($table, $primary = FALSE)
304	{
305		// save old fetch mode
306		global $ADODB_FETCH_MODE;
307
308		$false = false;
309		$save = $ADODB_FETCH_MODE;
310		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
311		if ($this->fetchMode !== FALSE) {
312		       $savem = $this->SetFetchMode(FALSE);
313		}
314
315		// get index details
316		$rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table));
317
318		// restore fetchmode
319		if (isset($savem)) {
320		        $this->SetFetchMode($savem);
321		}
322		$ADODB_FETCH_MODE = $save;
323
324		if (!is_object($rs)) {
325		        return $false;
326		}
327
328		$indexes = array ();
329
330		// parse index data into array
331		while ($row = $rs->FetchRow()) {
332		        if ($primary == FALSE AND $row[2] == 'PRIMARY') {
333		                continue;
334		        }
335
336		        if (!isset($indexes[$row[2]])) {
337		                $indexes[$row[2]] = array(
338		                        'unique' => ($row[1] == 0),
339		                        'columns' => array()
340		                );
341		        }
342
343		        $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
344		}
345
346		// sort columns by order in the index
347		foreach ( array_keys ($indexes) as $index )
348		{
349		        ksort ($indexes[$index]['columns']);
350		}
351
352		return $indexes;
353	}
354
355
356	// Format date column in sql string given an input format that understands Y M D
357	function SQLDate($fmt, $col=false)
358	{
359		if (!$col) $col = $this->sysTimeStamp;
360		$s = 'DATE_FORMAT('.$col.",'";
361		$concat = false;
362		$len = strlen($fmt);
363		for ($i=0; $i < $len; $i++) {
364			$ch = $fmt[$i];
365			switch($ch) {
366			case 'Y':
367			case 'y':
368				$s .= '%Y';
369				break;
370			case 'Q':
371			case 'q':
372				$s .= "'),Quarter($col)";
373
374				if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
375				else $s .= ",('";
376				$concat = true;
377				break;
378			case 'M':
379				$s .= '%b';
380				break;
381
382			case 'm':
383				$s .= '%m';
384				break;
385			case 'D':
386			case 'd':
387				$s .= '%d';
388				break;
389
390			case 'H':
391				$s .= '%H';
392				break;
393
394			case 'h':
395				$s .= '%I';
396				break;
397
398			case 'i':
399				$s .= '%i';
400				break;
401
402			case 's':
403				$s .= '%s';
404				break;
405
406			case 'a':
407			case 'A':
408				$s .= '%p';
409				break;
410
411			case 'w':
412				$s .= '%w';
413				break;
414
415			case 'l':
416				$s .= '%W';
417				break;
418
419			default:
420
421				if ($ch == '\\') {
422					$i++;
423					$ch = substr($fmt,$i,1);
424				}
425				$s .= $ch;
426				break;
427			}
428		}
429		$s.="')";
430		if ($concat) $s = "CONCAT($s)";
431		return $s;
432	}
433
434	// returns concatenated string
435	// much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
436	function Concat()
437	{
438		$s = "";
439		$arr = func_get_args();
440
441		// suggestion by andrew005@mnogo.ru
442		$s = implode(',',$arr);
443		if (strlen($s) > 0) return "CONCAT($s)";
444		else return '';
445	}
446
447	// dayFraction is a day in floating point
448	function OffsetDate($dayFraction,$date=false)
449	{
450		if (!$date) $date = $this->sysDate;
451
452		$fraction = $dayFraction * 24 * 3600;
453		return $date . ' + INTERVAL ' .	 $fraction.' SECOND';
454
455//		return "from_unixtime(unix_timestamp($date)+$fraction)";
456	}
457
458	function &MetaTables($ttype=false,$showSchema=false,$mask=false)
459	{
460		$save = $this->metaTablesSQL;
461		if ($showSchema && is_string($showSchema)) {
462			$this->metaTablesSQL .= " from $showSchema";
463		}
464
465		if ($mask) {
466			$mask = $this->qstr($mask);
467			$this->metaTablesSQL .= " like $mask";
468		}
469		$ret =& ADOConnection::MetaTables($ttype,$showSchema);
470
471		$this->metaTablesSQL = $save;
472		return $ret;
473	}
474
475	// "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
476	function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
477	{
478	 global $ADODB_FETCH_MODE;
479
480		if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
481
482	    if ( !empty($owner) ) {
483	       $table = "$owner.$table";
484	    }
485	    $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
486		if ($associative) $create_sql = $a_create_table["Create Table"];
487	    else $create_sql  = $a_create_table[1];
488
489	    $matches = array();
490
491	    if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
492	 	$foreign_keys = array();
493	    $num_keys = count($matches[0]);
494	    for ( $i = 0;  $i < $num_keys;  $i ++ ) {
495	        $my_field  = explode('`, `', $matches[1][$i]);
496	        $ref_table = $matches[2][$i];
497	        $ref_field = explode('`, `', $matches[3][$i]);
498
499	        if ( $upper ) {
500	            $ref_table = strtoupper($ref_table);
501	        }
502
503	        $foreign_keys[$ref_table] = array();
504	        $num_fields               = count($my_field);
505	        for ( $j = 0;  $j < $num_fields;  $j ++ ) {
506	            if ( $associative ) {
507	                $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
508	            } else {
509	                $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
510	            }
511	        }
512	    }
513
514	    return  $foreign_keys;
515	}
516
517 	function &MetaColumns($table)
518	{
519		$false = false;
520		if (!$this->metaColumnsSQL)
521			return $false;
522
523		global $ADODB_FETCH_MODE;
524		$save = $ADODB_FETCH_MODE;
525		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
526		if ($this->fetchMode !== false)
527			$savem = $this->SetFetchMode(false);
528		$rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
529		if (isset($savem)) $this->SetFetchMode($savem);
530		$ADODB_FETCH_MODE = $save;
531		if (!is_object($rs))
532			return $false;
533
534		$retarr = array();
535		while (!$rs->EOF) {
536			$fld = new ADOFieldObject();
537			$fld->name = $rs->fields[0];
538			$type = $rs->fields[1];
539
540			// split type into type(length):
541			$fld->scale = null;
542			if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
543				$fld->type = $query_array[1];
544				$fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
545				$fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
546			} elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
547				$fld->type = $query_array[1];
548				$fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
549			} elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
550				$fld->type = $query_array[1];
551				$fld->max_length = max(array_map("strlen",explode(",",$query_array[2]))) - 2; // PHP >= 4.0.6
552				$fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length);
553			} else {
554				$fld->type = $type;
555				$fld->max_length = -1;
556			}
557			$fld->not_null = ($rs->fields[2] != 'YES');
558			$fld->primary_key = ($rs->fields[3] == 'PRI');
559			$fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
560			$fld->binary = (strpos($type,'blob') !== false);
561			$fld->unsigned = (strpos($type,'unsigned') !== false);
562
563			if (!$fld->binary) {
564				$d = $rs->fields[4];
565				if ($d != '' && $d != 'NULL') {
566					$fld->has_default = true;
567					$fld->default_value = $d;
568				} else {
569					$fld->has_default = false;
570				}
571			}
572
573			if ($save == ADODB_FETCH_NUM) {
574				$retarr[] = $fld;
575			} else {
576				$retarr[strtoupper($fld->name)] = $fld;
577			}
578			$rs->MoveNext();
579		}
580
581		$rs->Close();
582		return $retarr;
583	}
584
585	// returns true or false
586	function SelectDB($dbName)
587	{
588//	    $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
589	    $this->database = $dbName;
590		$this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
591
592	    if ($this->_connectionID) {
593        	$result = @mysqli_select_db($this->_connectionID, $dbName);
594			if (!$result) {
595		    	ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
596			}
597			return $result;
598		}
599	    return false;
600	}
601
602	// parameters use PostgreSQL convention, not MySQL
603	function &SelectLimit($sql,
604			      $nrows = -1,
605			      $offset = -1,
606			      $inputarr = false,
607			      $arg3 = false,
608			      $secs = 0)
609	{
610		$offsetStr = ($offset >= 0) ? "$offset," : '';
611		if ($nrows < 0) $nrows = '18446744073709551615';
612
613		if ($secs)
614			$rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3);
615		else
616			$rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3);
617
618		return $rs;
619	}
620
621
622	function Prepare($sql)
623	{
624		return $sql;
625
626		$stmt = $this->_connectionID->prepare($sql);
627		if (!$stmt) {
628			echo $this->ErrorMsg();
629			return $sql;
630		}
631		return array($sql,$stmt);
632	}
633
634
635	// returns queryID or false
636	function _query($sql, $inputarr)
637	{
638	global $ADODB_COUNTRECS;
639
640		if (is_array($sql)) {
641			$stmt = $sql[1];
642			$a = '';
643			foreach($inputarr as $k => $v) {
644				if (is_string($v)) $a .= 's';
645				else if (is_integer($v)) $a .= 'i';
646				else $a .= 'd';
647			}
648
649			$fnarr = array_merge( array($stmt,$a) , $inputarr);
650			$ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr);
651
652			$ret = mysqli_stmt_execute($stmt);
653			return $ret;
654		}
655		if (!$mysql_res =  mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
656		    if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
657		    return false;
658		}
659
660		return $mysql_res;
661	}
662
663	/*	Returns: the last error message from previous database operation	*/
664	function ErrorMsg()
665	  {
666	    if (empty($this->_connectionID))
667	      $this->_errorMsg = @mysqli_connect_error();
668	    else
669	      $this->_errorMsg = @mysqli_error($this->_connectionID);
670	    return $this->_errorMsg;
671	  }
672
673	/*	Returns: the last error number from previous database operation	*/
674	function ErrorNo()
675	  {
676	    if (empty($this->_connectionID))
677	      return @mysqli_connect_errno();
678	    else
679	      return @mysqli_errno($this->_connectionID);
680	  }
681
682	// returns true or false
683	function _close()
684	  {
685	    @mysqli_close($this->_connectionID);
686	    $this->_connectionID = false;
687	  }
688
689	/*
690	* Maximum size of C field
691	*/
692	function CharMax()
693	{
694		return 255;
695	}
696
697	/*
698	* Maximum size of X field
699	*/
700	function TextMax()
701	{
702	  return 4294967295;
703	}
704
705
706
707	// this is a set of functions for managing client encoding - very important if the encodings
708	// of your database and your output target (i.e. HTML) don't match
709	// for instance, you may have UTF8 database and server it on-site as latin1 etc.
710	// GetCharSet - get the name of the character set the client is using now
711	// Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
712	// depends on compile flags of mysql distribution
713
714  function GetCharSet()
715  {
716    //we will use ADO's builtin property charSet
717    if (!method_exists($this->_connectionID,'character_set_name'))
718    	return false;
719
720    $this->charSet = @$this->_connectionID->character_set_name();
721    if (!$this->charSet) {
722      return false;
723    } else {
724      return $this->charSet;
725    }
726  }
727
728  // SetCharSet - switch the client encoding
729  function SetCharSet($charset_name)
730  {
731    if (!method_exists($this->_connectionID,'set_charset'))
732    	return false;
733
734    if ($this->charSet !== $charset_name) {
735      $if = @$this->_connectionID->set_charset($charset_name);
736      if ($if == "0" & $this->GetCharSet() == $charset_name) {
737        return true;
738      } else return false;
739    } else return true;
740  }
741
742
743
744
745}
746
747/*--------------------------------------------------------------------------------------
748	 Class Name: Recordset
749--------------------------------------------------------------------------------------*/
750
751class ADORecordSet_mysqli extends ADORecordSet{
752
753	var $databaseType = "mysqli";
754	var $canSeek = true;
755
756	function ADORecordSet_mysqli($queryID, $mode = false)
757	{
758	  if ($mode === false)
759	   {
760	      global $ADODB_FETCH_MODE;
761	      $mode = $ADODB_FETCH_MODE;
762	   }
763
764	  switch ($mode)
765	    {
766	    case ADODB_FETCH_NUM:
767	      $this->fetchMode = MYSQLI_NUM;
768	      break;
769	    case ADODB_FETCH_ASSOC:
770	      $this->fetchMode = MYSQLI_ASSOC;
771	      break;
772	    case ADODB_FETCH_DEFAULT:
773	    case ADODB_FETCH_BOTH:
774	    default:
775	      $this->fetchMode = MYSQLI_BOTH;
776	      break;
777	    }
778	  $this->adodbFetchMode = $mode;
779	  $this->ADORecordSet($queryID);
780	}
781
782	function _initrs()
783	{
784	global $ADODB_COUNTRECS;
785
786		$this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
787		$this->_numOfFields = @mysqli_num_fields($this->_queryID);
788	}
789
790/*
7911      = MYSQLI_NOT_NULL_FLAG
7922      = MYSQLI_PRI_KEY_FLAG
7934      = MYSQLI_UNIQUE_KEY_FLAG
7948      = MYSQLI_MULTIPLE_KEY_FLAG
79516     = MYSQLI_BLOB_FLAG
79632     = MYSQLI_UNSIGNED_FLAG
79764     = MYSQLI_ZEROFILL_FLAG
798128    = MYSQLI_BINARY_FLAG
799256    = MYSQLI_ENUM_FLAG
800512    = MYSQLI_AUTO_INCREMENT_FLAG
8011024   = MYSQLI_TIMESTAMP_FLAG
8022048   = MYSQLI_SET_FLAG
80332768  = MYSQLI_NUM_FLAG
80416384  = MYSQLI_PART_KEY_FLAG
80532768  = MYSQLI_GROUP_FLAG
80665536  = MYSQLI_UNIQUE_FLAG
807131072 = MYSQLI_BINCMP_FLAG
808*/
809
810	function &FetchField($fieldOffset = -1)
811	{
812		$fieldnr = $fieldOffset;
813		if ($fieldOffset != -1) {
814		  $fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr);
815		}
816		$o = mysqli_fetch_field($this->_queryID);
817		/* Properties of an ADOFieldObject as set by MetaColumns */
818		$o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
819		$o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
820		$o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
821		$o->binary = $o->flags & MYSQLI_BINARY_FLAG;
822		// $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
823		$o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
824
825		return $o;
826	}
827
828	function &GetRowAssoc($upper = true)
829	{
830		if ($this->fetchMode == MYSQLI_ASSOC && !$upper)
831		  return $this->fields;
832		$row =& ADORecordSet::GetRowAssoc($upper);
833		return $row;
834	}
835
836	/* Use associative array to get fields array */
837	function Fields($colname)
838	{
839	  if ($this->fetchMode != MYSQLI_NUM)
840	    return @$this->fields[$colname];
841
842	  if (!$this->bind) {
843	    $this->bind = array();
844	    for ($i = 0; $i < $this->_numOfFields; $i++) {
845	      $o = $this->FetchField($i);
846	      $this->bind[strtoupper($o->name)] = $i;
847	    }
848	  }
849	  return $this->fields[$this->bind[strtoupper($colname)]];
850	}
851
852	function _seek($row)
853	{
854	  if ($this->_numOfRows == 0)
855	    return false;
856
857	  if ($row < 0)
858	    return false;
859
860	  mysqli_data_seek($this->_queryID, $row);
861	  $this->EOF = false;
862	  return true;
863	}
864
865	// 10% speedup to move MoveNext to child class
866	// This is the only implementation that works now (23-10-2003).
867	// Other functions return no or the wrong results.
868	function MoveNext()
869	{
870		if ($this->EOF) return false;
871		$this->_currentRow++;
872		$this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode);
873
874		if (is_array($this->fields)) return true;
875		$this->EOF = true;
876		return false;
877	}
878
879	function _fetch()
880	{
881		$this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode);
882	  	return is_array($this->fields);
883	}
884
885	function _close()
886	{
887		mysqli_free_result($this->_queryID);
888	  	$this->_queryID = false;
889	}
890
891/*
892
8930 = MYSQLI_TYPE_DECIMAL
8941 = MYSQLI_TYPE_CHAR
8951 = MYSQLI_TYPE_TINY
8962 = MYSQLI_TYPE_SHORT
8973 = MYSQLI_TYPE_LONG
8984 = MYSQLI_TYPE_FLOAT
8995 = MYSQLI_TYPE_DOUBLE
9006 = MYSQLI_TYPE_NULL
9017 = MYSQLI_TYPE_TIMESTAMP
9028 = MYSQLI_TYPE_LONGLONG
9039 = MYSQLI_TYPE_INT24
90410 = MYSQLI_TYPE_DATE
90511 = MYSQLI_TYPE_TIME
90612 = MYSQLI_TYPE_DATETIME
90713 = MYSQLI_TYPE_YEAR
90814 = MYSQLI_TYPE_NEWDATE
909247 = MYSQLI_TYPE_ENUM
910248 = MYSQLI_TYPE_SET
911249 = MYSQLI_TYPE_TINY_BLOB
912250 = MYSQLI_TYPE_MEDIUM_BLOB
913251 = MYSQLI_TYPE_LONG_BLOB
914252 = MYSQLI_TYPE_BLOB
915253 = MYSQLI_TYPE_VAR_STRING
916254 = MYSQLI_TYPE_STRING
917255 = MYSQLI_TYPE_GEOMETRY
918*/
919
920	function MetaType($t, $len = -1, $fieldobj = false)
921	{
922		if (is_object($t)) {
923		    $fieldobj = $t;
924		    $t = $fieldobj->type;
925		    $len = $fieldobj->max_length;
926		}
927
928
929		 $len = -1; // mysql max_length is not accurate
930		 switch (strtoupper($t)) {
931		 case 'STRING':
932		 case 'CHAR':
933		 case 'VARCHAR':
934		 case 'TINYBLOB':
935		 case 'TINYTEXT':
936		 case 'ENUM':
937		 case 'SET':
938
939		case MYSQLI_TYPE_TINY_BLOB :
940		case MYSQLI_TYPE_CHAR :
941		case MYSQLI_TYPE_STRING :
942		case MYSQLI_TYPE_ENUM :
943		case MYSQLI_TYPE_SET :
944		case 253 :
945		   if ($len <= $this->blobSize) return 'C';
946
947		case 'TEXT':
948		case 'LONGTEXT':
949		case 'MEDIUMTEXT':
950		   return 'X';
951
952
953		   // php_mysql extension always returns 'blob' even if 'text'
954		   // so we have to check whether binary...
955		case 'IMAGE':
956		case 'LONGBLOB':
957		case 'BLOB':
958		case 'MEDIUMBLOB':
959
960		case MYSQLI_TYPE_BLOB :
961		case MYSQLI_TYPE_LONG_BLOB :
962		case MYSQLI_TYPE_MEDIUM_BLOB :
963
964		   return !empty($fieldobj->binary) ? 'B' : 'X';
965		case 'YEAR':
966		case 'DATE':
967		case MYSQLI_TYPE_DATE :
968		case MYSQLI_TYPE_YEAR :
969
970		   return 'D';
971
972		case 'TIME':
973		case 'DATETIME':
974		case 'TIMESTAMP':
975
976		case MYSQLI_TYPE_DATETIME :
977		case MYSQLI_TYPE_NEWDATE :
978		case MYSQLI_TYPE_TIME :
979		case MYSQLI_TYPE_TIMESTAMP :
980
981			return 'T';
982
983		case 'INT':
984		case 'INTEGER':
985		case 'BIGINT':
986		case 'TINYINT':
987		case 'MEDIUMINT':
988		case 'SMALLINT':
989
990		case MYSQLI_TYPE_INT24 :
991		case MYSQLI_TYPE_LONG :
992		case MYSQLI_TYPE_LONGLONG :
993		case MYSQLI_TYPE_SHORT :
994		case MYSQLI_TYPE_TINY :
995
996		   if (!empty($fieldobj->primary_key)) return 'R';
997
998		   return 'I';
999
1000
1001		   // Added floating-point types
1002		   // Maybe not necessery.
1003		 case 'FLOAT':
1004		 case 'DOUBLE':
1005		   //		case 'DOUBLE PRECISION':
1006		 case 'DECIMAL':
1007		 case 'DEC':
1008		 case 'FIXED':
1009		 default:
1010		 	//if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
1011		 	return 'N';
1012		}
1013	} // function
1014
1015
1016} // rs class
1017
1018}
1019
1020?>