Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 /* 3 @version v5.21.0 2021-02-27 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')) { 24 die(); 25 } 26 27 if (!defined("_ADODB_MYSQLI_LAYER")) { 28 define("_ADODB_MYSQLI_LAYER", 1); 29 30 // PHP5 compat... 31 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128); 32 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1); 33 34 /** 35 * Class ADODB_mysqli 36 */ 37 class ADODB_mysqli extends ADOConnection { 38 var $databaseType = 'mysqli'; 39 var $dataProvider = 'mysql'; 40 var $hasInsertID = true; 41 var $hasAffectedRows = true; 42 var $metaTablesSQL = "SELECT 43 TABLE_NAME, 44 CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END 45 FROM INFORMATION_SCHEMA.TABLES 46 WHERE TABLE_SCHEMA="; 47 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; 48 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 49 var $hasLimit = true; 50 var $hasMoveFirst = true; 51 var $hasGenID = true; 52 var $isoDates = true; // accepts dates in ISO format 53 var $sysDate = 'CURDATE()'; 54 var $sysTimeStamp = 'NOW()'; 55 var $hasTransactions = true; 56 var $forceNewConnect = false; 57 var $poorAffectedRows = true; 58 var $clientFlags = 0; 59 var $substr = "substring"; 60 var $port = 3306; //Default to 3306 to fix HHVM bug 61 var $socket = ''; //Default to empty string to fix HHVM bug 62 var $_bindInputArray = false; 63 var $nameQuote = '`'; /// string to use to quote identifiers and names 64 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0)); 65 var $arrayClass = 'ADORecordSet_array_mysqli'; 66 var $multiQuery = false; 67 var $ssl_key = null; 68 var $ssl_cert = null; 69 var $ssl_ca = null; 70 var $ssl_capath = null; 71 var $ssl_cipher = null; 72 73 /** 74 * Tells the insert_id method how to obtain the last value, depending on whether 75 * we are using a stored procedure or not 76 */ 77 private $usePreparedStatement = false; 78 private $useLastInsertStatement = false; 79 80 /** 81 * Sets the isolation level of a transaction. 82 * 83 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:settransactionmode 84 * 85 * @param string $transaction_mode The transaction mode to set. 86 * 87 * @return void 88 */ 89 function SetTransactionMode($transaction_mode) 90 { 91 $this->_transmode = $transaction_mode; 92 if (empty($transaction_mode)) { 93 $this->execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); 94 return; 95 } 96 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 97 $this->execute("SET SESSION TRANSACTION ".$transaction_mode); 98 } 99 100 /** 101 * Connect to a database. 102 * 103 * @todo add: parameter int $port, parameter string $socket 104 * 105 * @param string|null $argHostname (Optional) The host to connect to. 106 * @param string|null $argUsername (Optional) The username to connect as. 107 * @param string|null $argPassword (Optional) The password to connect with. 108 * @param string|null $argDatabasename (Optional) The name of the database to start in when connected. 109 * @param bool $persist (Optional) Whether or not to use a persistent connection. 110 * 111 * @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension 112 * isn't currently loaded. 113 */ 114 function _connect($argHostname = null, 115 $argUsername = null, 116 $argPassword = null, 117 $argDatabasename = null, 118 $persist = false) 119 { 120 if(!extension_loaded("mysqli")) { 121 return null; 122 } 123 $this->_connectionID = @mysqli_init(); 124 125 if (is_null($this->_connectionID)) { 126 // mysqli_init only fails if insufficient memory 127 if ($this->debug) { 128 ADOConnection::outp("mysqli_init() failed : " . $this->errorMsg()); 129 } 130 return false; 131 } 132 /* 133 I suggest a simple fix which would enable adodb and mysqli driver to 134 read connection options from the standard mysql configuration file 135 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com> 136 */ 137 $this->optionFlags = array(); 138 foreach($this->optionFlags as $arr) { 139 mysqli_options($this->_connectionID,$arr[0],$arr[1]); 140 } 141 142 /* 143 * Now merge in the standard connection parameters setting 144 */ 145 foreach ($this->connectionParameters as $options) 146 { 147 foreach($options as $k=>$v) 148 $ok = mysqli_options($this->_connectionID,$k,$v); 149 } 150 151 //https://php.net/manual/en/mysqli.persistconns.php 152 if ($persist && strncmp($argHostname,'p:',2) != 0) { 153 $argHostname = 'p:' . $argHostname; 154 } 155 156 // SSL Connections for MySQLI 157 if ($this->ssl_key || $this->ssl_cert || $this->ssl_ca || $this->ssl_capath || $this->ssl_cipher) { 158 mysqli_ssl_set($this->_connectionID, $this->ssl_key, $this->ssl_cert, $this->ssl_ca, $this->ssl_capath, $this->ssl_cipher); 159 } 160 161 #if (!empty($this->port)) $argHostname .= ":".$this->port; 162 $ok = @mysqli_real_connect($this->_connectionID, 163 $argHostname, 164 $argUsername, 165 $argPassword, 166 $argDatabasename, 167 # PHP7 compat: port must be int. Use default port if cast yields zero 168 (int)$this->port != 0 ? (int)$this->port : 3306, 169 $this->socket, 170 $this->clientFlags); 171 172 if ($ok) { 173 if ($argDatabasename) return $this->selectDB($argDatabasename); 174 return true; 175 } else { 176 if ($this->debug) { 177 ADOConnection::outp("Could not connect : " . $this->errorMsg()); 178 } 179 $this->_connectionID = null; 180 return false; 181 } 182 } 183 184 /** 185 * Connect to a database with a persistent connection. 186 * 187 * @param string|null $argHostname The host to connect to. 188 * @param string|null $argUsername The username to connect as. 189 * @param string|null $argPassword The password to connect with. 190 * @param string|null $argDatabasename The name of the database to start in when connected. 191 * 192 * @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension 193 * isn't currently loaded. 194 */ 195 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 196 { 197 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true); 198 } 199 200 /** 201 * Connect to a database, whilst setting $this->forceNewConnect to true. 202 * 203 * When is this used? Close old connection first? 204 * In _connect(), check $this->forceNewConnect? 205 * 206 * @param string|null $argHostname The host to connect to. 207 * @param string|null $argUsername The username to connect as. 208 * @param string|null $argPassword The password to connect with. 209 * @param string|null $argDatabasename The name of the database to start in when connected. 210 * 211 * @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension 212 * isn't currently loaded. 213 */ 214 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 215 { 216 $this->forceNewConnect = true; 217 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); 218 } 219 220 /** 221 * Replaces a null value with a specified replacement. 222 * 223 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:ifnull 224 * 225 * @param mixed $field The field in the table to check. 226 * @param mixed $ifNull The value to replace the null value with if it is found. 227 * 228 * @return string 229 */ 230 function IfNull($field, $ifNull) 231 { 232 return " IFNULL($field, $ifNull) "; 233 } 234 235 /** 236 * Retrieves the first column of the first matching row of an executed SQL statement. 237 * 238 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:getone 239 * 240 * @param string $sql The SQL to execute. 241 * @param bool|array $inputarr (Optional) An array containing any required SQL parameters, or false if none needed. 242 * 243 * @return bool|array|null 244 */ 245 function GetOne($sql, $inputarr = false) 246 { 247 global $ADODB_GETONE_EOF; 248 249 $ret = false; 250 $rs = $this->execute($sql,$inputarr); 251 if ($rs) { 252 if ($rs->EOF) $ret = $ADODB_GETONE_EOF; 253 else $ret = reset($rs->fields); 254 $rs->close(); 255 } 256 return $ret; 257 } 258 259 /** 260 * Get information about the current MySQL server. 261 * 262 * @return array 263 */ 264 function ServerInfo() 265 { 266 $arr['description'] = $this->getOne("select version()"); 267 $arr['version'] = ADOConnection::_findvers($arr['description']); 268 return $arr; 269 } 270 271 /** 272 * Begins a granular transaction. 273 * 274 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:begintrans 275 * 276 * @return bool Always returns true. 277 */ 278 function BeginTrans() 279 { 280 if ($this->transOff) return true; 281 $this->transCnt += 1; 282 283 //$this->execute('SET AUTOCOMMIT=0'); 284 mysqli_autocommit($this->_connectionID, false); 285 $this->execute('BEGIN'); 286 return true; 287 } 288 289 /** 290 * Commits a granular transaction. 291 * 292 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:committrans 293 * 294 * @param bool $ok (Optional) If false, will rollback the transaction instead. 295 * 296 * @return bool Always returns true. 297 */ 298 function CommitTrans($ok = true) 299 { 300 if ($this->transOff) return true; 301 if (!$ok) return $this->rollbackTrans(); 302 303 if ($this->transCnt) $this->transCnt -= 1; 304 $this->execute('COMMIT'); 305 306 //$this->execute('SET AUTOCOMMIT=1'); 307 mysqli_autocommit($this->_connectionID, true); 308 return true; 309 } 310 311 /** 312 * Rollback a smart transaction. 313 * 314 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:rollbacktrans 315 * 316 * @return bool Always returns true. 317 */ 318 function RollbackTrans() 319 { 320 if ($this->transOff) return true; 321 if ($this->transCnt) $this->transCnt -= 1; 322 $this->execute('ROLLBACK'); 323 //$this->execute('SET AUTOCOMMIT=1'); 324 mysqli_autocommit($this->_connectionID, true); 325 return true; 326 } 327 328 /** 329 * Lock a table row for a duration of a transaction. 330 * 331 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:rowlock 332 * 333 * @param string $tables The table(s) to lock rows for. 334 * @param string $where (Optional) The WHERE clause to use to determine which rows to lock. 335 * @param string $col (Optional) The columns to select. 336 * 337 * @return bool True if the locking SQL statement executed successfully, otherwise false. 338 */ 339 function RowLock($tables, $where = '', $col = '1 as adodbignore') 340 { 341 if ($this->transCnt==0) $this->beginTrans(); 342 if ($where) $where = ' where '.$where; 343 $rs = $this->execute("select $col from $tables $where for update"); 344 return !empty($rs); 345 } 346 347 /** 348 * Appropriately quotes strings with ' characters for insertion into the database. 349 * 350 * Relies on mysqli_real_escape_string() 351 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr 352 * 353 * @param string $s The string to quote 354 * @param bool $magic_quotes This param is not used since 5.21.0. 355 * It remains for backwards compatibility. 356 * 357 * @return string Quoted string 358 */ 359 function qStr($s, $magic_quotes=false) 360 { 361 if (is_null($s)) { 362 return 'NULL'; 363 } 364 365 // mysqli_real_escape_string() throws a warning when the given 366 // connection is invalid 367 if ($this->_connectionID) { 368 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; 369 } 370 371 if ($this->replaceQuote[0] == '\\') { 372 $s = str_replace(array('\\', "\0"), array('\\\\', "\\\0") ,$s); 373 } 374 return "'" . str_replace("'", $this->replaceQuote, $s) . "'"; 375 } 376 377 /** 378 * Return the AUTO_INCREMENT id of the last row that has been inserted or updated in a table. 379 * 380 * @return int|string 381 */ 382 function _insertid() 383 { 384 // mysqli_insert_id does not return the last_insert_id if called after 385 // execution of a stored procedure so we execute this instead. 386 if ($this->useLastInsertStatement) 387 $result = ADOConnection::getOne('SELECT LAST_INSERT_ID()'); 388 else 389 $result = @mysqli_insert_id($this->_connectionID); 390 391 if ($result == -1) { 392 if ($this->debug) 393 ADOConnection::outp("mysqli_insert_id() failed : " . $this->errorMsg()); 394 } 395 // reset prepared statement flags 396 $this->usePreparedStatement = false; 397 $this->useLastInsertStatement = false; 398 return $result; 399 } 400 401 /** 402 * Returns how many rows were effected by the most recently executed SQL statement. 403 * Only works for INSERT, UPDATE and DELETE queries. 404 * 405 * @return int The number of rows affected. 406 */ 407 function _affectedrows() 408 { 409 $result = @mysqli_affected_rows($this->_connectionID); 410 if ($result == -1) { 411 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->errorMsg()); 412 } 413 return $result; 414 } 415 416 // Reference on Last_Insert_ID on the recommended way to simulate sequences 417 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; 418 var $_genSeqSQL = "create table if not exists %s (id int not null)"; 419 var $_genSeqCountSQL = "select count(*) from %s"; 420 var $_genSeq2SQL = "insert into %s values (%s)"; 421 var $_dropSeqSQL = "drop table if exists %s"; 422 423 /** 424 * Creates a sequence in the database. 425 * 426 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:createsequence 427 * 428 * @param string $seqname The sequence name. 429 * @param int $startID The start id. 430 * 431 * @return ADORecordSet|bool A record set if executed successfully, otherwise false. 432 */ 433 function CreateSequence($seqname = 'adodbseq', $startID = 1) 434 { 435 if (empty($this->_genSeqSQL)) return false; 436 437 $ok = $this->execute(sprintf($this->_genSeqSQL,$seqname)); 438 if (!$ok) return false; 439 return $this->execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 440 } 441 442 /** 443 * A portable method of creating sequence numbers. 444 * 445 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:genid 446 * 447 * @param string $seqname (Optional) The name of the sequence to use. 448 * @param int $startID (Optional) The point to start at in the sequence. 449 * 450 * @return bool|int|string 451 */ 452 function GenID($seqname = 'adodbseq', $startID = 1) 453 { 454 // post-nuke sets hasGenID to false 455 if (!$this->hasGenID) return false; 456 457 $getnext = sprintf($this->_genIDSQL,$seqname); 458 $holdtransOK = $this->_transOK; // save the current status 459 $rs = @$this->execute($getnext); 460 if (!$rs) { 461 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset 462 $this->execute(sprintf($this->_genSeqSQL,$seqname)); 463 $cnt = $this->getOne(sprintf($this->_genSeqCountSQL,$seqname)); 464 if (!$cnt) $this->execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 465 $rs = $this->execute($getnext); 466 } 467 468 if ($rs) { 469 $this->genID = mysqli_insert_id($this->_connectionID); 470 if ($this->genID == 0) { 471 $getnext = "select LAST_INSERT_ID() from " . $seqname; 472 $rs = $this->execute($getnext); 473 $this->genID = (int)$rs->fields[0]; 474 } 475 $rs->close(); 476 } else 477 $this->genID = 0; 478 479 return $this->genID; 480 } 481 482 /** 483 * Return a list of all visible databases except the 'mysql' database. 484 * 485 * @return array|false An array of database names, or false if the query failed. 486 */ 487 function MetaDatabases() 488 { 489 $query = "SHOW DATABASES"; 490 $ret = $this->execute($query); 491 if ($ret && is_object($ret)){ 492 $arr = array(); 493 while (!$ret->EOF){ 494 $db = $ret->fields('Database'); 495 if ($db != 'mysql') $arr[] = $db; 496 $ret->moveNext(); 497 } 498 return $arr; 499 } 500 return $ret; 501 } 502 503 /** 504 * Get a list of indexes on the specified table. 505 * 506 * @param string $table The name of the table to get indexes for. 507 * @param bool $primary (Optional) Whether or not to include the primary key. 508 * @param bool $owner (Optional) Unused. 509 * 510 * @return array|bool An array of the indexes, or false if the query to get the indexes failed. 511 */ 512 function MetaIndexes($table, $primary = false, $owner = false) 513 { 514 // save old fetch mode 515 global $ADODB_FETCH_MODE; 516 517 $false = false; 518 $save = $ADODB_FETCH_MODE; 519 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 520 if ($this->fetchMode !== FALSE) { 521 $savem = $this->setFetchMode(FALSE); 522 } 523 524 // get index details 525 $rs = $this->execute(sprintf('SHOW INDEXES FROM %s',$table)); 526 527 // restore fetchmode 528 if (isset($savem)) { 529 $this->setFetchMode($savem); 530 } 531 $ADODB_FETCH_MODE = $save; 532 533 if (!is_object($rs)) { 534 return $false; 535 } 536 537 $indexes = array (); 538 539 // parse index data into array 540 while ($row = $rs->fetchRow()) { 541 if ($primary == FALSE AND $row[2] == 'PRIMARY') { 542 continue; 543 } 544 545 if (!isset($indexes[$row[2]])) { 546 $indexes[$row[2]] = array( 547 'unique' => ($row[1] == 0), 548 'columns' => array() 549 ); 550 } 551 552 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; 553 } 554 555 // sort columns by order in the index 556 foreach ( array_keys ($indexes) as $index ) 557 { 558 ksort ($indexes[$index]['columns']); 559 } 560 561 return $indexes; 562 } 563 564 /** 565 * Returns a portably-formatted date string from a timestamp database column. 566 * 567 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:sqldate 568 * 569 * @param string $fmt The date format to use. 570 * @param string|bool $col (Optional) The table column to date format, or if false, use NOW(). 571 * 572 * @return bool|string The SQL DATE_FORMAT() string, or false if the provided date format was empty. 573 */ 574 function SQLDate($fmt, $col = false) 575 { 576 if (!$col) $col = $this->sysTimeStamp; 577 $s = 'DATE_FORMAT('.$col.",'"; 578 $concat = false; 579 $len = strlen($fmt); 580 for ($i=0; $i < $len; $i++) { 581 $ch = $fmt[$i]; 582 switch($ch) { 583 case 'Y': 584 case 'y': 585 $s .= '%Y'; 586 break; 587 case 'Q': 588 case 'q': 589 $s .= "'),Quarter($col)"; 590 591 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; 592 else $s .= ",('"; 593 $concat = true; 594 break; 595 case 'M': 596 $s .= '%b'; 597 break; 598 599 case 'm': 600 $s .= '%m'; 601 break; 602 case 'D': 603 case 'd': 604 $s .= '%d'; 605 break; 606 607 case 'H': 608 $s .= '%H'; 609 break; 610 611 case 'h': 612 $s .= '%I'; 613 break; 614 615 case 'i': 616 $s .= '%i'; 617 break; 618 619 case 's': 620 $s .= '%s'; 621 break; 622 623 case 'a': 624 case 'A': 625 $s .= '%p'; 626 break; 627 628 case 'w': 629 $s .= '%w'; 630 break; 631 632 case 'l': 633 $s .= '%W'; 634 break; 635 636 default: 637 638 if ($ch == '\\') { 639 $i++; 640 $ch = substr($fmt,$i,1); 641 } 642 $s .= $ch; 643 break; 644 } 645 } 646 $s.="')"; 647 if ($concat) $s = "CONCAT($s)"; 648 return $s; 649 } 650 651 /** 652 * Returns a database-specific concatenation of strings. 653 * 654 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:concat 655 * 656 * @return string 657 */ 658 function Concat() 659 { 660 $arr = func_get_args(); 661 662 // suggestion by andrew005@mnogo.ru 663 $s = implode(',',$arr); 664 if (strlen($s) > 0) return "CONCAT($s)"; 665 else return ''; 666 } 667 668 /** 669 * Creates a portable date offset field, for use in SQL statements. 670 * 671 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:offsetdate 672 * 673 * @param float $dayFraction A day in floating point 674 * @param string|bool $date (Optional) The date to offset. If false, uses CURDATE() 675 * 676 * @return string 677 */ 678 function OffsetDate($dayFraction, $date = false) 679 { 680 if (!$date) $date = $this->sysDate; 681 682 $fraction = $dayFraction * 24 * 3600; 683 return $date . ' + INTERVAL ' . $fraction.' SECOND'; 684 685 // return "from_unixtime(unix_timestamp($date)+$fraction)"; 686 } 687 688 /** 689 * Returns information about stored procedures and stored functions. 690 * 691 * @param string|bool $NamePattern (Optional) Only look for procedures/functions with a name matching this pattern. 692 * @param null $catalog (Optional) Unused. 693 * @param null $schemaPattern (Optional) Unused. 694 * 695 * @return array 696 */ 697 function MetaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null) 698 { 699 // save old fetch mode 700 global $ADODB_FETCH_MODE; 701 702 $save = $ADODB_FETCH_MODE; 703 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 704 705 if ($this->fetchMode !== FALSE) { 706 $savem = $this->setFetchMode(FALSE); 707 } 708 709 $procedures = array (); 710 711 // get index details 712 713 $likepattern = ''; 714 if ($NamePattern) { 715 $likepattern = " LIKE '".$NamePattern."'"; 716 } 717 $rs = $this->execute('SHOW PROCEDURE STATUS'.$likepattern); 718 if (is_object($rs)) { 719 720 // parse index data into array 721 while ($row = $rs->fetchRow()) { 722 $procedures[$row[1]] = array( 723 'type' => 'PROCEDURE', 724 'catalog' => '', 725 'schema' => '', 726 'remarks' => $row[7], 727 ); 728 } 729 } 730 731 $rs = $this->execute('SHOW FUNCTION STATUS'.$likepattern); 732 if (is_object($rs)) { 733 // parse index data into array 734 while ($row = $rs->fetchRow()) { 735 $procedures[$row[1]] = array( 736 'type' => 'FUNCTION', 737 'catalog' => '', 738 'schema' => '', 739 'remarks' => $row[7] 740 ); 741 } 742 } 743 744 // restore fetchmode 745 if (isset($savem)) { 746 $this->setFetchMode($savem); 747 } 748 $ADODB_FETCH_MODE = $save; 749 750 return $procedures; 751 } 752 753 /** 754 * Retrieves a list of tables based on given criteria 755 * 756 * @param string|bool $ttype (Optional) Table type = 'TABLE', 'VIEW' or false=both (default) 757 * @param string|bool $showSchema (Optional) schema name, false = current schema (default) 758 * @param string|bool $mask (Optional) filters the table by name 759 * 760 * @return array list of tables 761 */ 762 function MetaTables($ttype = false, $showSchema = false, $mask = false) 763 { 764 $save = $this->metaTablesSQL; 765 if ($showSchema && is_string($showSchema)) { 766 $this->metaTablesSQL .= $this->qstr($showSchema); 767 } else { 768 $this->metaTablesSQL .= "schema()"; 769 } 770 771 if ($mask) { 772 $mask = $this->qstr($mask); 773 $this->metaTablesSQL .= " AND table_name LIKE $mask"; 774 } 775 $ret = ADOConnection::metaTables($ttype,$showSchema); 776 777 $this->metaTablesSQL = $save; 778 return $ret; 779 } 780 781 /** 782 * Return information about a table's foreign keys. 783 * 784 * @param string $table The name of the table to get the foreign keys for. 785 * @param string|bool $owner (Optional) The database the table belongs to, or false to assume the current db. 786 * @param string|bool $upper (Optional) Force uppercase table name on returned array keys. 787 * @param bool $associative (Optional) Whether to return an associate or numeric array. 788 * 789 * @return array|bool An array of foreign keys, or false no foreign keys could be found. 790 */ 791 function MetaForeignKeys($table, $owner = false, $upper = false, $associative = false) 792 { 793 794 global $ADODB_FETCH_MODE; 795 796 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC 797 || $this->fetchMode == ADODB_FETCH_ASSOC) 798 $associative = true; 799 800 $savem = $ADODB_FETCH_MODE; 801 $this->setFetchMode(ADODB_FETCH_ASSOC); 802 803 if ( !empty($owner) ) { 804 $table = "$owner.$table"; 805 } 806 807 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); 808 809 $this->setFetchMode($savem); 810 811 $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"]; 812 813 $matches = array(); 814 815 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; 816 $foreign_keys = array(); 817 $num_keys = count($matches[0]); 818 for ( $i = 0; $i < $num_keys; $i ++ ) { 819 $my_field = explode('`, `', $matches[1][$i]); 820 $ref_table = $matches[2][$i]; 821 $ref_field = explode('`, `', $matches[3][$i]); 822 823 if ( $upper ) { 824 $ref_table = strtoupper($ref_table); 825 } 826 827 // see https://sourceforge.net/p/adodb/bugs/100/ 828 if (!isset($foreign_keys[$ref_table])) { 829 $foreign_keys[$ref_table] = array(); 830 } 831 $num_fields = count($my_field); 832 for ( $j = 0; $j < $num_fields; $j ++ ) { 833 if ( $associative ) { 834 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; 835 } else { 836 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; 837 } 838 } 839 } 840 841 return $foreign_keys; 842 } 843 844 /** 845 * Return an array of information about a table's columns. 846 * 847 * @param string $table The name of the table to get the column info for. 848 * @param bool $normalize (Optional) Unused. 849 * 850 * @return ADOFieldObject[]|bool An array of info for each column, or false if it could not determine the info. 851 */ 852 function MetaColumns($table, $normalize = true) 853 { 854 $false = false; 855 if (!$this->metaColumnsSQL) 856 return $false; 857 858 global $ADODB_FETCH_MODE; 859 $save = $ADODB_FETCH_MODE; 860 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 861 if ($this->fetchMode !== false) 862 $savem = $this->SetFetchMode(false); 863 /* 864 * Return assoc array where key is column name, value is column type 865 * [1] => int unsigned 866 */ 867 868 $SQL = "SELECT column_name, column_type 869 FROM information_schema.columns 870 WHERE table_schema='{$this->databaseName}' 871 AND table_name='$table'"; 872 873 $schemaArray = $this->getAssoc($SQL); 874 $schemaArray = array_change_key_case($schemaArray,CASE_LOWER); 875 876 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 877 if (isset($savem)) $this->SetFetchMode($savem); 878 $ADODB_FETCH_MODE = $save; 879 if (!is_object($rs)) 880 return $false; 881 882 $retarr = array(); 883 while (!$rs->EOF) { 884 $fld = new ADOFieldObject(); 885 $fld->name = $rs->fields[0]; 886 $type = $rs->fields[1]; 887 888 /* 889 * Type from information_schema returns 890 * the same format in V8 mysql as V5 891 */ 892 $type = $schemaArray[strtolower($fld->name)]; 893 894 // split type into type(length): 895 $fld->scale = null; 896 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { 897 $fld->type = $query_array[1]; 898 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 899 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; 900 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { 901 $fld->type = $query_array[1]; 902 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 903 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { 904 $fld->type = $query_array[1]; 905 $arr = explode(",",$query_array[2]); 906 $fld->enums = $arr; 907 $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 908 $fld->max_length = ($zlen > 0) ? $zlen : 1; 909 } else { 910 $fld->type = $type; 911 $fld->max_length = -1; 912 } 913 914 $fld->not_null = ($rs->fields[2] != 'YES'); 915 $fld->primary_key = ($rs->fields[3] == 'PRI'); 916 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); 917 $fld->binary = (strpos($type,'blob') !== false); 918 $fld->unsigned = (strpos($type,'unsigned') !== false); 919 $fld->zerofill = (strpos($type,'zerofill') !== false); 920 921 if (!$fld->binary) { 922 $d = $rs->fields[4]; 923 if ($d != '' && $d != 'NULL') { 924 $fld->has_default = true; 925 $fld->default_value = $d; 926 } else { 927 $fld->has_default = false; 928 } 929 } 930 931 if ($save == ADODB_FETCH_NUM) { 932 $retarr[] = $fld; 933 } else { 934 $retarr[strtoupper($fld->name)] = $fld; 935 } 936 $rs->moveNext(); 937 } 938 939 $rs->close(); 940 return $retarr; 941 } 942 943 /** 944 * Select which database to connect to. 945 * 946 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:selectdb 947 * 948 * @param string $dbName The name of the database to select. 949 * 950 * @return bool True if the database was selected successfully, otherwise false. 951 */ 952 function SelectDB($dbName) 953 { 954 // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); 955 $this->database = $dbName; 956 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 957 958 if ($this->_connectionID) { 959 $result = @mysqli_select_db($this->_connectionID, $dbName); 960 if (!$result) { 961 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->errorMsg()); 962 } 963 return $result; 964 } 965 return false; 966 } 967 968 /** 969 * Executes a provided SQL statement and returns a handle to the result, with the ability to supply a starting 970 * offset and record count. 971 * 972 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:selectlimit 973 * 974 * @param string $sql The SQL to execute. 975 * @param int $nrows (Optional) The limit for the number of records you want returned. By default, all results. 976 * @param int $offset (Optional) The offset to use when selecting the results. By default, no offset. 977 * @param array|bool $inputarr (Optional) Any parameter values required by the SQL statement, or false if none. 978 * @param int $secs (Optional) If greater than 0, perform a cached execute. By default, normal execution. 979 * 980 * @return ADORecordSet|false The query results, or false if the query failed to execute. 981 */ 982 function SelectLimit($sql, 983 $nrows = -1, 984 $offset = -1, 985 $inputarr = false, 986 $secs = 0) 987 { 988 $nrows = (int) $nrows; 989 $offset = (int) $offset; 990 $offsetStr = ($offset >= 0) ? "$offset," : ''; 991 if ($nrows < 0) $nrows = '18446744073709551615'; 992 993 if ($secs) 994 $rs = $this->cacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr ); 995 else 996 $rs = $this->execute($sql . " LIMIT $offsetStr$nrows" , $inputarr ); 997 998 return $rs; 999 } 1000 1001 /** 1002 * Prepares an SQL statement and returns a handle to use. 1003 * 1004 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:prepare 1005 * @todo update this function to handle prepared statements correctly 1006 * 1007 * @param string $sql The SQL to prepare. 1008 * 1009 * @return string The original SQL that was provided. 1010 */ 1011 function Prepare($sql) 1012 { 1013 /* 1014 * Flag the insert_id method to use the correct retrieval method 1015 */ 1016 $this->usePreparedStatement = true; 1017 1018 /* 1019 * Prepared statements are not yet handled correctly 1020 */ 1021 return $sql; 1022 $stmt = $this->_connectionID->prepare($sql); 1023 if (!$stmt) { 1024 echo $this->errorMsg(); 1025 return $sql; 1026 } 1027 return array($sql,$stmt); 1028 } 1029 1030 /** 1031 * Return the query id. 1032 * 1033 * @param string|array $sql 1034 * @param array $inputarr 1035 * 1036 * @return bool|mysqli_result 1037 */ 1038 function _query($sql, $inputarr) 1039 { 1040 global $ADODB_COUNTRECS; 1041 // Move to the next recordset, or return false if there is none. In a stored proc 1042 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 1043 // returns false. I think this is because the last "recordset" is actually just the 1044 // return value of the stored proc (ie the number of rows affected). 1045 // Commented out for reasons of performance. You should retrieve every recordset yourself. 1046 // if (!mysqli_next_result($this->connection->_connectionID)) return false; 1047 1048 if (is_array($sql)) { 1049 1050 // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but 1051 // returns as bound variables. 1052 1053 $stmt = $sql[1]; 1054 $a = ''; 1055 foreach($inputarr as $k => $v) { 1056 if (is_string($v)) $a .= 's'; 1057 else if (is_integer($v)) $a .= 'i'; 1058 else $a .= 'd'; 1059 } 1060 1061 /* 1062 * set prepared statement flags 1063 */ 1064 if ($this->usePreparedStatement) 1065 $this->useLastInsertStatement = true; 1066 1067 $fnarr = array_merge( array($stmt,$a) , $inputarr); 1068 call_user_func_array('mysqli_stmt_bind_param',$fnarr); 1069 $ret = mysqli_stmt_execute($stmt); 1070 return $ret; 1071 } 1072 else 1073 { 1074 /* 1075 * reset prepared statement flags, in case we set them 1076 * previously and didn't use them 1077 */ 1078 $this->usePreparedStatement = false; 1079 $this->useLastInsertStatement = false; 1080 } 1081 1082 /* 1083 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { 1084 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->errorMsg()); 1085 return false; 1086 } 1087 1088 return $mysql_res; 1089 */ 1090 1091 if ($this->multiQuery) { 1092 $rs = mysqli_multi_query($this->_connectionID, $sql.';'); 1093 if ($rs) { 1094 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID ); 1095 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID ) 1096 } 1097 } else { 1098 $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); 1099 1100 if ($rs) return $rs; 1101 } 1102 1103 if($this->debug) 1104 ADOConnection::outp("Query: " . $sql . " failed. " . $this->errorMsg()); 1105 1106 return false; 1107 1108 } 1109 1110 /** 1111 * Returns a database specific error message. 1112 * 1113 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:errormsg 1114 * 1115 * @return string The last error message. 1116 */ 1117 function ErrorMsg() 1118 { 1119 if (empty($this->_connectionID)) 1120 $this->_errorMsg = @mysqli_connect_error(); 1121 else 1122 $this->_errorMsg = @mysqli_error($this->_connectionID); 1123 return $this->_errorMsg; 1124 } 1125 1126 /** 1127 * Returns the last error number from previous database operation. 1128 * 1129 * @return int The last error number. 1130 */ 1131 function ErrorNo() 1132 { 1133 if (empty($this->_connectionID)) 1134 return @mysqli_connect_errno(); 1135 else 1136 return @mysqli_errno($this->_connectionID); 1137 } 1138 1139 /** 1140 * Close the database connection. 1141 * 1142 * @return void 1143 */ 1144 function _close() 1145 { 1146 if($this->_connectionID) { 1147 mysqli_close($this->_connectionID); 1148 } 1149 $this->_connectionID = false; 1150 } 1151 1152 /** 1153 * Returns the largest length of data that can be inserted into a character field. 1154 * 1155 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:charmax 1156 * 1157 * @return int 1158 */ 1159 function CharMax() 1160 { 1161 return 255; 1162 } 1163 1164 /** 1165 * Returns the largest length of data that can be inserted into a text field. 1166 * 1167 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:textmax 1168 * 1169 * @return int 1170 */ 1171 function TextMax() 1172 { 1173 return 4294967295; 1174 } 1175 1176 /** 1177 * Get the name of the character set the client connection is using now. 1178 * 1179 * @return string|bool The name of the character set, or false if it can't be determined. 1180 */ 1181 function GetCharSet() 1182 { 1183 //we will use ADO's builtin property charSet 1184 if (!method_exists($this->_connectionID,'character_set_name')) 1185 return false; 1186 1187 $this->charSet = @$this->_connectionID->character_set_name(); 1188 if (!$this->charSet) { 1189 return false; 1190 } else { 1191 return $this->charSet; 1192 } 1193 } 1194 1195 /** 1196 * Sets the character set for database connections (limited databases). 1197 * 1198 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:setcharset 1199 * 1200 * @param string $charset_name The character set to switch to. 1201 * 1202 * @return bool True if the character set was changed successfully, otherwise false. 1203 */ 1204 function SetCharSet($charset_name) 1205 { 1206 if (!method_exists($this->_connectionID,'set_charset')) { 1207 return false; 1208 } 1209 1210 if ($this->charSet !== $charset_name) { 1211 $if = @$this->_connectionID->set_charset($charset_name); 1212 return ($if === true & $this->getCharSet() == $charset_name); 1213 } else { 1214 return true; 1215 } 1216 } 1217 1218 } 1219 1220 /** 1221 * Class ADORecordSet_mysqli 1222 */ 1223 class ADORecordSet_mysqli extends ADORecordSet{ 1224 1225 var $databaseType = "mysqli"; 1226 var $canSeek = true; 1227 1228 function __construct($queryID, $mode = false) 1229 { 1230 if ($mode === false) { 1231 global $ADODB_FETCH_MODE; 1232 $mode = $ADODB_FETCH_MODE; 1233 } 1234 1235 switch ($mode) { 1236 case ADODB_FETCH_NUM: 1237 $this->fetchMode = MYSQLI_NUM; 1238 break; 1239 case ADODB_FETCH_ASSOC: 1240 $this->fetchMode = MYSQLI_ASSOC; 1241 break; 1242 case ADODB_FETCH_DEFAULT: 1243 case ADODB_FETCH_BOTH: 1244 default: 1245 $this->fetchMode = MYSQLI_BOTH; 1246 break; 1247 } 1248 $this->adodbFetchMode = $mode; 1249 parent::__construct($queryID); 1250 } 1251 1252 function _initrs() 1253 { 1254 global $ADODB_COUNTRECS; 1255 1256 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; 1257 $this->_numOfFields = @mysqli_num_fields($this->_queryID); 1258 } 1259 1260 /* 1261 1 = MYSQLI_NOT_NULL_FLAG 1262 2 = MYSQLI_PRI_KEY_FLAG 1263 4 = MYSQLI_UNIQUE_KEY_FLAG 1264 8 = MYSQLI_MULTIPLE_KEY_FLAG 1265 16 = MYSQLI_BLOB_FLAG 1266 32 = MYSQLI_UNSIGNED_FLAG 1267 64 = MYSQLI_ZEROFILL_FLAG 1268 128 = MYSQLI_BINARY_FLAG 1269 256 = MYSQLI_ENUM_FLAG 1270 512 = MYSQLI_AUTO_INCREMENT_FLAG 1271 1024 = MYSQLI_TIMESTAMP_FLAG 1272 2048 = MYSQLI_SET_FLAG 1273 32768 = MYSQLI_NUM_FLAG 1274 16384 = MYSQLI_PART_KEY_FLAG 1275 32768 = MYSQLI_GROUP_FLAG 1276 65536 = MYSQLI_UNIQUE_FLAG 1277 131072 = MYSQLI_BINCMP_FLAG 1278 */ 1279 1280 /** 1281 * Returns raw, database specific information about a field. 1282 * 1283 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:recordset:fetchfield 1284 * 1285 * @param int $fieldOffset (Optional) The field number to get information for. 1286 * 1287 * @return ADOFieldObject|bool 1288 */ 1289 function FetchField($fieldOffset = -1) 1290 { 1291 $fieldnr = $fieldOffset; 1292 if ($fieldOffset != -1) { 1293 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr); 1294 } 1295 $o = @mysqli_fetch_field($this->_queryID); 1296 if (!$o) return false; 1297 1298 //Fix for HHVM 1299 if ( !isset($o->flags) ) { 1300 $o->flags = 0; 1301 } 1302 /* Properties of an ADOFieldObject as set by MetaColumns */ 1303 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; 1304 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; 1305 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; 1306 $o->binary = $o->flags & MYSQLI_BINARY_FLAG; 1307 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ 1308 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; 1309 1310 /* 1311 * Trivial method to cast class to ADOfieldObject 1312 */ 1313 $a = new ADOFieldObject; 1314 foreach (get_object_vars($o) as $key => $name) 1315 $a->$key = $name; 1316 return $a; 1317 } 1318 1319 /** 1320 * Reads a row in associative mode if the recordset fetch mode is numeric. 1321 * Using this function when the fetch mode is set to ADODB_FETCH_ASSOC may produce unpredictable results. 1322 * 1323 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:getrowassoc 1324 * 1325 * @param int $upper Indicates whether the keys of the recordset should be upper case or lower case. 1326 * 1327 * @return array|bool 1328 */ 1329 function GetRowAssoc($upper = ADODB_ASSOC_CASE) 1330 { 1331 if ($this->fetchMode == MYSQLI_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) { 1332 return $this->fields; 1333 } 1334 $row = ADORecordSet::getRowAssoc($upper); 1335 return $row; 1336 } 1337 1338 /** 1339 * Returns a single field in a single row of the current recordset. 1340 * 1341 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:recordset:fields 1342 * 1343 * @param string $colname The name of the field to retrieve. 1344 * 1345 * @return mixed 1346 */ 1347 function Fields($colname) 1348 { 1349 if ($this->fetchMode != MYSQLI_NUM) { 1350 return @$this->fields[$colname]; 1351 } 1352 1353 if (!$this->bind) { 1354 $this->bind = array(); 1355 for ($i = 0; $i < $this->_numOfFields; $i++) { 1356 $o = $this->fetchField($i); 1357 $this->bind[strtoupper($o->name)] = $i; 1358 } 1359 } 1360 return $this->fields[$this->bind[strtoupper($colname)]]; 1361 } 1362 1363 /** 1364 * Adjusts the result pointer to an arbitrary row in the result. 1365 * 1366 * @param int $row The row to seek to. 1367 * 1368 * @return bool False if the recordset contains no rows, otherwise true. 1369 */ 1370 function _seek($row) 1371 { 1372 if ($this->_numOfRows == 0 || $row < 0) { 1373 return false; 1374 } 1375 1376 mysqli_data_seek($this->_queryID, $row); 1377 $this->EOF = false; 1378 return true; 1379 } 1380 1381 /** 1382 * In databases that allow accessing of recordsets, retrieves the next set. 1383 * 1384 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:recordset:nextrecordset 1385 * 1386 * @return bool 1387 */ 1388 function NextRecordSet() 1389 { 1390 global $ADODB_COUNTRECS; 1391 1392 mysqli_free_result($this->_queryID); 1393 $this->_queryID = -1; 1394 // Move to the next recordset, or return false if there is none. In a stored proc 1395 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 1396 // returns false. I think this is because the last "recordset" is actually just the 1397 // return value of the stored proc (ie the number of rows affected). 1398 if (!mysqli_next_result($this->connection->_connectionID)) { 1399 return false; 1400 } 1401 1402 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using 1403 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result($this->connection->_connectionID) 1404 : @mysqli_use_result($this->connection->_connectionID); 1405 1406 if (!$this->_queryID) { 1407 return false; 1408 } 1409 1410 $this->_inited = false; 1411 $this->bind = false; 1412 $this->_currentRow = -1; 1413 $this->init(); 1414 return true; 1415 } 1416 1417 /** 1418 * Moves the cursor to the next record of the recordset from the current position. 1419 * 1420 * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:movenext 1421 * 1422 * @return bool False if there are no more records to move on to, otherwise true. 1423 */ 1424 function MoveNext() 1425 { 1426 if ($this->EOF) return false; 1427 $this->_currentRow++; 1428 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); 1429 1430 if (is_array($this->fields)) { 1431 $this->_updatefields(); 1432 return true; 1433 } 1434 $this->EOF = true; 1435 return false; 1436 } 1437 1438 /** 1439 * Attempt to fetch a result row using the current fetch mode and return whether or not this was successful. 1440 * 1441 * @return bool True if row was fetched successfully, otherwise false. 1442 */ 1443 function _fetch() 1444 { 1445 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); 1446 $this->_updatefields(); 1447 return is_array($this->fields); 1448 } 1449 1450 /** 1451 * Frees the memory associated with a result. 1452 * 1453 * @return void 1454 */ 1455 function _close() 1456 { 1457 //if results are attached to this pointer from Stored Procedure calls, the next standard query will die 2014 1458 //only a problem with persistent connections 1459 1460 if (isset($this->connection->_connectionID) && $this->connection->_connectionID) { 1461 while (mysqli_more_results($this->connection->_connectionID)) { 1462 mysqli_next_result($this->connection->_connectionID); 1463 } 1464 } 1465 1466 if ($this->_queryID instanceof mysqli_result) { 1467 mysqli_free_result($this->_queryID); 1468 } 1469 $this->_queryID = false; 1470 } 1471 1472 /* 1473 1474 0 = MYSQLI_TYPE_DECIMAL 1475 1 = MYSQLI_TYPE_CHAR 1476 1 = MYSQLI_TYPE_TINY 1477 2 = MYSQLI_TYPE_SHORT 1478 3 = MYSQLI_TYPE_LONG 1479 4 = MYSQLI_TYPE_FLOAT 1480 5 = MYSQLI_TYPE_DOUBLE 1481 6 = MYSQLI_TYPE_NULL 1482 7 = MYSQLI_TYPE_TIMESTAMP 1483 8 = MYSQLI_TYPE_LONGLONG 1484 9 = MYSQLI_TYPE_INT24 1485 10 = MYSQLI_TYPE_DATE 1486 11 = MYSQLI_TYPE_TIME 1487 12 = MYSQLI_TYPE_DATETIME 1488 13 = MYSQLI_TYPE_YEAR 1489 14 = MYSQLI_TYPE_NEWDATE 1490 247 = MYSQLI_TYPE_ENUM 1491 248 = MYSQLI_TYPE_SET 1492 249 = MYSQLI_TYPE_TINY_BLOB 1493 250 = MYSQLI_TYPE_MEDIUM_BLOB 1494 251 = MYSQLI_TYPE_LONG_BLOB 1495 252 = MYSQLI_TYPE_BLOB 1496 253 = MYSQLI_TYPE_VAR_STRING 1497 254 = MYSQLI_TYPE_STRING 1498 255 = MYSQLI_TYPE_GEOMETRY 1499 */ 1500 1501 /** 1502 * Get the MetaType character for a given field type. 1503 * 1504 * @param string|object $t The type to get the MetaType character for. 1505 * @param int $len (Optional) Redundant. Will always be set to -1. 1506 * @param bool|object $fieldobj (Optional) 1507 * 1508 * @return string The MetaType 1509 */ 1510 function MetaType($t, $len = -1, $fieldobj = false) 1511 { 1512 if (is_object($t)) { 1513 $fieldobj = $t; 1514 $t = $fieldobj->type; 1515 $len = $fieldobj->max_length; 1516 } 1517 1518 $len = -1; // mysql max_length is not accurate 1519 switch (strtoupper($t)) { 1520 case 'STRING': 1521 case 'CHAR': 1522 case 'VARCHAR': 1523 case 'TINYBLOB': 1524 case 'TINYTEXT': 1525 case 'ENUM': 1526 case 'SET': 1527 1528 case MYSQLI_TYPE_TINY_BLOB : 1529 // case MYSQLI_TYPE_CHAR : 1530 case MYSQLI_TYPE_STRING : 1531 case MYSQLI_TYPE_ENUM : 1532 case MYSQLI_TYPE_SET : 1533 case 253 : 1534 if ($len <= $this->blobSize) { 1535 return 'C'; 1536 } 1537 1538 case 'TEXT': 1539 case 'LONGTEXT': 1540 case 'MEDIUMTEXT': 1541 return 'X'; 1542 1543 // php_mysql extension always returns 'blob' even if 'text' 1544 // so we have to check whether binary... 1545 case 'IMAGE': 1546 case 'LONGBLOB': 1547 case 'BLOB': 1548 case 'MEDIUMBLOB': 1549 1550 case MYSQLI_TYPE_BLOB : 1551 case MYSQLI_TYPE_LONG_BLOB : 1552 case MYSQLI_TYPE_MEDIUM_BLOB : 1553 return !empty($fieldobj->binary) ? 'B' : 'X'; 1554 1555 case 'YEAR': 1556 case 'DATE': 1557 case MYSQLI_TYPE_DATE : 1558 case MYSQLI_TYPE_YEAR : 1559 return 'D'; 1560 1561 case 'TIME': 1562 case 'DATETIME': 1563 case 'TIMESTAMP': 1564 1565 case MYSQLI_TYPE_DATETIME : 1566 case MYSQLI_TYPE_NEWDATE : 1567 case MYSQLI_TYPE_TIME : 1568 case MYSQLI_TYPE_TIMESTAMP : 1569 return 'T'; 1570 1571 case 'INT': 1572 case 'INTEGER': 1573 case 'BIGINT': 1574 case 'TINYINT': 1575 case 'MEDIUMINT': 1576 case 'SMALLINT': 1577 1578 case MYSQLI_TYPE_INT24 : 1579 case MYSQLI_TYPE_LONG : 1580 case MYSQLI_TYPE_LONGLONG : 1581 case MYSQLI_TYPE_SHORT : 1582 case MYSQLI_TYPE_TINY : 1583 if (!empty($fieldobj->primary_key)) { 1584 return 'R'; 1585 } 1586 return 'I'; 1587 1588 // Added floating-point types 1589 // Maybe not necessary. 1590 case 'FLOAT': 1591 case 'DOUBLE': 1592 // case 'DOUBLE PRECISION': 1593 case 'DECIMAL': 1594 case 'DEC': 1595 case 'FIXED': 1596 default: 1597 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1598 return 'N'; 1599 } 1600 } 1601 1602 1603 } // rs class 1604 1605 /** 1606 * Class ADORecordSet_array_mysqli 1607 */ 1608 class ADORecordSet_array_mysqli extends ADORecordSet_array 1609 { 1610 /** 1611 * Get the MetaType character for a given field type. 1612 * 1613 * @param string|object $t The type to get the MetaType character for. 1614 * @param int $len (Optional) Redundant. Will always be set to -1. 1615 * @param bool|object $fieldobj (Optional) 1616 * 1617 * @return string The MetaType 1618 */ 1619 function MetaType($t, $len = -1, $fieldobj = false) 1620 { 1621 if (is_object($t)) { 1622 $fieldobj = $t; 1623 $t = $fieldobj->type; 1624 $len = $fieldobj->max_length; 1625 } 1626 1627 $len = -1; // mysql max_length is not accurate 1628 switch (strtoupper($t)) { 1629 case 'STRING': 1630 case 'CHAR': 1631 case 'VARCHAR': 1632 case 'TINYBLOB': 1633 case 'TINYTEXT': 1634 case 'ENUM': 1635 case 'SET': 1636 1637 case MYSQLI_TYPE_TINY_BLOB : 1638 // case MYSQLI_TYPE_CHAR : 1639 case MYSQLI_TYPE_STRING : 1640 case MYSQLI_TYPE_ENUM : 1641 case MYSQLI_TYPE_SET : 1642 case 253 : 1643 if ($len <= $this->blobSize) { 1644 return 'C'; 1645 } 1646 1647 case 'TEXT': 1648 case 'LONGTEXT': 1649 case 'MEDIUMTEXT': 1650 return 'X'; 1651 1652 // php_mysql extension always returns 'blob' even if 'text' 1653 // so we have to check whether binary... 1654 case 'IMAGE': 1655 case 'LONGBLOB': 1656 case 'BLOB': 1657 case 'MEDIUMBLOB': 1658 1659 case MYSQLI_TYPE_BLOB : 1660 case MYSQLI_TYPE_LONG_BLOB : 1661 case MYSQLI_TYPE_MEDIUM_BLOB : 1662 return !empty($fieldobj->binary) ? 'B' : 'X'; 1663 1664 case 'YEAR': 1665 case 'DATE': 1666 case MYSQLI_TYPE_DATE : 1667 case MYSQLI_TYPE_YEAR : 1668 return 'D'; 1669 1670 case 'TIME': 1671 case 'DATETIME': 1672 case 'TIMESTAMP': 1673 1674 case MYSQLI_TYPE_DATETIME : 1675 case MYSQLI_TYPE_NEWDATE : 1676 case MYSQLI_TYPE_TIME : 1677 case MYSQLI_TYPE_TIMESTAMP : 1678 return 'T'; 1679 1680 case 'INT': 1681 case 'INTEGER': 1682 case 'BIGINT': 1683 case 'TINYINT': 1684 case 'MEDIUMINT': 1685 case 'SMALLINT': 1686 1687 case MYSQLI_TYPE_INT24 : 1688 case MYSQLI_TYPE_LONG : 1689 case MYSQLI_TYPE_LONGLONG : 1690 case MYSQLI_TYPE_SHORT : 1691 case MYSQLI_TYPE_TINY : 1692 if (!empty($fieldobj->primary_key)) { 1693 return 'R'; 1694 } 1695 return 'I'; 1696 1697 // Added floating-point types 1698 // Maybe not necessary. 1699 case 'FLOAT': 1700 case 'DOUBLE': 1701 // case 'DOUBLE PRECISION': 1702 case 'DECIMAL': 1703 case 'DEC': 1704 case 'FIXED': 1705 default: 1706 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1707 return 'N'; 1708 } 1709 } 1710 } 1711 1712 } // if defined _ADODB_MYSQLI_LAYER
title
Description
Body
title
Description
Body
title
Description
Body
title
Body