Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /* 3 @version v5.20.16 12-Jan-2020 4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 6 Released under both BSD license and Lesser GPL library license. 7 Whenever there is any discrepancy between the two licenses, 8 the BSD license will take precedence. 9 Set tabs to 8. 10 11 This is the preferred driver for MySQL connections, and supports both transactional 12 and non-transactional table types. You can use this as a drop-in replacement for both 13 the mysql and mysqlt drivers. As of ADOdb Version 5.20.0, all other native MySQL drivers 14 are deprecated 15 16 Requires mysql client. Works on Windows and Unix. 17 18 21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl) 19 Based on adodb 3.40 20 */ 21 22 // security - hide paths 23 if (!defined('ADODB_DIR')) die(); 24 25 if (! defined("_ADODB_MYSQLI_LAYER")) { 26 define("_ADODB_MYSQLI_LAYER", 1 ); 27 28 // PHP5 compat... 29 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128); 30 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1); 31 32 // disable adodb extension - currently incompatible. 33 global $ADODB_EXTENSION; $ADODB_EXTENSION = false; 34 35 class ADODB_mysqli extends ADOConnection { 36 var $databaseType = 'mysqli'; 37 var $dataProvider = 'mysql'; 38 var $hasInsertID = true; 39 var $hasAffectedRows = true; 40 var $metaTablesSQL = "SELECT 41 TABLE_NAME, 42 CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END 43 FROM INFORMATION_SCHEMA.TABLES 44 WHERE TABLE_SCHEMA="; 45 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; 46 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 47 var $hasLimit = true; 48 var $hasMoveFirst = true; 49 var $hasGenID = true; 50 var $isoDates = true; // accepts dates in ISO format 51 var $sysDate = 'CURDATE()'; 52 var $sysTimeStamp = 'NOW()'; 53 var $hasTransactions = true; 54 var $forceNewConnect = false; 55 var $poorAffectedRows = true; 56 var $clientFlags = 0; 57 var $substr = "substring"; 58 var $port = 3306; //Default to 3306 to fix HHVM bug 59 var $socket = ''; //Default to empty string to fix HHVM bug 60 var $_bindInputArray = false; 61 var $nameQuote = '`'; /// string to use to quote identifiers and names 62 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0)); 63 var $arrayClass = 'ADORecordSet_array_mysqli'; 64 var $multiQuery = false; 65 66 function __construct() 67 { 68 // if(!extension_loaded("mysqli")) 69 //trigger_error("You must have the mysqli extension installed.", E_USER_ERROR); 70 } 71 72 function SetTransactionMode( $transaction_mode ) 73 { 74 $this->_transmode = $transaction_mode; 75 if (empty($transaction_mode)) { 76 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); 77 return; 78 } 79 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 80 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); 81 } 82 83 // returns true or false 84 // To add: parameter int $port, 85 // parameter string $socket 86 function _connect($argHostname = NULL, 87 $argUsername = NULL, 88 $argPassword = NULL, 89 $argDatabasename = NULL, $persist=false) 90 { 91 if(!extension_loaded("mysqli")) { 92 return null; 93 } 94 $this->_connectionID = @mysqli_init(); 95 96 if (is_null($this->_connectionID)) { 97 // mysqli_init only fails if insufficient memory 98 if ($this->debug) { 99 ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg()); 100 } 101 return false; 102 } 103 /* 104 I suggest a simple fix which would enable adodb and mysqli driver to 105 read connection options from the standard mysql configuration file 106 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com> 107 */ 108 foreach($this->optionFlags as $arr) { 109 mysqli_options($this->_connectionID,$arr[0],$arr[1]); 110 } 111 112 //http ://php.net/manual/en/mysqli.persistconns.php 113 if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname,'p:',2) != 0) $argHostname = 'p:'.$argHostname; 114 115 #if (!empty($this->port)) $argHostname .= ":".$this->port; 116 $ok = @mysqli_real_connect($this->_connectionID, 117 $argHostname, 118 $argUsername, 119 $argPassword, 120 $argDatabasename, 121 # PHP7 compat: port must be int. Use default port if cast yields zero 122 (int)$this->port != 0 ? (int)$this->port : 3306, 123 $this->socket, 124 $this->clientFlags); 125 126 if ($ok) { 127 if ($argDatabasename) return $this->SelectDB($argDatabasename); 128 return true; 129 } else { 130 if ($this->debug) { 131 ADOConnection::outp("Could not connect : " . $this->ErrorMsg()); 132 } 133 $this->_connectionID = null; 134 return false; 135 } 136 } 137 138 // returns true or false 139 // How to force a persistent connection 140 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 141 { 142 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true); 143 } 144 145 // When is this used? Close old connection first? 146 // In _connect(), check $this->forceNewConnect? 147 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 148 { 149 $this->forceNewConnect = true; 150 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); 151 } 152 153 function IfNull( $field, $ifNull ) 154 { 155 return " IFNULL($field, $ifNull) "; // if MySQL 156 } 157 158 // do not use $ADODB_COUNTRECS 159 function GetOne($sql,$inputarr=false) 160 { 161 global $ADODB_GETONE_EOF; 162 163 $ret = false; 164 $rs = $this->Execute($sql,$inputarr); 165 if ($rs) { 166 if ($rs->EOF) $ret = $ADODB_GETONE_EOF; 167 else $ret = reset($rs->fields); 168 $rs->Close(); 169 } 170 return $ret; 171 } 172 173 function ServerInfo() 174 { 175 $arr['description'] = $this->GetOne("select version()"); 176 $arr['version'] = ADOConnection::_findvers($arr['description']); 177 return $arr; 178 } 179 180 181 function BeginTrans() 182 { 183 if ($this->transOff) return true; 184 $this->transCnt += 1; 185 186 //$this->Execute('SET AUTOCOMMIT=0'); 187 mysqli_autocommit($this->_connectionID, false); 188 $this->Execute('BEGIN'); 189 return true; 190 } 191 192 function CommitTrans($ok=true) 193 { 194 if ($this->transOff) return true; 195 if (!$ok) return $this->RollbackTrans(); 196 197 if ($this->transCnt) $this->transCnt -= 1; 198 $this->Execute('COMMIT'); 199 200 //$this->Execute('SET AUTOCOMMIT=1'); 201 mysqli_autocommit($this->_connectionID, true); 202 return true; 203 } 204 205 function RollbackTrans() 206 { 207 if ($this->transOff) return true; 208 if ($this->transCnt) $this->transCnt -= 1; 209 $this->Execute('ROLLBACK'); 210 //$this->Execute('SET AUTOCOMMIT=1'); 211 mysqli_autocommit($this->_connectionID, true); 212 return true; 213 } 214 215 function RowLock($tables,$where='',$col='1 as adodbignore') 216 { 217 if ($this->transCnt==0) $this->BeginTrans(); 218 if ($where) $where = ' where '.$where; 219 $rs = $this->Execute("select $col from $tables $where for update"); 220 return !empty($rs); 221 } 222 223 /** 224 * Quotes a string to be sent to the database 225 * When there is no active connection, 226 * @param string $s The string to quote 227 * @param boolean $magic_quotes If false, use mysqli_real_escape_string() 228 * if you are quoting a string extracted from a POST/GET variable, 229 * then pass get_magic_quotes_gpc() as the second parameter. This will 230 * ensure that the variable is not quoted twice, once by qstr() and 231 * once by the magic_quotes_gpc. 232 * Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc()); 233 * @return string Quoted string 234 */ 235 function qstr($s, $magic_quotes = false) 236 { 237 if (is_null($s)) return 'NULL'; 238 if (!$magic_quotes) { 239 // mysqli_real_escape_string() throws a warning when the given 240 // connection is invalid 241 if (PHP_VERSION >= 5 && $this->_connectionID) { 242 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; 243 } 244 245 if ($this->replaceQuote[0] == '\\') { 246 $s = adodb_str_replace(array('\\',"\0"), array('\\\\',"\\\0") ,$s); 247 } 248 return "'" . str_replace("'", $this->replaceQuote, $s) . "'"; 249 } 250 // undo magic quotes for " 251 $s = str_replace('\\"','"',$s); 252 return "'$s'"; 253 } 254 255 function _insertid() 256 { 257 $result = @mysqli_insert_id($this->_connectionID); 258 if ($result == -1) { 259 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg()); 260 } 261 return $result; 262 } 263 264 // Only works for INSERT, UPDATE and DELETE query's 265 function _affectedrows() 266 { 267 $result = @mysqli_affected_rows($this->_connectionID); 268 if ($result == -1) { 269 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg()); 270 } 271 return $result; 272 } 273 274 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html 275 // Reference on Last_Insert_ID on the recommended way to simulate sequences 276 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; 277 var $_genSeqSQL = "create table if not exists %s (id int not null)"; 278 var $_genSeqCountSQL = "select count(*) from %s"; 279 var $_genSeq2SQL = "insert into %s values (%s)"; 280 var $_dropSeqSQL = "drop table if exists %s"; 281 282 function CreateSequence($seqname='adodbseq',$startID=1) 283 { 284 if (empty($this->_genSeqSQL)) return false; 285 $u = strtoupper($seqname); 286 287 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 288 if (!$ok) return false; 289 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 290 } 291 292 function GenID($seqname='adodbseq',$startID=1) 293 { 294 // post-nuke sets hasGenID to false 295 if (!$this->hasGenID) return false; 296 297 $getnext = sprintf($this->_genIDSQL,$seqname); 298 $holdtransOK = $this->_transOK; // save the current status 299 $rs = @$this->Execute($getnext); 300 if (!$rs) { 301 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset 302 $u = strtoupper($seqname); 303 $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 304 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname)); 305 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 306 $rs = $this->Execute($getnext); 307 } 308 309 if ($rs) { 310 $this->genID = mysqli_insert_id($this->_connectionID); 311 $rs->Close(); 312 } else 313 $this->genID = 0; 314 315 return $this->genID; 316 } 317 318 function MetaDatabases() 319 { 320 $query = "SHOW DATABASES"; 321 $ret = $this->Execute($query); 322 if ($ret && is_object($ret)){ 323 $arr = array(); 324 while (!$ret->EOF){ 325 $db = $ret->Fields('Database'); 326 if ($db != 'mysql') $arr[] = $db; 327 $ret->MoveNext(); 328 } 329 return $arr; 330 } 331 return $ret; 332 } 333 334 335 function MetaIndexes ($table, $primary = FALSE, $owner = false) 336 { 337 // save old fetch mode 338 global $ADODB_FETCH_MODE; 339 340 $false = false; 341 $save = $ADODB_FETCH_MODE; 342 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 343 if ($this->fetchMode !== FALSE) { 344 $savem = $this->SetFetchMode(FALSE); 345 } 346 347 // get index details 348 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); 349 350 // restore fetchmode 351 if (isset($savem)) { 352 $this->SetFetchMode($savem); 353 } 354 $ADODB_FETCH_MODE = $save; 355 356 if (!is_object($rs)) { 357 return $false; 358 } 359 360 $indexes = array (); 361 362 // parse index data into array 363 while ($row = $rs->FetchRow()) { 364 if ($primary == FALSE AND $row[2] == 'PRIMARY') { 365 continue; 366 } 367 368 if (!isset($indexes[$row[2]])) { 369 $indexes[$row[2]] = array( 370 'unique' => ($row[1] == 0), 371 'columns' => array() 372 ); 373 } 374 375 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; 376 } 377 378 // sort columns by order in the index 379 foreach ( array_keys ($indexes) as $index ) 380 { 381 ksort ($indexes[$index]['columns']); 382 } 383 384 return $indexes; 385 } 386 387 388 // Format date column in sql string given an input format that understands Y M D 389 function SQLDate($fmt, $col=false) 390 { 391 if (!$col) $col = $this->sysTimeStamp; 392 $s = 'DATE_FORMAT('.$col.",'"; 393 $concat = false; 394 $len = strlen($fmt); 395 for ($i=0; $i < $len; $i++) { 396 $ch = $fmt[$i]; 397 switch($ch) { 398 case 'Y': 399 case 'y': 400 $s .= '%Y'; 401 break; 402 case 'Q': 403 case 'q': 404 $s .= "'),Quarter($col)"; 405 406 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; 407 else $s .= ",('"; 408 $concat = true; 409 break; 410 case 'M': 411 $s .= '%b'; 412 break; 413 414 case 'm': 415 $s .= '%m'; 416 break; 417 case 'D': 418 case 'd': 419 $s .= '%d'; 420 break; 421 422 case 'H': 423 $s .= '%H'; 424 break; 425 426 case 'h': 427 $s .= '%I'; 428 break; 429 430 case 'i': 431 $s .= '%i'; 432 break; 433 434 case 's': 435 $s .= '%s'; 436 break; 437 438 case 'a': 439 case 'A': 440 $s .= '%p'; 441 break; 442 443 case 'w': 444 $s .= '%w'; 445 break; 446 447 case 'l': 448 $s .= '%W'; 449 break; 450 451 default: 452 453 if ($ch == '\\') { 454 $i++; 455 $ch = substr($fmt,$i,1); 456 } 457 $s .= $ch; 458 break; 459 } 460 } 461 $s.="')"; 462 if ($concat) $s = "CONCAT($s)"; 463 return $s; 464 } 465 466 // returns concatenated string 467 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator 468 function Concat() 469 { 470 $s = ""; 471 $arr = func_get_args(); 472 473 // suggestion by andrew005@mnogo.ru 474 $s = implode(',',$arr); 475 if (strlen($s) > 0) return "CONCAT($s)"; 476 else return ''; 477 } 478 479 // dayFraction is a day in floating point 480 function OffsetDate($dayFraction,$date=false) 481 { 482 if (!$date) $date = $this->sysDate; 483 484 $fraction = $dayFraction * 24 * 3600; 485 return $date . ' + INTERVAL ' . $fraction.' SECOND'; 486 487 // return "from_unixtime(unix_timestamp($date)+$fraction)"; 488 } 489 490 function MetaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null) 491 { 492 // save old fetch mode 493 global $ADODB_FETCH_MODE; 494 495 $false = false; 496 $save = $ADODB_FETCH_MODE; 497 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 498 499 if ($this->fetchMode !== FALSE) { 500 $savem = $this->SetFetchMode(FALSE); 501 } 502 503 $procedures = array (); 504 505 // get index details 506 507 $likepattern = ''; 508 if ($NamePattern) { 509 $likepattern = " LIKE '".$NamePattern."'"; 510 } 511 $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern); 512 if (is_object($rs)) { 513 514 // parse index data into array 515 while ($row = $rs->FetchRow()) { 516 $procedures[$row[1]] = array( 517 'type' => 'PROCEDURE', 518 'catalog' => '', 519 'schema' => '', 520 'remarks' => $row[7], 521 ); 522 } 523 } 524 525 $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern); 526 if (is_object($rs)) { 527 // parse index data into array 528 while ($row = $rs->FetchRow()) { 529 $procedures[$row[1]] = array( 530 'type' => 'FUNCTION', 531 'catalog' => '', 532 'schema' => '', 533 'remarks' => $row[7] 534 ); 535 } 536 } 537 538 // restore fetchmode 539 if (isset($savem)) { 540 $this->SetFetchMode($savem); 541 } 542 $ADODB_FETCH_MODE = $save; 543 544 return $procedures; 545 } 546 547 /** 548 * Retrieves a list of tables based on given criteria 549 * 550 * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default) 551 * @param string $showSchema schema name, false = current schema (default) 552 * @param string $mask filters the table by name 553 * 554 * @return array list of tables 555 */ 556 function MetaTables($ttype=false,$showSchema=false,$mask=false) 557 { 558 $save = $this->metaTablesSQL; 559 if ($showSchema && is_string($showSchema)) { 560 $this->metaTablesSQL .= $this->qstr($showSchema); 561 } else { 562 $this->metaTablesSQL .= "schema()"; 563 } 564 565 if ($mask) { 566 $mask = $this->qstr($mask); 567 $this->metaTablesSQL .= " AND table_name LIKE $mask"; 568 } 569 $ret = ADOConnection::MetaTables($ttype,$showSchema); 570 571 $this->metaTablesSQL = $save; 572 return $ret; 573 } 574 575 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> 576 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) 577 { 578 global $ADODB_FETCH_MODE; 579 580 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; 581 582 if ( !empty($owner) ) { 583 $table = "$owner.$table"; 584 } 585 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); 586 if ($associative) { 587 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"]; 588 } else $create_sql = $a_create_table[1]; 589 590 $matches = array(); 591 592 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; 593 $foreign_keys = array(); 594 $num_keys = count($matches[0]); 595 for ( $i = 0; $i < $num_keys; $i ++ ) { 596 $my_field = explode('`, `', $matches[1][$i]); 597 $ref_table = $matches[2][$i]; 598 $ref_field = explode('`, `', $matches[3][$i]); 599 600 if ( $upper ) { 601 $ref_table = strtoupper($ref_table); 602 } 603 604 // see https://sourceforge.net/p/adodb/bugs/100/ 605 if (!isset($foreign_keys[$ref_table])) { 606 $foreign_keys[$ref_table] = array(); 607 } 608 $num_fields = count($my_field); 609 for ( $j = 0; $j < $num_fields; $j ++ ) { 610 if ( $associative ) { 611 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; 612 } else { 613 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; 614 } 615 } 616 } 617 618 return $foreign_keys; 619 } 620 621 function MetaColumns($table, $normalize=true) 622 { 623 $false = false; 624 if (!$this->metaColumnsSQL) 625 return $false; 626 627 global $ADODB_FETCH_MODE; 628 $save = $ADODB_FETCH_MODE; 629 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 630 if ($this->fetchMode !== false) 631 $savem = $this->SetFetchMode(false); 632 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 633 if (isset($savem)) $this->SetFetchMode($savem); 634 $ADODB_FETCH_MODE = $save; 635 if (!is_object($rs)) 636 return $false; 637 638 $retarr = array(); 639 while (!$rs->EOF) { 640 $fld = new ADOFieldObject(); 641 $fld->name = $rs->fields[0]; 642 $type = $rs->fields[1]; 643 644 // split type into type(length): 645 $fld->scale = null; 646 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { 647 $fld->type = $query_array[1]; 648 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 649 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; 650 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { 651 $fld->type = $query_array[1]; 652 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 653 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { 654 $fld->type = $query_array[1]; 655 $arr = explode(",",$query_array[2]); 656 $fld->enums = $arr; 657 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 658 $fld->max_length = ($zlen > 0) ? $zlen : 1; 659 } else { 660 $fld->type = $type; 661 $fld->max_length = -1; 662 } 663 $fld->not_null = ($rs->fields[2] != 'YES'); 664 $fld->primary_key = ($rs->fields[3] == 'PRI'); 665 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); 666 $fld->binary = (strpos($type,'blob') !== false); 667 $fld->unsigned = (strpos($type,'unsigned') !== false); 668 $fld->zerofill = (strpos($type,'zerofill') !== false); 669 670 if (!$fld->binary) { 671 $d = $rs->fields[4]; 672 if ($d != '' && $d != 'NULL') { 673 $fld->has_default = true; 674 $fld->default_value = $d; 675 } else { 676 $fld->has_default = false; 677 } 678 } 679 680 if ($save == ADODB_FETCH_NUM) { 681 $retarr[] = $fld; 682 } else { 683 $retarr[strtoupper($fld->name)] = $fld; 684 } 685 $rs->MoveNext(); 686 } 687 688 $rs->Close(); 689 return $retarr; 690 } 691 692 // returns true or false 693 function SelectDB($dbName) 694 { 695 // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); 696 $this->database = $dbName; 697 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 698 699 if ($this->_connectionID) { 700 $result = @mysqli_select_db($this->_connectionID, $dbName); 701 if (!$result) { 702 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); 703 } 704 return $result; 705 } 706 return false; 707 } 708 709 // parameters use PostgreSQL convention, not MySQL 710 function SelectLimit($sql, 711 $nrows = -1, 712 $offset = -1, 713 $inputarr = false, 714 $secs = 0) 715 { 716 $nrows = (int) $nrows; 717 $offset = (int) $offset; 718 $offsetStr = ($offset >= 0) ? "$offset," : ''; 719 if ($nrows < 0) $nrows = '18446744073709551615'; 720 721 if ($secs) 722 $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr ); 723 else 724 $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr ); 725 726 return $rs; 727 } 728 729 730 function Prepare($sql) 731 { 732 return $sql; 733 $stmt = $this->_connectionID->prepare($sql); 734 if (!$stmt) { 735 echo $this->ErrorMsg(); 736 return $sql; 737 } 738 return array($sql,$stmt); 739 } 740 741 742 // returns queryID or false 743 function _query($sql, $inputarr) 744 { 745 global $ADODB_COUNTRECS; 746 // Move to the next recordset, or return false if there is none. In a stored proc 747 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 748 // returns false. I think this is because the last "recordset" is actually just the 749 // return value of the stored proc (ie the number of rows affected). 750 // Commented out for reasons of performance. You should retrieve every recordset yourself. 751 // if (!mysqli_next_result($this->connection->_connectionID)) return false; 752 753 if (is_array($sql)) { 754 755 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but 756 // returns as bound variables. 757 758 $stmt = $sql[1]; 759 $a = ''; 760 foreach($inputarr as $k => $v) { 761 if (is_string($v)) $a .= 's'; 762 else if (is_integer($v)) $a .= 'i'; 763 else $a .= 'd'; 764 } 765 766 $fnarr = array_merge( array($stmt,$a) , $inputarr); 767 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr); 768 $ret = mysqli_stmt_execute($stmt); 769 return $ret; 770 } 771 772 /* 773 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { 774 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 775 return false; 776 } 777 778 return $mysql_res; 779 */ 780 781 if ($this->multiQuery) { 782 $rs = mysqli_multi_query($this->_connectionID, $sql.';'); 783 if ($rs) { 784 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID ); 785 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID ) 786 } 787 } else { 788 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); 789 790 if ($rs) return $rs; 791 } 792 793 if($this->debug) 794 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 795 796 return false; 797 798 } 799 800 /* Returns: the last error message from previous database operation */ 801 function ErrorMsg() 802 { 803 if (empty($this->_connectionID)) 804 $this->_errorMsg = @mysqli_connect_error(); 805 else 806 $this->_errorMsg = @mysqli_error($this->_connectionID); 807 return $this->_errorMsg; 808 } 809 810 /* Returns: the last error number from previous database operation */ 811 function ErrorNo() 812 { 813 if (empty($this->_connectionID)) 814 return @mysqli_connect_errno(); 815 else 816 return @mysqli_errno($this->_connectionID); 817 } 818 819 // returns true or false 820 function _close() 821 { 822 @mysqli_close($this->_connectionID); 823 $this->_connectionID = false; 824 } 825 826 /* 827 * Maximum size of C field 828 */ 829 function CharMax() 830 { 831 return 255; 832 } 833 834 /* 835 * Maximum size of X field 836 */ 837 function TextMax() 838 { 839 return 4294967295; 840 } 841 842 843 // this is a set of functions for managing client encoding - very important if the encodings 844 // of your database and your output target (i.e. HTML) don't match 845 // for instance, you may have UTF8 database and server it on-site as latin1 etc. 846 // GetCharSet - get the name of the character set the client is using now 847 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported 848 // depends on compile flags of mysql distribution 849 850 function GetCharSet() 851 { 852 //we will use ADO's builtin property charSet 853 if (!method_exists($this->_connectionID,'character_set_name')) 854 return false; 855 856 $this->charSet = @$this->_connectionID->character_set_name(); 857 if (!$this->charSet) { 858 return false; 859 } else { 860 return $this->charSet; 861 } 862 } 863 864 // SetCharSet - switch the client encoding 865 function SetCharSet($charset_name) 866 { 867 if (!method_exists($this->_connectionID,'set_charset')) { 868 return false; 869 } 870 871 if ($this->charSet !== $charset_name) { 872 $if = @$this->_connectionID->set_charset($charset_name); 873 return ($if === true & $this->GetCharSet() == $charset_name); 874 } else { 875 return true; 876 } 877 } 878 879 } 880 881 /*-------------------------------------------------------------------------------------- 882 Class Name: Recordset 883 --------------------------------------------------------------------------------------*/ 884 885 class ADORecordSet_mysqli extends ADORecordSet{ 886 887 var $databaseType = "mysqli"; 888 var $canSeek = true; 889 890 function __construct($queryID, $mode = false) 891 { 892 if ($mode === false) { 893 global $ADODB_FETCH_MODE; 894 $mode = $ADODB_FETCH_MODE; 895 } 896 897 switch ($mode) { 898 case ADODB_FETCH_NUM: 899 $this->fetchMode = MYSQLI_NUM; 900 break; 901 case ADODB_FETCH_ASSOC: 902 $this->fetchMode = MYSQLI_ASSOC; 903 break; 904 case ADODB_FETCH_DEFAULT: 905 case ADODB_FETCH_BOTH: 906 default: 907 $this->fetchMode = MYSQLI_BOTH; 908 break; 909 } 910 $this->adodbFetchMode = $mode; 911 parent::__construct($queryID); 912 } 913 914 function _initrs() 915 { 916 global $ADODB_COUNTRECS; 917 918 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; 919 $this->_numOfFields = @mysqli_num_fields($this->_queryID); 920 } 921 922 /* 923 1 = MYSQLI_NOT_NULL_FLAG 924 2 = MYSQLI_PRI_KEY_FLAG 925 4 = MYSQLI_UNIQUE_KEY_FLAG 926 8 = MYSQLI_MULTIPLE_KEY_FLAG 927 16 = MYSQLI_BLOB_FLAG 928 32 = MYSQLI_UNSIGNED_FLAG 929 64 = MYSQLI_ZEROFILL_FLAG 930 128 = MYSQLI_BINARY_FLAG 931 256 = MYSQLI_ENUM_FLAG 932 512 = MYSQLI_AUTO_INCREMENT_FLAG 933 1024 = MYSQLI_TIMESTAMP_FLAG 934 2048 = MYSQLI_SET_FLAG 935 32768 = MYSQLI_NUM_FLAG 936 16384 = MYSQLI_PART_KEY_FLAG 937 32768 = MYSQLI_GROUP_FLAG 938 65536 = MYSQLI_UNIQUE_FLAG 939 131072 = MYSQLI_BINCMP_FLAG 940 */ 941 942 function FetchField($fieldOffset = -1) 943 { 944 $fieldnr = $fieldOffset; 945 if ($fieldOffset != -1) { 946 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr); 947 } 948 $o = @mysqli_fetch_field($this->_queryID); 949 if (!$o) return false; 950 951 //Fix for HHVM 952 if ( !isset($o->flags) ) { 953 $o->flags = 0; 954 } 955 /* Properties of an ADOFieldObject as set by MetaColumns */ 956 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; 957 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; 958 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; 959 $o->binary = $o->flags & MYSQLI_BINARY_FLAG; 960 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ 961 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; 962 963 return $o; 964 } 965 966 function GetRowAssoc($upper = ADODB_ASSOC_CASE) 967 { 968 if ($this->fetchMode == MYSQLI_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) { 969 return $this->fields; 970 } 971 $row = ADORecordSet::GetRowAssoc($upper); 972 return $row; 973 } 974 975 /* Use associative array to get fields array */ 976 function Fields($colname) 977 { 978 if ($this->fetchMode != MYSQLI_NUM) { 979 return @$this->fields[$colname]; 980 } 981 982 if (!$this->bind) { 983 $this->bind = array(); 984 for ($i = 0; $i < $this->_numOfFields; $i++) { 985 $o = $this->FetchField($i); 986 $this->bind[strtoupper($o->name)] = $i; 987 } 988 } 989 return $this->fields[$this->bind[strtoupper($colname)]]; 990 } 991 992 function _seek($row) 993 { 994 if ($this->_numOfRows == 0 || $row < 0) { 995 return false; 996 } 997 998 mysqli_data_seek($this->_queryID, $row); 999 $this->EOF = false; 1000 return true; 1001 } 1002 1003 1004 function NextRecordSet() 1005 { 1006 global $ADODB_COUNTRECS; 1007 1008 mysqli_free_result($this->_queryID); 1009 $this->_queryID = -1; 1010 // Move to the next recordset, or return false if there is none. In a stored proc 1011 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 1012 // returns false. I think this is because the last "recordset" is actually just the 1013 // return value of the stored proc (ie the number of rows affected). 1014 if(!mysqli_next_result($this->connection->_connectionID)) { 1015 return false; 1016 } 1017 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using 1018 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID ) 1019 : @mysqli_use_result( $this->connection->_connectionID ); 1020 if(!$this->_queryID) { 1021 return false; 1022 } 1023 $this->_inited = false; 1024 $this->bind = false; 1025 $this->_currentRow = -1; 1026 $this->Init(); 1027 return true; 1028 } 1029 1030 // 10% speedup to move MoveNext to child class 1031 // This is the only implementation that works now (23-10-2003). 1032 // Other functions return no or the wrong results. 1033 function MoveNext() 1034 { 1035 if ($this->EOF) return false; 1036 $this->_currentRow++; 1037 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); 1038 1039 if (is_array($this->fields)) { 1040 $this->_updatefields(); 1041 return true; 1042 } 1043 $this->EOF = true; 1044 return false; 1045 } 1046 1047 function _fetch() 1048 { 1049 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); 1050 $this->_updatefields(); 1051 return is_array($this->fields); 1052 } 1053 1054 function _close() 1055 { 1056 //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014 1057 //only a problem with persistant connections 1058 1059 if(isset($this->connection->_connectionID) && $this->connection->_connectionID) { 1060 while(mysqli_more_results($this->connection->_connectionID)){ 1061 mysqli_next_result($this->connection->_connectionID); 1062 } 1063 } 1064 1065 if($this->_queryID instanceof mysqli_result) { 1066 mysqli_free_result($this->_queryID); 1067 } 1068 $this->_queryID = false; 1069 } 1070 1071 /* 1072 1073 0 = MYSQLI_TYPE_DECIMAL 1074 1 = MYSQLI_TYPE_CHAR 1075 1 = MYSQLI_TYPE_TINY 1076 2 = MYSQLI_TYPE_SHORT 1077 3 = MYSQLI_TYPE_LONG 1078 4 = MYSQLI_TYPE_FLOAT 1079 5 = MYSQLI_TYPE_DOUBLE 1080 6 = MYSQLI_TYPE_NULL 1081 7 = MYSQLI_TYPE_TIMESTAMP 1082 8 = MYSQLI_TYPE_LONGLONG 1083 9 = MYSQLI_TYPE_INT24 1084 10 = MYSQLI_TYPE_DATE 1085 11 = MYSQLI_TYPE_TIME 1086 12 = MYSQLI_TYPE_DATETIME 1087 13 = MYSQLI_TYPE_YEAR 1088 14 = MYSQLI_TYPE_NEWDATE 1089 247 = MYSQLI_TYPE_ENUM 1090 248 = MYSQLI_TYPE_SET 1091 249 = MYSQLI_TYPE_TINY_BLOB 1092 250 = MYSQLI_TYPE_MEDIUM_BLOB 1093 251 = MYSQLI_TYPE_LONG_BLOB 1094 252 = MYSQLI_TYPE_BLOB 1095 253 = MYSQLI_TYPE_VAR_STRING 1096 254 = MYSQLI_TYPE_STRING 1097 255 = MYSQLI_TYPE_GEOMETRY 1098 */ 1099 1100 function MetaType($t, $len = -1, $fieldobj = false) 1101 { 1102 if (is_object($t)) { 1103 $fieldobj = $t; 1104 $t = $fieldobj->type; 1105 $len = $fieldobj->max_length; 1106 } 1107 1108 1109 $len = -1; // mysql max_length is not accurate 1110 switch (strtoupper($t)) { 1111 case 'STRING': 1112 case 'CHAR': 1113 case 'VARCHAR': 1114 case 'TINYBLOB': 1115 case 'TINYTEXT': 1116 case 'ENUM': 1117 case 'SET': 1118 1119 case MYSQLI_TYPE_TINY_BLOB : 1120 #case MYSQLI_TYPE_CHAR : 1121 case MYSQLI_TYPE_STRING : 1122 case MYSQLI_TYPE_ENUM : 1123 case MYSQLI_TYPE_SET : 1124 case 253 : 1125 if ($len <= $this->blobSize) return 'C'; 1126 1127 case 'TEXT': 1128 case 'LONGTEXT': 1129 case 'MEDIUMTEXT': 1130 return 'X'; 1131 1132 // php_mysql extension always returns 'blob' even if 'text' 1133 // so we have to check whether binary... 1134 case 'IMAGE': 1135 case 'LONGBLOB': 1136 case 'BLOB': 1137 case 'MEDIUMBLOB': 1138 1139 case MYSQLI_TYPE_BLOB : 1140 case MYSQLI_TYPE_LONG_BLOB : 1141 case MYSQLI_TYPE_MEDIUM_BLOB : 1142 return !empty($fieldobj->binary) ? 'B' : 'X'; 1143 1144 case 'YEAR': 1145 case 'DATE': 1146 case MYSQLI_TYPE_DATE : 1147 case MYSQLI_TYPE_YEAR : 1148 return 'D'; 1149 1150 case 'TIME': 1151 case 'DATETIME': 1152 case 'TIMESTAMP': 1153 1154 case MYSQLI_TYPE_DATETIME : 1155 case MYSQLI_TYPE_NEWDATE : 1156 case MYSQLI_TYPE_TIME : 1157 case MYSQLI_TYPE_TIMESTAMP : 1158 return 'T'; 1159 1160 case 'INT': 1161 case 'INTEGER': 1162 case 'BIGINT': 1163 case 'TINYINT': 1164 case 'MEDIUMINT': 1165 case 'SMALLINT': 1166 1167 case MYSQLI_TYPE_INT24 : 1168 case MYSQLI_TYPE_LONG : 1169 case MYSQLI_TYPE_LONGLONG : 1170 case MYSQLI_TYPE_SHORT : 1171 case MYSQLI_TYPE_TINY : 1172 if (!empty($fieldobj->primary_key)) return 'R'; 1173 return 'I'; 1174 1175 // Added floating-point types 1176 // Maybe not necessery. 1177 case 'FLOAT': 1178 case 'DOUBLE': 1179 // case 'DOUBLE PRECISION': 1180 case 'DECIMAL': 1181 case 'DEC': 1182 case 'FIXED': 1183 default: 1184 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1185 return 'N'; 1186 } 1187 } // function 1188 1189 1190 } // rs class 1191 1192 } 1193 1194 class ADORecordSet_array_mysqli extends ADORecordSet_array { 1195 1196 function __construct($id=-1,$mode=false) 1197 { 1198 parent::__construct($id,$mode); 1199 } 1200 1201 function MetaType($t, $len = -1, $fieldobj = false) 1202 { 1203 if (is_object($t)) { 1204 $fieldobj = $t; 1205 $t = $fieldobj->type; 1206 $len = $fieldobj->max_length; 1207 } 1208 1209 1210 $len = -1; // mysql max_length is not accurate 1211 switch (strtoupper($t)) { 1212 case 'STRING': 1213 case 'CHAR': 1214 case 'VARCHAR': 1215 case 'TINYBLOB': 1216 case 'TINYTEXT': 1217 case 'ENUM': 1218 case 'SET': 1219 1220 case MYSQLI_TYPE_TINY_BLOB : 1221 #case MYSQLI_TYPE_CHAR : 1222 case MYSQLI_TYPE_STRING : 1223 case MYSQLI_TYPE_ENUM : 1224 case MYSQLI_TYPE_SET : 1225 case 253 : 1226 if ($len <= $this->blobSize) return 'C'; 1227 1228 case 'TEXT': 1229 case 'LONGTEXT': 1230 case 'MEDIUMTEXT': 1231 return 'X'; 1232 1233 // php_mysql extension always returns 'blob' even if 'text' 1234 // so we have to check whether binary... 1235 case 'IMAGE': 1236 case 'LONGBLOB': 1237 case 'BLOB': 1238 case 'MEDIUMBLOB': 1239 1240 case MYSQLI_TYPE_BLOB : 1241 case MYSQLI_TYPE_LONG_BLOB : 1242 case MYSQLI_TYPE_MEDIUM_BLOB : 1243 1244 return !empty($fieldobj->binary) ? 'B' : 'X'; 1245 case 'YEAR': 1246 case 'DATE': 1247 case MYSQLI_TYPE_DATE : 1248 case MYSQLI_TYPE_YEAR : 1249 1250 return 'D'; 1251 1252 case 'TIME': 1253 case 'DATETIME': 1254 case 'TIMESTAMP': 1255 1256 case MYSQLI_TYPE_DATETIME : 1257 case MYSQLI_TYPE_NEWDATE : 1258 case MYSQLI_TYPE_TIME : 1259 case MYSQLI_TYPE_TIMESTAMP : 1260 1261 return 'T'; 1262 1263 case 'INT': 1264 case 'INTEGER': 1265 case 'BIGINT': 1266 case 'TINYINT': 1267 case 'MEDIUMINT': 1268 case 'SMALLINT': 1269 1270 case MYSQLI_TYPE_INT24 : 1271 case MYSQLI_TYPE_LONG : 1272 case MYSQLI_TYPE_LONGLONG : 1273 case MYSQLI_TYPE_SHORT : 1274 case MYSQLI_TYPE_TINY : 1275 1276 if (!empty($fieldobj->primary_key)) return 'R'; 1277 1278 return 'I'; 1279 1280 1281 // Added floating-point types 1282 // Maybe not necessery. 1283 case 'FLOAT': 1284 case 'DOUBLE': 1285 // case 'DOUBLE PRECISION': 1286 case 'DECIMAL': 1287 case 'DEC': 1288 case 'FIXED': 1289 default: 1290 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1291 return 'N'; 1292 } 1293 } // function 1294 1295 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body