Update to upstream version 4.94
[Packages/TYPO3.CMS.git] / typo3 / sysext / adodb / adodb / drivers / adodb-mysqli.inc.php
1 <?php
2 /*
3 V4.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
12 21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
13 Based on adodb 3.40
14 */
15
16 // security - hide paths
17 if (!defined('ADODB_DIR')) die();
18
19 if (! defined("_ADODB_MYSQLI_LAYER")) {
20 define("_ADODB_MYSQLI_LAYER", 1 );
21
22 // PHP5 compat...
23 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128);
24 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1);
25
26 // disable adodb extension - currently incompatible.
27 global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
28
29 class ADODB_mysqli extends ADOConnection {
30 var $databaseType = 'mysqli';
31 var $dataProvider = '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
751 class 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 /*
791 1 = MYSQLI_NOT_NULL_FLAG
792 2 = MYSQLI_PRI_KEY_FLAG
793 4 = MYSQLI_UNIQUE_KEY_FLAG
794 8 = MYSQLI_MULTIPLE_KEY_FLAG
795 16 = MYSQLI_BLOB_FLAG
796 32 = MYSQLI_UNSIGNED_FLAG
797 64 = MYSQLI_ZEROFILL_FLAG
798 128 = MYSQLI_BINARY_FLAG
799 256 = MYSQLI_ENUM_FLAG
800 512 = MYSQLI_AUTO_INCREMENT_FLAG
801 1024 = MYSQLI_TIMESTAMP_FLAG
802 2048 = MYSQLI_SET_FLAG
803 32768 = MYSQLI_NUM_FLAG
804 16384 = MYSQLI_PART_KEY_FLAG
805 32768 = MYSQLI_GROUP_FLAG
806 65536 = MYSQLI_UNIQUE_FLAG
807 131072 = 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
893 0 = MYSQLI_TYPE_DECIMAL
894 1 = MYSQLI_TYPE_CHAR
895 1 = MYSQLI_TYPE_TINY
896 2 = MYSQLI_TYPE_SHORT
897 3 = MYSQLI_TYPE_LONG
898 4 = MYSQLI_TYPE_FLOAT
899 5 = MYSQLI_TYPE_DOUBLE
900 6 = MYSQLI_TYPE_NULL
901 7 = MYSQLI_TYPE_TIMESTAMP
902 8 = MYSQLI_TYPE_LONGLONG
903 9 = MYSQLI_TYPE_INT24
904 10 = MYSQLI_TYPE_DATE
905 11 = MYSQLI_TYPE_TIME
906 12 = MYSQLI_TYPE_DATETIME
907 13 = MYSQLI_TYPE_YEAR
908 14 = MYSQLI_TYPE_NEWDATE
909 247 = MYSQLI_TYPE_ENUM
910 248 = MYSQLI_TYPE_SET
911 249 = MYSQLI_TYPE_TINY_BLOB
912 250 = MYSQLI_TYPE_MEDIUM_BLOB
913 251 = MYSQLI_TYPE_LONG_BLOB
914 252 = MYSQLI_TYPE_BLOB
915 253 = MYSQLI_TYPE_VAR_STRING
916 254 = MYSQLI_TYPE_STRING
917 255 = 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 ?>