|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* 00003 V5.14 8 Sept 2011 (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved. 00004 Released under both BSD license and Lesser GPL library license. 00005 Whenever there is any discrepancy between the two licenses, 00006 the BSD license will take precedence. 00007 Set tabs to 8. 00008 00009 MySQL code that does not support transactions. Use mysqlt if you need transactions. 00010 Requires mysql client. Works on Windows and Unix. 00011 00012 21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl) 00013 Based on adodb 3.40 00014 */ 00015 00016 // security - hide paths 00017 if (!defined('ADODB_DIR')) die(); 00018 00019 if (! defined("_ADODB_MYSQLI_LAYER")) { 00020 define("_ADODB_MYSQLI_LAYER", 1 ); 00021 00022 // PHP5 compat... 00023 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128); 00024 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1); 00025 00026 // disable adodb extension - currently incompatible. 00027 global $ADODB_EXTENSION; $ADODB_EXTENSION = false; 00028 00029 class ADODB_mysqli extends ADOConnection { 00030 var $databaseType = 'mysqli'; 00031 var $dataProvider = 'native'; 00032 var $hasInsertID = true; 00033 var $hasAffectedRows = true; 00034 var $metaTablesSQL = "SHOW TABLES"; 00035 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; 00036 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 00037 var $hasLimit = true; 00038 var $hasMoveFirst = true; 00039 var $hasGenID = true; 00040 var $isoDates = true; // accepts dates in ISO format 00041 var $sysDate = 'CURDATE()'; 00042 var $sysTimeStamp = 'NOW()'; 00043 var $hasTransactions = true; 00044 var $forceNewConnect = false; 00045 var $poorAffectedRows = true; 00046 var $clientFlags = 0; 00047 var $substr = "substring"; 00048 var $port = false; 00049 var $socket = false; 00050 var $_bindInputArray = false; 00051 var $nameQuote = '`'; 00052 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0)); 00053 var $arrayClass = 'ADORecordSet_array_mysqli'; 00054 var $multiQuery = false; 00055 00056 function ADODB_mysqli() 00057 { 00058 // if(!extension_loaded("mysqli")) 00059 ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR); 00060 00061 } 00062 00063 function SetTransactionMode( $transaction_mode ) 00064 { 00065 $this->_transmode = $transaction_mode; 00066 if (empty($transaction_mode)) { 00067 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); 00068 return; 00069 } 00070 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 00071 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); 00072 } 00073 00074 // returns true or false 00075 // To add: parameter int $port, 00076 // parameter string $socket 00077 function _connect($argHostname = NULL, 00078 $argUsername = NULL, 00079 $argPassword = NULL, 00080 $argDatabasename = NULL, $persist=false) 00081 { 00082 if(!extension_loaded("mysqli")) { 00083 return null; 00084 } 00085 $this->_connectionID = @mysqli_init(); 00086 00087 if (is_null($this->_connectionID)) { 00088 // mysqli_init only fails if insufficient memory 00089 if ($this->debug) 00090 ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg()); 00091 return false; 00092 } 00093 /* 00094 I suggest a simple fix which would enable adodb and mysqli driver to 00095 read connection options from the standard mysql configuration file 00096 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com> 00097 */ 00098 foreach($this->optionFlags as $arr) { 00099 mysqli_options($this->_connectionID,$arr[0],$arr[1]); 00100 } 00101 00102 //http ://php.net/manual/en/mysqli.persistconns.php 00103 if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname,'p:',2) != 0) $argHostname = 'p:'.$argHostname; 00104 00105 #if (!empty($this->port)) $argHostname .= ":".$this->port; 00106 $ok = mysqli_real_connect($this->_connectionID, 00107 $argHostname, 00108 $argUsername, 00109 $argPassword, 00110 $argDatabasename, 00111 $this->port, 00112 $this->socket, 00113 $this->clientFlags); 00114 00115 if ($ok) { 00116 if ($argDatabasename) return $this->SelectDB($argDatabasename); 00117 return true; 00118 } else { 00119 if ($this->debug) 00120 ADOConnection::outp("Could't connect : " . $this->ErrorMsg()); 00121 $this->_connectionID = null; 00122 return false; 00123 } 00124 } 00125 00126 // returns true or false 00127 // How to force a persistent connection 00128 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 00129 { 00130 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true); 00131 00132 } 00133 00134 // When is this used? Close old connection first? 00135 // In _connect(), check $this->forceNewConnect? 00136 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 00137 { 00138 $this->forceNewConnect = true; 00139 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); 00140 } 00141 00142 function IfNull( $field, $ifNull ) 00143 { 00144 return " IFNULL($field, $ifNull) "; // if MySQL 00145 } 00146 00147 // do not use $ADODB_COUNTRECS 00148 function GetOne($sql,$inputarr=false) 00149 { 00150 global $ADODB_GETONE_EOF; 00151 00152 $ret = false; 00153 $rs = $this->Execute($sql,$inputarr); 00154 if ($rs) { 00155 if ($rs->EOF) $ret = $ADODB_GETONE_EOF; 00156 else $ret = reset($rs->fields); 00157 $rs->Close(); 00158 } 00159 return $ret; 00160 } 00161 00162 function ServerInfo() 00163 { 00164 $arr['description'] = $this->GetOne("select version()"); 00165 $arr['version'] = ADOConnection::_findvers($arr['description']); 00166 return $arr; 00167 } 00168 00169 00170 function BeginTrans() 00171 { 00172 if ($this->transOff) return true; 00173 $this->transCnt += 1; 00174 00175 //$this->Execute('SET AUTOCOMMIT=0'); 00176 mysqli_autocommit($this->_connectionID, false); 00177 $this->Execute('BEGIN'); 00178 return true; 00179 } 00180 00181 function CommitTrans($ok=true) 00182 { 00183 if ($this->transOff) return true; 00184 if (!$ok) return $this->RollbackTrans(); 00185 00186 if ($this->transCnt) $this->transCnt -= 1; 00187 $this->Execute('COMMIT'); 00188 00189 //$this->Execute('SET AUTOCOMMIT=1'); 00190 mysqli_autocommit($this->_connectionID, true); 00191 return true; 00192 } 00193 00194 function RollbackTrans() 00195 { 00196 if ($this->transOff) return true; 00197 if ($this->transCnt) $this->transCnt -= 1; 00198 $this->Execute('ROLLBACK'); 00199 //$this->Execute('SET AUTOCOMMIT=1'); 00200 mysqli_autocommit($this->_connectionID, true); 00201 return true; 00202 } 00203 00204 function RowLock($tables,$where='',$col='1 as adodbignore') 00205 { 00206 if ($this->transCnt==0) $this->BeginTrans(); 00207 if ($where) $where = ' where '.$where; 00208 $rs = $this->Execute("select $col from $tables $where for update"); 00209 return !empty($rs); 00210 } 00211 00212 // if magic quotes disabled, use mysql_real_escape_string() 00213 // From readme.htm: 00214 // Quotes a string to be sent to the database. The $magic_quotes_enabled 00215 // parameter may look funny, but the idea is if you are quoting a 00216 // string extracted from a POST/GET variable, then 00217 // pass get_magic_quotes_gpc() as the second parameter. This will 00218 // ensure that the variable is not quoted twice, once by qstr and once 00219 // by the magic_quotes_gpc. 00220 // 00221 //Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc()); 00222 function qstr($s, $magic_quotes = false) 00223 { 00224 if (is_null($s)) return 'NULL'; 00225 if (!$magic_quotes) { 00226 if (PHP_VERSION >= 5) 00227 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; 00228 00229 if ($this->replaceQuote[0] == '\\') 00230 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 00231 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 00232 } 00233 // undo magic quotes for " 00234 $s = str_replace('\\"','"',$s); 00235 return "'$s'"; 00236 } 00237 00238 function _insertid() 00239 { 00240 $result = @mysqli_insert_id($this->_connectionID); 00241 if ($result == -1){ 00242 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg()); 00243 } 00244 return $result; 00245 } 00246 00247 // Only works for INSERT, UPDATE and DELETE query's 00248 function _affectedrows() 00249 { 00250 $result = @mysqli_affected_rows($this->_connectionID); 00251 if ($result == -1) { 00252 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg()); 00253 } 00254 return $result; 00255 } 00256 00257 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html 00258 // Reference on Last_Insert_ID on the recommended way to simulate sequences 00259 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; 00260 var $_genSeqSQL = "create table %s (id int not null)"; 00261 var $_genSeqCountSQL = "select count(*) from %s"; 00262 var $_genSeq2SQL = "insert into %s values (%s)"; 00263 var $_dropSeqSQL = "drop table %s"; 00264 00265 function CreateSequence($seqname='adodbseq',$startID=1) 00266 { 00267 if (empty($this->_genSeqSQL)) return false; 00268 $u = strtoupper($seqname); 00269 00270 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 00271 if (!$ok) return false; 00272 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 00273 } 00274 00275 function GenID($seqname='adodbseq',$startID=1) 00276 { 00277 // post-nuke sets hasGenID to false 00278 if (!$this->hasGenID) return false; 00279 00280 $getnext = sprintf($this->_genIDSQL,$seqname); 00281 $holdtransOK = $this->_transOK; // save the current status 00282 $rs = @$this->Execute($getnext); 00283 if (!$rs) { 00284 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset 00285 $u = strtoupper($seqname); 00286 $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 00287 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname)); 00288 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 00289 $rs = $this->Execute($getnext); 00290 } 00291 00292 if ($rs) { 00293 $this->genID = mysqli_insert_id($this->_connectionID); 00294 $rs->Close(); 00295 } else 00296 $this->genID = 0; 00297 00298 return $this->genID; 00299 } 00300 00301 function MetaDatabases() 00302 { 00303 $query = "SHOW DATABASES"; 00304 $ret = $this->Execute($query); 00305 if ($ret && is_object($ret)){ 00306 $arr = array(); 00307 while (!$ret->EOF){ 00308 $db = $ret->Fields('Database'); 00309 if ($db != 'mysql') $arr[] = $db; 00310 $ret->MoveNext(); 00311 } 00312 return $arr; 00313 } 00314 return $ret; 00315 } 00316 00317 00318 function MetaIndexes ($table, $primary = FALSE, $owner = false) 00319 { 00320 // save old fetch mode 00321 global $ADODB_FETCH_MODE; 00322 00323 $false = false; 00324 $save = $ADODB_FETCH_MODE; 00325 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00326 if ($this->fetchMode !== FALSE) { 00327 $savem = $this->SetFetchMode(FALSE); 00328 } 00329 00330 // get index details 00331 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); 00332 00333 // restore fetchmode 00334 if (isset($savem)) { 00335 $this->SetFetchMode($savem); 00336 } 00337 $ADODB_FETCH_MODE = $save; 00338 00339 if (!is_object($rs)) { 00340 return $false; 00341 } 00342 00343 $indexes = array (); 00344 00345 // parse index data into array 00346 while ($row = $rs->FetchRow()) { 00347 if ($primary == FALSE AND $row[2] == 'PRIMARY') { 00348 continue; 00349 } 00350 00351 if (!isset($indexes[$row[2]])) { 00352 $indexes[$row[2]] = array( 00353 'unique' => ($row[1] == 0), 00354 'columns' => array() 00355 ); 00356 } 00357 00358 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; 00359 } 00360 00361 // sort columns by order in the index 00362 foreach ( array_keys ($indexes) as $index ) 00363 { 00364 ksort ($indexes[$index]['columns']); 00365 } 00366 00367 return $indexes; 00368 } 00369 00370 00371 // Format date column in sql string given an input format that understands Y M D 00372 function SQLDate($fmt, $col=false) 00373 { 00374 if (!$col) $col = $this->sysTimeStamp; 00375 $s = 'DATE_FORMAT('.$col.",'"; 00376 $concat = false; 00377 $len = strlen($fmt); 00378 for ($i=0; $i < $len; $i++) { 00379 $ch = $fmt[$i]; 00380 switch($ch) { 00381 case 'Y': 00382 case 'y': 00383 $s .= '%Y'; 00384 break; 00385 case 'Q': 00386 case 'q': 00387 $s .= "'),Quarter($col)"; 00388 00389 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; 00390 else $s .= ",('"; 00391 $concat = true; 00392 break; 00393 case 'M': 00394 $s .= '%b'; 00395 break; 00396 00397 case 'm': 00398 $s .= '%m'; 00399 break; 00400 case 'D': 00401 case 'd': 00402 $s .= '%d'; 00403 break; 00404 00405 case 'H': 00406 $s .= '%H'; 00407 break; 00408 00409 case 'h': 00410 $s .= '%I'; 00411 break; 00412 00413 case 'i': 00414 $s .= '%i'; 00415 break; 00416 00417 case 's': 00418 $s .= '%s'; 00419 break; 00420 00421 case 'a': 00422 case 'A': 00423 $s .= '%p'; 00424 break; 00425 00426 case 'w': 00427 $s .= '%w'; 00428 break; 00429 00430 case 'l': 00431 $s .= '%W'; 00432 break; 00433 00434 default: 00435 00436 if ($ch == '\\') { 00437 $i++; 00438 $ch = substr($fmt,$i,1); 00439 } 00440 $s .= $ch; 00441 break; 00442 } 00443 } 00444 $s.="')"; 00445 if ($concat) $s = "CONCAT($s)"; 00446 return $s; 00447 } 00448 00449 // returns concatenated string 00450 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator 00451 function Concat() 00452 { 00453 $s = ""; 00454 $arr = func_get_args(); 00455 00456 // suggestion by andrew005@mnogo.ru 00457 $s = implode(',',$arr); 00458 if (strlen($s) > 0) return "CONCAT($s)"; 00459 else return ''; 00460 } 00461 00462 // dayFraction is a day in floating point 00463 function OffsetDate($dayFraction,$date=false) 00464 { 00465 if (!$date) $date = $this->sysDate; 00466 00467 $fraction = $dayFraction * 24 * 3600; 00468 return $date . ' + INTERVAL ' . $fraction.' SECOND'; 00469 00470 // return "from_unixtime(unix_timestamp($date)+$fraction)"; 00471 } 00472 00473 function MetaTables($ttype=false,$showSchema=false,$mask=false) 00474 { 00475 $save = $this->metaTablesSQL; 00476 if ($showSchema && is_string($showSchema)) { 00477 $this->metaTablesSQL .= " from $showSchema"; 00478 } 00479 00480 if ($mask) { 00481 $mask = $this->qstr($mask); 00482 $this->metaTablesSQL .= " like $mask"; 00483 } 00484 $ret = ADOConnection::MetaTables($ttype,$showSchema); 00485 00486 $this->metaTablesSQL = $save; 00487 return $ret; 00488 } 00489 00490 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> 00491 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) 00492 { 00493 global $ADODB_FETCH_MODE; 00494 00495 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; 00496 00497 if ( !empty($owner) ) { 00498 $table = "$owner.$table"; 00499 } 00500 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); 00501 if ($associative) { 00502 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"]; 00503 } else $create_sql = $a_create_table[1]; 00504 00505 $matches = array(); 00506 00507 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; 00508 $foreign_keys = array(); 00509 $num_keys = count($matches[0]); 00510 for ( $i = 0; $i < $num_keys; $i ++ ) { 00511 $my_field = explode('`, `', $matches[1][$i]); 00512 $ref_table = $matches[2][$i]; 00513 $ref_field = explode('`, `', $matches[3][$i]); 00514 00515 if ( $upper ) { 00516 $ref_table = strtoupper($ref_table); 00517 } 00518 00519 // see https://sourceforge.net/tracker/index.php?func=detail&aid=2287278&group_id=42718&atid=433976 00520 if (!isset($foreign_keys[$ref_table])) { 00521 $foreign_keys[$ref_table] = array(); 00522 } 00523 $num_fields = count($my_field); 00524 for ( $j = 0; $j < $num_fields; $j ++ ) { 00525 if ( $associative ) { 00526 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; 00527 } else { 00528 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; 00529 } 00530 } 00531 } 00532 00533 return $foreign_keys; 00534 } 00535 00536 function MetaColumns($table, $normalize=true) 00537 { 00538 $false = false; 00539 if (!$this->metaColumnsSQL) 00540 return $false; 00541 00542 global $ADODB_FETCH_MODE; 00543 $save = $ADODB_FETCH_MODE; 00544 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00545 if ($this->fetchMode !== false) 00546 $savem = $this->SetFetchMode(false); 00547 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 00548 if (isset($savem)) $this->SetFetchMode($savem); 00549 $ADODB_FETCH_MODE = $save; 00550 if (!is_object($rs)) 00551 return $false; 00552 00553 $retarr = array(); 00554 while (!$rs->EOF) { 00555 $fld = new ADOFieldObject(); 00556 $fld->name = $rs->fields[0]; 00557 $type = $rs->fields[1]; 00558 00559 // split type into type(length): 00560 $fld->scale = null; 00561 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { 00562 $fld->type = $query_array[1]; 00563 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 00564 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; 00565 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { 00566 $fld->type = $query_array[1]; 00567 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 00568 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { 00569 $fld->type = $query_array[1]; 00570 $arr = explode(",",$query_array[2]); 00571 $fld->enums = $arr; 00572 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 00573 $fld->max_length = ($zlen > 0) ? $zlen : 1; 00574 } else { 00575 $fld->type = $type; 00576 $fld->max_length = -1; 00577 } 00578 $fld->not_null = ($rs->fields[2] != 'YES'); 00579 $fld->primary_key = ($rs->fields[3] == 'PRI'); 00580 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); 00581 $fld->binary = (strpos($type,'blob') !== false); 00582 $fld->unsigned = (strpos($type,'unsigned') !== false); 00583 $fld->zerofill = (strpos($type,'zerofill') !== false); 00584 00585 if (!$fld->binary) { 00586 $d = $rs->fields[4]; 00587 if ($d != '' && $d != 'NULL') { 00588 $fld->has_default = true; 00589 $fld->default_value = $d; 00590 } else { 00591 $fld->has_default = false; 00592 } 00593 } 00594 00595 if ($save == ADODB_FETCH_NUM) { 00596 $retarr[] = $fld; 00597 } else { 00598 $retarr[strtoupper($fld->name)] = $fld; 00599 } 00600 $rs->MoveNext(); 00601 } 00602 00603 $rs->Close(); 00604 return $retarr; 00605 } 00606 00607 // returns true or false 00608 function SelectDB($dbName) 00609 { 00610 // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); 00611 $this->database = $dbName; 00612 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 00613 00614 if ($this->_connectionID) { 00615 $result = @mysqli_select_db($this->_connectionID, $dbName); 00616 if (!$result) { 00617 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); 00618 } 00619 return $result; 00620 } 00621 return false; 00622 } 00623 00624 // parameters use PostgreSQL convention, not MySQL 00625 function SelectLimit($sql, 00626 $nrows = -1, 00627 $offset = -1, 00628 $inputarr = false, 00629 $secs = 0) 00630 { 00631 $offsetStr = ($offset >= 0) ? "$offset," : ''; 00632 if ($nrows < 0) $nrows = '18446744073709551615'; 00633 00634 if ($secs) 00635 $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr ); 00636 else 00637 $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr ); 00638 00639 return $rs; 00640 } 00641 00642 00643 function Prepare($sql) 00644 { 00645 return $sql; 00646 $stmt = $this->_connectionID->prepare($sql); 00647 if (!$stmt) { 00648 echo $this->ErrorMsg(); 00649 return $sql; 00650 } 00651 return array($sql,$stmt); 00652 } 00653 00654 00655 // returns queryID or false 00656 function _query($sql, $inputarr) 00657 { 00658 global $ADODB_COUNTRECS; 00659 // Move to the next recordset, or return false if there is none. In a stored proc 00660 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 00661 // returns false. I think this is because the last "recordset" is actually just the 00662 // return value of the stored proc (ie the number of rows affected). 00663 // Commented out for reasons of performance. You should retrieve every recordset yourself. 00664 // if (!mysqli_next_result($this->connection->_connectionID)) return false; 00665 00666 if (is_array($sql)) { 00667 00668 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but 00669 // returns as bound variables. 00670 00671 $stmt = $sql[1]; 00672 $a = ''; 00673 foreach($inputarr as $k => $v) { 00674 if (is_string($v)) $a .= 's'; 00675 else if (is_integer($v)) $a .= 'i'; 00676 else $a .= 'd'; 00677 } 00678 00679 $fnarr = array_merge( array($stmt,$a) , $inputarr); 00680 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr); 00681 $ret = mysqli_stmt_execute($stmt); 00682 return $ret; 00683 } 00684 00685 /* 00686 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { 00687 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 00688 return false; 00689 } 00690 00691 return $mysql_res; 00692 */ 00693 00694 if ($this->multiQuery) { 00695 $rs = mysqli_multi_query($this->_connectionID, $sql.';'); 00696 if ($rs) { 00697 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID ); 00698 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID ) 00699 } 00700 } else { 00701 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); 00702 00703 if ($rs) return $rs; 00704 } 00705 00706 if($this->debug) 00707 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 00708 00709 return false; 00710 00711 } 00712 00713 /* Returns: the last error message from previous database operation */ 00714 function ErrorMsg() 00715 { 00716 if (empty($this->_connectionID)) 00717 $this->_errorMsg = @mysqli_connect_error(); 00718 else 00719 $this->_errorMsg = @mysqli_error($this->_connectionID); 00720 return $this->_errorMsg; 00721 } 00722 00723 /* Returns: the last error number from previous database operation */ 00724 function ErrorNo() 00725 { 00726 if (empty($this->_connectionID)) 00727 return @mysqli_connect_errno(); 00728 else 00729 return @mysqli_errno($this->_connectionID); 00730 } 00731 00732 // returns true or false 00733 function _close() 00734 { 00735 @mysqli_close($this->_connectionID); 00736 $this->_connectionID = false; 00737 } 00738 00739 /* 00740 * Maximum size of C field 00741 */ 00742 function CharMax() 00743 { 00744 return 255; 00745 } 00746 00747 /* 00748 * Maximum size of X field 00749 */ 00750 function TextMax() 00751 { 00752 return 4294967295; 00753 } 00754 00755 00756 00757 // this is a set of functions for managing client encoding - very important if the encodings 00758 // of your database and your output target (i.e. HTML) don't match 00759 // for instance, you may have UTF8 database and server it on-site as latin1 etc. 00760 // GetCharSet - get the name of the character set the client is using now 00761 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported 00762 // depends on compile flags of mysql distribution 00763 00764 function GetCharSet() 00765 { 00766 //we will use ADO's builtin property charSet 00767 if (!method_exists($this->_connectionID,'character_set_name')) 00768 return false; 00769 00770 $this->charSet = @$this->_connectionID->character_set_name(); 00771 if (!$this->charSet) { 00772 return false; 00773 } else { 00774 return $this->charSet; 00775 } 00776 } 00777 00778 // SetCharSet - switch the client encoding 00779 function SetCharSet($charset_name) 00780 { 00781 if (!method_exists($this->_connectionID,'set_charset')) 00782 return false; 00783 00784 if ($this->charSet !== $charset_name) { 00785 $if = @$this->_connectionID->set_charset($charset_name); 00786 if ($if == "0" & $this->GetCharSet() == $charset_name) { 00787 return true; 00788 } else return false; 00789 } else return true; 00790 } 00791 00792 00793 00794 00795 } 00796 00797 /*-------------------------------------------------------------------------------------- 00798 Class Name: Recordset 00799 --------------------------------------------------------------------------------------*/ 00800 00801 class ADORecordSet_mysqli extends ADORecordSet{ 00802 00803 var $databaseType = "mysqli"; 00804 var $canSeek = true; 00805 00806 function ADORecordSet_mysqli($queryID, $mode = false) 00807 { 00808 if ($mode === false) 00809 { 00810 global $ADODB_FETCH_MODE; 00811 $mode = $ADODB_FETCH_MODE; 00812 } 00813 00814 switch ($mode) 00815 { 00816 case ADODB_FETCH_NUM: 00817 $this->fetchMode = MYSQLI_NUM; 00818 break; 00819 case ADODB_FETCH_ASSOC: 00820 $this->fetchMode = MYSQLI_ASSOC; 00821 break; 00822 case ADODB_FETCH_DEFAULT: 00823 case ADODB_FETCH_BOTH: 00824 default: 00825 $this->fetchMode = MYSQLI_BOTH; 00826 break; 00827 } 00828 $this->adodbFetchMode = $mode; 00829 $this->ADORecordSet($queryID); 00830 } 00831 00832 function _initrs() 00833 { 00834 global $ADODB_COUNTRECS; 00835 00836 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; 00837 $this->_numOfFields = @mysqli_num_fields($this->_queryID); 00838 } 00839 00840 /* 00841 1 = MYSQLI_NOT_NULL_FLAG 00842 2 = MYSQLI_PRI_KEY_FLAG 00843 4 = MYSQLI_UNIQUE_KEY_FLAG 00844 8 = MYSQLI_MULTIPLE_KEY_FLAG 00845 16 = MYSQLI_BLOB_FLAG 00846 32 = MYSQLI_UNSIGNED_FLAG 00847 64 = MYSQLI_ZEROFILL_FLAG 00848 128 = MYSQLI_BINARY_FLAG 00849 256 = MYSQLI_ENUM_FLAG 00850 512 = MYSQLI_AUTO_INCREMENT_FLAG 00851 1024 = MYSQLI_TIMESTAMP_FLAG 00852 2048 = MYSQLI_SET_FLAG 00853 32768 = MYSQLI_NUM_FLAG 00854 16384 = MYSQLI_PART_KEY_FLAG 00855 32768 = MYSQLI_GROUP_FLAG 00856 65536 = MYSQLI_UNIQUE_FLAG 00857 131072 = MYSQLI_BINCMP_FLAG 00858 */ 00859 00860 function FetchField($fieldOffset = -1) 00861 { 00862 $fieldnr = $fieldOffset; 00863 if ($fieldOffset != -1) { 00864 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr); 00865 } 00866 $o = @mysqli_fetch_field($this->_queryID); 00867 if (!$o) return false; 00868 /* Properties of an ADOFieldObject as set by MetaColumns */ 00869 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; 00870 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; 00871 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; 00872 $o->binary = $o->flags & MYSQLI_BINARY_FLAG; 00873 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ 00874 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; 00875 00876 return $o; 00877 } 00878 00879 function GetRowAssoc($upper = true) 00880 { 00881 if ($this->fetchMode == MYSQLI_ASSOC && !$upper) 00882 return $this->fields; 00883 $row = ADORecordSet::GetRowAssoc($upper); 00884 return $row; 00885 } 00886 00887 /* Use associative array to get fields array */ 00888 function Fields($colname) 00889 { 00890 if ($this->fetchMode != MYSQLI_NUM) 00891 return @$this->fields[$colname]; 00892 00893 if (!$this->bind) { 00894 $this->bind = array(); 00895 for ($i = 0; $i < $this->_numOfFields; $i++) { 00896 $o = $this->FetchField($i); 00897 $this->bind[strtoupper($o->name)] = $i; 00898 } 00899 } 00900 return $this->fields[$this->bind[strtoupper($colname)]]; 00901 } 00902 00903 function _seek($row) 00904 { 00905 if ($this->_numOfRows == 0) 00906 return false; 00907 00908 if ($row < 0) 00909 return false; 00910 00911 mysqli_data_seek($this->_queryID, $row); 00912 $this->EOF = false; 00913 return true; 00914 } 00915 00916 00917 function NextRecordSet() 00918 { 00919 global $ADODB_COUNTRECS; 00920 00921 mysqli_free_result($this->_queryID); 00922 $this->_queryID = -1; 00923 // Move to the next recordset, or return false if there is none. In a stored proc 00924 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 00925 // returns false. I think this is because the last "recordset" is actually just the 00926 // return value of the stored proc (ie the number of rows affected). 00927 if(!mysqli_next_result($this->connection->_connectionID)) { 00928 return false; 00929 } 00930 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using 00931 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID ) 00932 : @mysqli_use_result( $this->connection->_connectionID ); 00933 if(!$this->_queryID) { 00934 return false; 00935 } 00936 $this->_inited = false; 00937 $this->bind = false; 00938 $this->_currentRow = -1; 00939 $this->Init(); 00940 return true; 00941 } 00942 00943 // 10% speedup to move MoveNext to child class 00944 // This is the only implementation that works now (23-10-2003). 00945 // Other functions return no or the wrong results. 00946 function MoveNext() 00947 { 00948 if ($this->EOF) return false; 00949 $this->_currentRow++; 00950 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); 00951 00952 if (is_array($this->fields)) return true; 00953 $this->EOF = true; 00954 return false; 00955 } 00956 00957 function _fetch() 00958 { 00959 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); 00960 return is_array($this->fields); 00961 } 00962 00963 function _close() 00964 { 00965 //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014 00966 //only a problem with persistant connections 00967 00968 //mysqli_next_result($this->connection->_connectionID); trashes the DB side attached results. 00969 00970 while(mysqli_more_results($this->connection->_connectionID)){ 00971 @mysqli_next_result($this->connection->_connectionID); 00972 } 00973 00974 //Because you can have one attached result, without tripping mysqli_more_results 00975 @mysqli_next_result($this->connection->_connectionID); 00976 00977 00978 mysqli_free_result($this->_queryID); 00979 $this->_queryID = false; 00980 } 00981 00982 /* 00983 00984 0 = MYSQLI_TYPE_DECIMAL 00985 1 = MYSQLI_TYPE_CHAR 00986 1 = MYSQLI_TYPE_TINY 00987 2 = MYSQLI_TYPE_SHORT 00988 3 = MYSQLI_TYPE_LONG 00989 4 = MYSQLI_TYPE_FLOAT 00990 5 = MYSQLI_TYPE_DOUBLE 00991 6 = MYSQLI_TYPE_NULL 00992 7 = MYSQLI_TYPE_TIMESTAMP 00993 8 = MYSQLI_TYPE_LONGLONG 00994 9 = MYSQLI_TYPE_INT24 00995 10 = MYSQLI_TYPE_DATE 00996 11 = MYSQLI_TYPE_TIME 00997 12 = MYSQLI_TYPE_DATETIME 00998 13 = MYSQLI_TYPE_YEAR 00999 14 = MYSQLI_TYPE_NEWDATE 01000 247 = MYSQLI_TYPE_ENUM 01001 248 = MYSQLI_TYPE_SET 01002 249 = MYSQLI_TYPE_TINY_BLOB 01003 250 = MYSQLI_TYPE_MEDIUM_BLOB 01004 251 = MYSQLI_TYPE_LONG_BLOB 01005 252 = MYSQLI_TYPE_BLOB 01006 253 = MYSQLI_TYPE_VAR_STRING 01007 254 = MYSQLI_TYPE_STRING 01008 255 = MYSQLI_TYPE_GEOMETRY 01009 */ 01010 01011 function MetaType($t, $len = -1, $fieldobj = false) 01012 { 01013 if (is_object($t)) { 01014 $fieldobj = $t; 01015 $t = $fieldobj->type; 01016 $len = $fieldobj->max_length; 01017 } 01018 01019 01020 $len = -1; // mysql max_length is not accurate 01021 switch (strtoupper($t)) { 01022 case 'STRING': 01023 case 'CHAR': 01024 case 'VARCHAR': 01025 case 'TINYBLOB': 01026 case 'TINYTEXT': 01027 case 'ENUM': 01028 case 'SET': 01029 01030 case MYSQLI_TYPE_TINY_BLOB : 01031 #case MYSQLI_TYPE_CHAR : 01032 case MYSQLI_TYPE_STRING : 01033 case MYSQLI_TYPE_ENUM : 01034 case MYSQLI_TYPE_SET : 01035 case 253 : 01036 if ($len <= $this->blobSize) return 'C'; 01037 01038 case 'TEXT': 01039 case 'LONGTEXT': 01040 case 'MEDIUMTEXT': 01041 return 'X'; 01042 01043 01044 // php_mysql extension always returns 'blob' even if 'text' 01045 // so we have to check whether binary... 01046 case 'IMAGE': 01047 case 'LONGBLOB': 01048 case 'BLOB': 01049 case 'MEDIUMBLOB': 01050 01051 case MYSQLI_TYPE_BLOB : 01052 case MYSQLI_TYPE_LONG_BLOB : 01053 case MYSQLI_TYPE_MEDIUM_BLOB : 01054 01055 return !empty($fieldobj->binary) ? 'B' : 'X'; 01056 case 'YEAR': 01057 case 'DATE': 01058 case MYSQLI_TYPE_DATE : 01059 case MYSQLI_TYPE_YEAR : 01060 01061 return 'D'; 01062 01063 case 'TIME': 01064 case 'DATETIME': 01065 case 'TIMESTAMP': 01066 01067 case MYSQLI_TYPE_DATETIME : 01068 case MYSQLI_TYPE_NEWDATE : 01069 case MYSQLI_TYPE_TIME : 01070 case MYSQLI_TYPE_TIMESTAMP : 01071 01072 return 'T'; 01073 01074 case 'INT': 01075 case 'INTEGER': 01076 case 'BIGINT': 01077 case 'TINYINT': 01078 case 'MEDIUMINT': 01079 case 'SMALLINT': 01080 01081 case MYSQLI_TYPE_INT24 : 01082 case MYSQLI_TYPE_LONG : 01083 case MYSQLI_TYPE_LONGLONG : 01084 case MYSQLI_TYPE_SHORT : 01085 case MYSQLI_TYPE_TINY : 01086 01087 if (!empty($fieldobj->primary_key)) return 'R'; 01088 01089 return 'I'; 01090 01091 01092 // Added floating-point types 01093 // Maybe not necessery. 01094 case 'FLOAT': 01095 case 'DOUBLE': 01096 // case 'DOUBLE PRECISION': 01097 case 'DECIMAL': 01098 case 'DEC': 01099 case 'FIXED': 01100 default: 01101 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 01102 return 'N'; 01103 } 01104 } // function 01105 01106 01107 } // rs class 01108 01109 } 01110 01111 class ADORecordSet_array_mysqli extends ADORecordSet_array { 01112 01113 function ADORecordSet_array_mysqli($id=-1,$mode=false) 01114 { 01115 $this->ADORecordSet_array($id,$mode); 01116 } 01117 01118 function MetaType($t, $len = -1, $fieldobj = false) 01119 { 01120 if (is_object($t)) { 01121 $fieldobj = $t; 01122 $t = $fieldobj->type; 01123 $len = $fieldobj->max_length; 01124 } 01125 01126 01127 $len = -1; // mysql max_length is not accurate 01128 switch (strtoupper($t)) { 01129 case 'STRING': 01130 case 'CHAR': 01131 case 'VARCHAR': 01132 case 'TINYBLOB': 01133 case 'TINYTEXT': 01134 case 'ENUM': 01135 case 'SET': 01136 01137 case MYSQLI_TYPE_TINY_BLOB : 01138 #case MYSQLI_TYPE_CHAR : 01139 case MYSQLI_TYPE_STRING : 01140 case MYSQLI_TYPE_ENUM : 01141 case MYSQLI_TYPE_SET : 01142 case 253 : 01143 if ($len <= $this->blobSize) return 'C'; 01144 01145 case 'TEXT': 01146 case 'LONGTEXT': 01147 case 'MEDIUMTEXT': 01148 return 'X'; 01149 01150 01151 // php_mysql extension always returns 'blob' even if 'text' 01152 // so we have to check whether binary... 01153 case 'IMAGE': 01154 case 'LONGBLOB': 01155 case 'BLOB': 01156 case 'MEDIUMBLOB': 01157 01158 case MYSQLI_TYPE_BLOB : 01159 case MYSQLI_TYPE_LONG_BLOB : 01160 case MYSQLI_TYPE_MEDIUM_BLOB : 01161 01162 return !empty($fieldobj->binary) ? 'B' : 'X'; 01163 case 'YEAR': 01164 case 'DATE': 01165 case MYSQLI_TYPE_DATE : 01166 case MYSQLI_TYPE_YEAR : 01167 01168 return 'D'; 01169 01170 case 'TIME': 01171 case 'DATETIME': 01172 case 'TIMESTAMP': 01173 01174 case MYSQLI_TYPE_DATETIME : 01175 case MYSQLI_TYPE_NEWDATE : 01176 case MYSQLI_TYPE_TIME : 01177 case MYSQLI_TYPE_TIMESTAMP : 01178 01179 return 'T'; 01180 01181 case 'INT': 01182 case 'INTEGER': 01183 case 'BIGINT': 01184 case 'TINYINT': 01185 case 'MEDIUMINT': 01186 case 'SMALLINT': 01187 01188 case MYSQLI_TYPE_INT24 : 01189 case MYSQLI_TYPE_LONG : 01190 case MYSQLI_TYPE_LONGLONG : 01191 case MYSQLI_TYPE_SHORT : 01192 case MYSQLI_TYPE_TINY : 01193 01194 if (!empty($fieldobj->primary_key)) return 'R'; 01195 01196 return 'I'; 01197 01198 01199 // Added floating-point types 01200 // Maybe not necessery. 01201 case 'FLOAT': 01202 case 'DOUBLE': 01203 // case 'DOUBLE PRECISION': 01204 case 'DECIMAL': 01205 case 'DEC': 01206 case 'FIXED': 01207 default: 01208 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 01209 return 'N'; 01210 } 01211 } // function 01212 01213 } 01214 01215 ?>