| [ PHPXref.com ] | [ Generated: Sun Jul 20 20:47:21 2008 ] | [ TPLN 2.6 ] |
| [ Index ] [ Variables ] [ Functions ] [ Classes ] [ Constants ] [ Statistics ] | ||
[Summary view] [Print] [Text view]
1 <?php 2 3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5 /** 6 * The PEAR DB driver for PHP's mysql extension 7 * for interacting with MySQL databases 8 * 9 * PHP versions 4 and 5 10 * 11 * LICENSE: This source file is subject to version 3.0 of the PHP license 12 * that is available through the world-wide-web at the following URI: 13 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 14 * the PHP License and are unable to obtain it through the web, please 15 * send a note to license@php.net so we can mail you a copy immediately. 16 * 17 * @category Database 18 * @package DB 19 * @author Stig Bakken <ssb@php.net> 20 * @author Daniel Convissor <danielc@php.net> 21 * @copyright 1997-2005 The PHP Group 22 * @license http://www.php.net/license/3_0.txt PHP License 3.0 23 * @version CVS: $Id: mysql.php,v 1.117 2005/03/29 15:03:26 danielc Exp $ 24 * @link http://pear.php.net/package/DB 25 */ 26 27 /** 28 * Obtain the DB_common class so it can be extended from 29 */ 30 require_once 'DB/common.php'; 31 32 /** 33 * The methods PEAR DB uses to interact with PHP's mysql extension 34 * for interacting with MySQL databases 35 * 36 * These methods overload the ones declared in DB_common. 37 * 38 * @category Database 39 * @package DB 40 * @author Stig Bakken <ssb@php.net> 41 * @author Daniel Convissor <danielc@php.net> 42 * @copyright 1997-2005 The PHP Group 43 * @license http://www.php.net/license/3_0.txt PHP License 3.0 44 * @version Release: @package_version@ 45 * @link http://pear.php.net/package/DB 46 */ 47 class DB_mysql extends DB_common 48 { 49 // {{{ properties 50 51 /** 52 * The DB driver type (mysql, oci8, odbc, etc.) 53 * @var string 54 */ 55 var $phptype = 'mysql'; 56 57 /** 58 * The database syntax variant to be used (db2, access, etc.), if any 59 * @var string 60 */ 61 var $dbsyntax = 'mysql'; 62 63 /** 64 * The capabilities of this DB implementation 65 * 66 * The 'new_link' element contains the PHP version that first provided 67 * new_link support for this DBMS. Contains false if it's unsupported. 68 * 69 * Meaning of the 'limit' element: 70 * + 'emulate' = emulate with fetch row by number 71 * + 'alter' = alter the query 72 * + false = skip rows 73 * 74 * @var array 75 */ 76 var $features = array( 77 'limit' => 'alter', 78 'new_link' => '4.2.0', 79 'numrows' => true, 80 'pconnect' => true, 81 'prepare' => false, 82 'ssl' => false, 83 'transactions' => true, 84 ); 85 86 /** 87 * A mapping of native error codes to DB error codes 88 * @var array 89 */ 90 var $errorcode_map = array( 91 1004 => DB_ERROR_CANNOT_CREATE, 92 1005 => DB_ERROR_CANNOT_CREATE, 93 1006 => DB_ERROR_CANNOT_CREATE, 94 1007 => DB_ERROR_ALREADY_EXISTS, 95 1008 => DB_ERROR_CANNOT_DROP, 96 1022 => DB_ERROR_ALREADY_EXISTS, 97 1044 => DB_ERROR_ACCESS_VIOLATION, 98 1046 => DB_ERROR_NODBSELECTED, 99 1048 => DB_ERROR_CONSTRAINT, 100 1049 => DB_ERROR_NOSUCHDB, 101 1050 => DB_ERROR_ALREADY_EXISTS, 102 1051 => DB_ERROR_NOSUCHTABLE, 103 1054 => DB_ERROR_NOSUCHFIELD, 104 1061 => DB_ERROR_ALREADY_EXISTS, 105 1062 => DB_ERROR_ALREADY_EXISTS, 106 1064 => DB_ERROR_SYNTAX, 107 1091 => DB_ERROR_NOT_FOUND, 108 1100 => DB_ERROR_NOT_LOCKED, 109 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, 110 1142 => DB_ERROR_ACCESS_VIOLATION, 111 1146 => DB_ERROR_NOSUCHTABLE, 112 1216 => DB_ERROR_CONSTRAINT, 113 1217 => DB_ERROR_CONSTRAINT, 114 ); 115 116 /** 117 * The raw database connection created by PHP 118 * @var resource 119 */ 120 var $connection; 121 122 /** 123 * The DSN information for connecting to a database 124 * @var array 125 */ 126 var $dsn = array(); 127 128 129 /** 130 * Should data manipulation queries be committed automatically? 131 * @var bool 132 * @access private 133 */ 134 var $autocommit = true; 135 136 /** 137 * The quantity of transactions begun 138 * 139 * {@internal While this is private, it can't actually be designated 140 * private in PHP 5 because it is directly accessed in the test suite.}} 141 * 142 * @var integer 143 * @access private 144 */ 145 var $transaction_opcount = 0; 146 147 /** 148 * The database specified in the DSN 149 * 150 * It's a fix to allow calls to different databases in the same script. 151 * 152 * @var string 153 * @access private 154 */ 155 var $_db = ''; 156 157 158 // }}} 159 // {{{ constructor 160 161 /** 162 * This constructor calls <kbd>$this->DB_common()</kbd> 163 * 164 * @return void 165 */ 166 function DB_mysql() 167 { 168 $this->DB_common(); 169 } 170 171 // }}} 172 // {{{ connect() 173 174 /** 175 * Connect to the database server, log in and open the database 176 * 177 * Don't call this method directly. Use DB::connect() instead. 178 * 179 * PEAR DB's mysql driver supports the following extra DSN options: 180 * + new_link If set to true, causes subsequent calls to connect() 181 * to return a new connection link instead of the 182 * existing one. WARNING: this is not portable to 183 * other DBMS's. Available since PEAR DB 1.7.0. 184 * + client_flags Any combination of MYSQL_CLIENT_* constants. 185 * Only used if PHP is at version 4.3.0 or greater. 186 * Available since PEAR DB 1.7.0. 187 * 188 * @param array $dsn the data source name 189 * @param bool $persistent should the connection be persistent? 190 * 191 * @return int DB_OK on success. A DB_Error object on failure. 192 */ 193 function connect($dsn, $persistent = false) 194 { 195 if (!PEAR::loadExtension('mysql')) { 196 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); 197 } 198 199 $this->dsn = $dsn; 200 if ($dsn['dbsyntax']) { 201 $this->dbsyntax = $dsn['dbsyntax']; 202 } 203 204 $params = array(); 205 if ($dsn['protocol'] && $dsn['protocol'] == 'unix') { 206 $params[0] = ':' . $dsn['socket']; 207 } else { 208 $params[0] = $dsn['hostspec'] ? $dsn['hostspec'] 209 : 'localhost'; 210 if ($dsn['port']) { 211 $params[0] .= ':' . $dsn['port']; 212 } 213 } 214 $params[] = $dsn['username'] ? $dsn['username'] : null; 215 $params[] = $dsn['password'] ? $dsn['password'] : null; 216 217 if (!$persistent) { 218 if (isset($dsn['new_link']) 219 && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) 220 { 221 $params[] = true; 222 } else { 223 $params[] = false; 224 } 225 } 226 if (version_compare(phpversion(), '4.3.0', '>=')) { 227 $params[] = isset($dsn['client_flags']) 228 ? $dsn['client_flags'] : null; 229 } 230 231 $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; 232 233 $ini = ini_get('track_errors'); 234 $php_errormsg = ''; 235 if ($ini) { 236 $this->connection = @call_user_func_array($connect_function, 237 $params); 238 } else { 239 ini_set('track_errors', 1); 240 $this->connection = @call_user_func_array($connect_function, 241 $params); 242 ini_set('track_errors', $ini); 243 } 244 245 if (!$this->connection) { 246 if (($err = @mysql_error()) != '') { 247 return $this->raiseError(DB_ERROR_CONNECT_FAILED, 248 null, null, null, 249 $err); 250 } else { 251 return $this->raiseError(DB_ERROR_CONNECT_FAILED, 252 null, null, null, 253 $php_errormsg); 254 } 255 } 256 257 if ($dsn['database']) { 258 if (!@mysql_select_db($dsn['database'], $this->connection)) { 259 return $this->mysqlRaiseError(); 260 } 261 $this->_db = $dsn['database']; 262 } 263 264 return DB_OK; 265 } 266 267 // }}} 268 // {{{ disconnect() 269 270 /** 271 * Disconnects from the database server 272 * 273 * @return bool TRUE on success, FALSE on failure 274 */ 275 function disconnect() 276 { 277 $ret = @mysql_close($this->connection); 278 $this->connection = null; 279 return $ret; 280 } 281 282 // }}} 283 // {{{ simpleQuery() 284 285 /** 286 * Sends a query to the database server 287 * 288 * Generally uses mysql_query(). If you want to use 289 * mysql_unbuffered_query() set the "result_buffering" option to 0 using 290 * setOptions(). This option was added in Release 1.7.0. 291 * 292 * @param string the SQL query string 293 * 294 * @return mixed + a PHP result resrouce for successful SELECT queries 295 * + the DB_OK constant for other successful queries 296 * + a DB_Error object on failure 297 */ 298 function simpleQuery($query) 299 { 300 $ismanip = DB::isManip($query); 301 $this->last_query = $query; 302 $query = $this->modifyQuery($query); 303 if ($this->_db) { 304 if (!@mysql_select_db($this->_db, $this->connection)) { 305 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 306 } 307 } 308 if (!$this->autocommit && $ismanip) { 309 if ($this->transaction_opcount == 0) { 310 $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); 311 $result = @mysql_query('BEGIN', $this->connection); 312 if (!$result) { 313 return $this->mysqlRaiseError(); 314 } 315 } 316 $this->transaction_opcount++; 317 } 318 if (!$this->options['result_buffering']) { 319 $result = @mysql_unbuffered_query($query, $this->connection); 320 } else { 321 $result = @mysql_query($query, $this->connection); 322 } 323 if (!$result) { 324 return $this->mysqlRaiseError(); 325 } 326 if (is_resource($result)) { 327 return $result; 328 } 329 return DB_OK; 330 } 331 332 // }}} 333 // {{{ nextResult() 334 335 /** 336 * Move the internal mysql result pointer to the next available result 337 * 338 * This method has not been implemented yet. 339 * 340 * @param a valid sql result resource 341 * 342 * @return false 343 */ 344 function nextResult($result) 345 { 346 return false; 347 } 348 349 // }}} 350 // {{{ fetchInto() 351 352 /** 353 * Places a row from the result set into the given array 354 * 355 * Formating of the array and the data therein are configurable. 356 * See DB_result::fetchInto() for more information. 357 * 358 * This method is not meant to be called directly. Use 359 * DB_result::fetchInto() instead. It can't be declared "protected" 360 * because DB_result is a separate object. 361 * 362 * @param resource $result the query result resource 363 * @param array $arr the referenced array to put the data in 364 * @param int $fetchmode how the resulting array should be indexed 365 * @param int $rownum the row number to fetch (0 = first row) 366 * 367 * @return mixed DB_OK on success, NULL when the end of a result set is 368 * reached or on failure 369 * 370 * @see DB_result::fetchInto() 371 */ 372 function fetchInto($result, &$arr, $fetchmode, $rownum = null) 373 { 374 if ($rownum !== null) { 375 if (!@mysql_data_seek($result, $rownum)) { 376 return null; 377 } 378 } 379 if ($fetchmode & DB_FETCHMODE_ASSOC) { 380 $arr = @mysql_fetch_array($result, MYSQL_ASSOC); 381 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { 382 $arr = array_change_key_case($arr, CASE_LOWER); 383 } 384 } else { 385 $arr = @mysql_fetch_row($result); 386 } 387 if (!$arr) { 388 return null; 389 } 390 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { 391 /* 392 * Even though this DBMS already trims output, we do this because 393 * a field might have intentional whitespace at the end that 394 * gets removed by DB_PORTABILITY_RTRIM under another driver. 395 */ 396 $this->_rtrimArrayValues($arr); 397 } 398 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { 399 $this->_convertNullArrayValuesToEmpty($arr); 400 } 401 return DB_OK; 402 } 403 404 // }}} 405 // {{{ freeResult() 406 407 /** 408 * Deletes the result set and frees the memory occupied by the result set 409 * 410 * This method is not meant to be called directly. Use 411 * DB_result::free() instead. It can't be declared "protected" 412 * because DB_result is a separate object. 413 * 414 * @param resource $result PHP's query result resource 415 * 416 * @return bool TRUE on success, FALSE if $result is invalid 417 * 418 * @see DB_result::free() 419 */ 420 function freeResult($result) 421 { 422 return @mysql_free_result($result); 423 } 424 425 // }}} 426 // {{{ numCols() 427 428 /** 429 * Gets the number of columns in a result set 430 * 431 * This method is not meant to be called directly. Use 432 * DB_result::numCols() instead. It can't be declared "protected" 433 * because DB_result is a separate object. 434 * 435 * @param resource $result PHP's query result resource 436 * 437 * @return int the number of columns. A DB_Error object on failure. 438 * 439 * @see DB_result::numCols() 440 */ 441 function numCols($result) 442 { 443 $cols = @mysql_num_fields($result); 444 if (!$cols) { 445 return $this->mysqlRaiseError(); 446 } 447 return $cols; 448 } 449 450 // }}} 451 // {{{ numRows() 452 453 /** 454 * Gets the number of rows in a result set 455 * 456 * This method is not meant to be called directly. Use 457 * DB_result::numRows() instead. It can't be declared "protected" 458 * because DB_result is a separate object. 459 * 460 * @param resource $result PHP's query result resource 461 * 462 * @return int the number of rows. A DB_Error object on failure. 463 * 464 * @see DB_result::numRows() 465 */ 466 function numRows($result) 467 { 468 $rows = @mysql_num_rows($result); 469 if ($rows === null) { 470 return $this->mysqlRaiseError(); 471 } 472 return $rows; 473 } 474 475 // }}} 476 // {{{ autoCommit() 477 478 /** 479 * Enables or disables automatic commits 480 * 481 * @param bool $onoff true turns it on, false turns it off 482 * 483 * @return int DB_OK on success. A DB_Error object if the driver 484 * doesn't support auto-committing transactions. 485 */ 486 function autoCommit($onoff = false) 487 { 488 // XXX if $this->transaction_opcount > 0, we should probably 489 // issue a warning here. 490 $this->autocommit = $onoff ? true : false; 491 return DB_OK; 492 } 493 494 // }}} 495 // {{{ commit() 496 497 /** 498 * Commits the current transaction 499 * 500 * @return int DB_OK on success. A DB_Error object on failure. 501 */ 502 function commit() 503 { 504 if ($this->transaction_opcount > 0) { 505 if ($this->_db) { 506 if (!@mysql_select_db($this->_db, $this->connection)) { 507 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 508 } 509 } 510 $result = @mysql_query('COMMIT', $this->connection); 511 $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); 512 $this->transaction_opcount = 0; 513 if (!$result) { 514 return $this->mysqlRaiseError(); 515 } 516 } 517 return DB_OK; 518 } 519 520 // }}} 521 // {{{ rollback() 522 523 /** 524 * Reverts the current transaction 525 * 526 * @return int DB_OK on success. A DB_Error object on failure. 527 */ 528 function rollback() 529 { 530 if ($this->transaction_opcount > 0) { 531 if ($this->_db) { 532 if (!@mysql_select_db($this->_db, $this->connection)) { 533 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 534 } 535 } 536 $result = @mysql_query('ROLLBACK', $this->connection); 537 $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); 538 $this->transaction_opcount = 0; 539 if (!$result) { 540 return $this->mysqlRaiseError(); 541 } 542 } 543 return DB_OK; 544 } 545 546 // }}} 547 // {{{ affectedRows() 548 549 /** 550 * Determines the number of rows affected by a data maniuplation query 551 * 552 * 0 is returned for queries that don't manipulate data. 553 * 554 * @return int the number of rows. A DB_Error object on failure. 555 */ 556 function affectedRows() 557 { 558 if (DB::isManip($this->last_query)) { 559 return @mysql_affected_rows($this->connection); 560 } else { 561 return 0; 562 } 563 } 564 565 // }}} 566 // {{{ nextId() 567 568 /** 569 * Returns the next free id in a sequence 570 * 571 * @param string $seq_name name of the sequence 572 * @param boolean $ondemand when true, the seqence is automatically 573 * created if it does not exist 574 * 575 * @return int the next id number in the sequence. 576 * A DB_Error object on failure. 577 * 578 * @see DB_common::nextID(), DB_common::getSequenceName(), 579 * DB_mysql::createSequence(), DB_mysql::dropSequence() 580 */ 581 function nextId($seq_name, $ondemand = true) 582 { 583 $seqname = $this->getSequenceName($seq_name); 584 do { 585 $repeat = 0; 586 $this->pushErrorHandling(PEAR_ERROR_RETURN); 587 $result = $this->query("UPDATE $seqname} ". 588 'SET id=LAST_INSERT_ID(id+1)'); 589 $this->popErrorHandling(); 590 if ($result === DB_OK) { 591 // COMMON CASE 592 $id = @mysql_insert_id($this->connection); 593 if ($id != 0) { 594 return $id; 595 } 596 // EMPTY SEQ TABLE 597 // Sequence table must be empty for some reason, so fill 598 // it and return 1 and obtain a user-level lock 599 $result = $this->getOne("SELECT GET_LOCK('$seqname}_lock',10)"); 600 if (DB::isError($result)) { 601 return $this->raiseError($result); 602 } 603 if ($result == 0) { 604 // Failed to get the lock 605 return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); 606 } 607 608 // add the default value 609 $result = $this->query("REPLACE INTO $seqname} (id) VALUES (0)"); 610 if (DB::isError($result)) { 611 return $this->raiseError($result); 612 } 613 614 // Release the lock 615 $result = $this->getOne('SELECT RELEASE_LOCK(' 616 . "'$seqname}_lock')"); 617 if (DB::isError($result)) { 618 return $this->raiseError($result); 619 } 620 // We know what the result will be, so no need to try again 621 return 1; 622 623 } elseif ($ondemand && DB::isError($result) && 624 $result->getCode() == DB_ERROR_NOSUCHTABLE) 625 { 626 // ONDEMAND TABLE CREATION 627 $result = $this->createSequence($seq_name); 628 if (DB::isError($result)) { 629 return $this->raiseError($result); 630 } else { 631 $repeat = 1; 632 } 633 634 } elseif (DB::isError($result) && 635 $result->getCode() == DB_ERROR_ALREADY_EXISTS) 636 { 637 // BACKWARDS COMPAT 638 // see _BCsequence() comment 639 $result = $this->_BCsequence($seqname); 640 if (DB::isError($result)) { 641 return $this->raiseError($result); 642 } 643 $repeat = 1; 644 } 645 } while ($repeat); 646 647 return $this->raiseError($result); 648 } 649 650 // }}} 651 // {{{ createSequence() 652 653 /** 654 * Creates a new sequence 655 * 656 * @param string $seq_name name of the new sequence 657 * 658 * @return int DB_OK on success. A DB_Error object on failure. 659 * 660 * @see DB_common::createSequence(), DB_common::getSequenceName(), 661 * DB_mysql::nextID(), DB_mysql::dropSequence() 662 */ 663 function createSequence($seq_name) 664 { 665 $seqname = $this->getSequenceName($seq_name); 666 $res = $this->query('CREATE TABLE ' . $seqname 667 . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' 668 . ' PRIMARY KEY(id))'); 669 if (DB::isError($res)) { 670 return $res; 671 } 672 // insert yields value 1, nextId call will generate ID 2 673 $res = $this->query("INSERT INTO $seqname} (id) VALUES (0)"); 674 if (DB::isError($res)) { 675 return $res; 676 } 677 // so reset to zero 678 return $this->query("UPDATE $seqname} SET id = 0"); 679 } 680 681 // }}} 682 // {{{ dropSequence() 683 684 /** 685 * Deletes a sequence 686 * 687 * @param string $seq_name name of the sequence to be deleted 688 * 689 * @return int DB_OK on success. A DB_Error object on failure. 690 * 691 * @see DB_common::dropSequence(), DB_common::getSequenceName(), 692 * DB_mysql::nextID(), DB_mysql::createSequence() 693 */ 694 function dropSequence($seq_name) 695 { 696 return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); 697 } 698 699 // }}} 700 // {{{ _BCsequence() 701 702 /** 703 * Backwards compatibility with old sequence emulation implementation 704 * (clean up the dupes) 705 * 706 * @param string $seqname the sequence name to clean up 707 * 708 * @return bool true on success. A DB_Error object on failure. 709 * 710 * @access private 711 */ 712 function _BCsequence($seqname) 713 { 714 // Obtain a user-level lock... this will release any previous 715 // application locks, but unlike LOCK TABLES, it does not abort 716 // the current transaction and is much less frequently used. 717 $result = $this->getOne("SELECT GET_LOCK('$seqname}_lock',10)"); 718 if (DB::isError($result)) { 719 return $result; 720 } 721 if ($result == 0) { 722 // Failed to get the lock, can't do the conversion, bail 723 // with a DB_ERROR_NOT_LOCKED error 724 return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); 725 } 726 727 $highest_id = $this->getOne("SELECT MAX(id) FROM $seqname}"); 728 if (DB::isError($highest_id)) { 729 return $highest_id; 730 } 731 // This should kill all rows except the highest 732 // We should probably do something if $highest_id isn't 733 // numeric, but I'm at a loss as how to handle that... 734 $result = $this->query('DELETE FROM ' . $seqname 735 . " WHERE id <> $highest_id"); 736 if (DB::isError($result)) { 737 return $result; 738 } 739 740 // If another thread has been waiting for this lock, 741 // it will go thru the above procedure, but will have no 742 // real effect 743 $result = $this->getOne("SELECT RELEASE_LOCK('$seqname}_lock')"); 744 if (DB::isError($result)) { 745 return $result; 746 } 747 return true; 748 } 749 750 // }}} 751 // {{{ quoteIdentifier() 752 753 /** 754 * Quotes a string so it can be safely used as a table or column name 755 * 756 * MySQL can't handle the backtick character (<kbd>`</kbd>) in 757 * table or column names. 758 * 759 * @param string $str identifier name to be quoted 760 * 761 * @return string quoted identifier string 762 * 763 * @see DB_common::quoteIdentifier() 764 * @since Method available since Release 1.6.0 765 */ 766 function quoteIdentifier($str) 767 { 768 return '`' . $str . '`'; 769 } 770 771 // }}} 772 // {{{ quote() 773 774 /** 775 * @deprecated Deprecated in release 1.6.0 776 */ 777 function quote($str) 778 { 779 return $this->quoteSmart($str); 780 } 781 782 // }}} 783 // {{{ escapeSimple() 784 785 /** 786 * Escapes a string according to the current DBMS's standards 787 * 788 * @param string $str the string to be escaped 789 * 790 * @return string the escaped string 791 * 792 * @see DB_common::quoteSmart() 793 * @since Method available since Release 1.6.0 794 */ 795 function escapeSimple($str) 796 { 797 if (function_exists('mysql_real_escape_string')) { 798 return @mysql_real_escape_string($str, $this->connection); 799 } else { 800 return @mysql_escape_string($str); 801 } 802 } 803 804 // }}} 805 // {{{ modifyQuery() 806 807 /** 808 * Changes a query string for various DBMS specific reasons 809 * 810 * This little hack lets you know how many rows were deleted 811 * when running a "DELETE FROM table" query. Only implemented 812 * if the DB_PORTABILITY_DELETE_COUNT portability option is on. 813 * 814 * @param string $query the query string to modify 815 * 816 * @return string the modified query string 817 * 818 * @access protected 819 * @see DB_common::setOption() 820 */ 821 function modifyQuery($query) 822 { 823 if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { 824 // "DELETE FROM table" gives 0 affected rows in MySQL. 825 // This little hack lets you know how many rows were deleted. 826 if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { 827 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', 828 'DELETE FROM \1 WHERE 1=1', $query); 829 } 830 } 831 return $query; 832 } 833 834 // }}} 835 // {{{ modifyLimitQuery() 836 837 /** 838 * Adds LIMIT clauses to a query string according to current DBMS standards 839 * 840 * @param string $query the query to modify 841 * @param int $from the row to start to fetching (0 = the first row) 842 * @param int $count the numbers of rows to fetch 843 * @param mixed $params array, string or numeric data to be used in 844 * execution of the statement. Quantity of items 845 * passed must match quantity of placeholders in 846 * query: meaning 1 placeholder for non-array 847 * parameters or 1 placeholder per array element. 848 * 849 * @return string the query string with LIMIT clauses added 850 * 851 * @access protected 852 */ 853 function modifyLimitQuery($query, $from, $count, $params = array()) 854 { 855 if (DB::isManip($query)) { 856 return $query . " LIMIT $count"; 857 } else { 858 return $query . " LIMIT $from, $count"; 859 } 860 } 861 862 // }}} 863 // {{{ mysqlRaiseError() 864 865 /** 866 * Produces a DB_Error object regarding the current problem 867 * 868 * @param int $errno if the error is being manually raised pass a 869 * DB_ERROR* constant here. If this isn't passed 870 * the error information gathered from the DBMS. 871 * 872 * @return object the DB_Error object 873 * 874 * @see DB_common::raiseError(), 875 * DB_mysql::errorNative(), DB_common::errorCode() 876 */ 877 function mysqlRaiseError($errno = null) 878 { 879 if ($errno === null) { 880 if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { 881 $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; 882 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; 883 $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; 884 } else { 885 // Doing this in case mode changes during runtime. 886 $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; 887 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; 888 $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; 889 } 890 $errno = $this->errorCode(mysql_errno($this->connection)); 891 } 892 return $this->raiseError($errno, null, null, null, 893 @mysql_errno($this->connection) . ' ** ' . 894 @mysql_error($this->connection)); 895 } 896 897 // }}} 898 // {{{ errorNative() 899 900 /** 901 * Gets the DBMS' native error code produced by the last query 902 * 903 * @return int the DBMS' error code 904 */ 905 function errorNative() 906 { 907 return @mysql_errno($this->connection); 908 } 909 910 // }}} 911 // {{{ tableInfo() 912 913 /** 914 * Returns information about a table or a result set 915 * 916 * @param object|string $result DB_result object from a query or a 917 * string containing the name of a table. 918 * While this also accepts a query result 919 * resource identifier, this behavior is 920 * deprecated. 921 * @param int $mode a valid tableInfo mode 922 * 923 * @return array an associative array with the information requested. 924 * A DB_Error object on failure. 925 * 926 * @see DB_common::tableInfo() 927 */ 928 function tableInfo($result, $mode = null) 929 { 930 if (is_string($result)) { 931 /* 932 * Probably received a table name. 933 * Create a result resource identifier. 934 */ 935 $id = @mysql_list_fields($this->dsn['database'], 936 $result, $this->connection); 937 $got_string = true; 938 } elseif (isset($result->result)) { 939 /* 940 * Probably received a result object. 941 * Extract the result resource identifier. 942 */ 943 $id = $result->result; 944 $got_string = false; 945 } else { 946 /* 947 * Probably received a result resource identifier. 948 * Copy it. 949 * Deprecated. Here for compatibility only. 950 */ 951 $id = $result; 952 $got_string = false; 953 } 954 955 if (!is_resource($id)) { 956 return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA); 957 } 958 959 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { 960 $case_func = 'strtolower'; 961 } else { 962 $case_func = 'strval'; 963 } 964 965 $count = @mysql_num_fields($id); 966 $res = array(); 967 968 if ($mode) { 969 $res['num_fields'] = $count; 970 } 971 972 for ($i = 0; $i < $count; $i++) { 973 $res[$i] = array( 974 'table' => $case_func(@mysql_field_table($id, $i)), 975 'name' => $case_func(@mysql_field_name($id, $i)), 976 'type' => @mysql_field_type($id, $i), 977 'len' => @mysql_field_len($id, $i), 978 'flags' => @mysql_field_flags($id, $i), 979 ); 980 if ($mode & DB_TABLEINFO_ORDER) { 981 $res['order'][$res[$i]['name']] = $i; 982 } 983 if ($mode & DB_TABLEINFO_ORDERTABLE) { 984 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 985 } 986 } 987 988 // free the result only if we were called on a table 989 if ($got_string) { 990 @mysql_free_result($id); 991 } 992 return $res; 993 } 994 995 // }}} 996 // {{{ getSpecialQuery() 997 998 /** 999 * Obtains the query string needed for listing a given type of objects 1000 * 1001 * @param string $type the kind of objects you want to retrieve 1002 * 1003 * @return string the SQL query string or null if the driver doesn't 1004 * support the object type requested 1005 * 1006 * @access protected 1007 * @see DB_common::getListOf() 1008 */ 1009 function getSpecialQuery($type) 1010 { 1011 switch ($type) { 1012 case 'tables': 1013 return 'SHOW TABLES'; 1014 case 'users': 1015 return 'SELECT DISTINCT User FROM mysql.user'; 1016 case 'databases': 1017 return 'SHOW DATABASES'; 1018 default: 1019 return null; 1020 } 1021 } 1022 1023 // }}} 1024 1025 } 1026 1027 /* 1028 * Local variables: 1029 * tab-width: 4 1030 * c-basic-offset: 4 1031 * End: 1032 */ 1033 1034 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| [ Powered by PHPXref - Served by Debian GNU/Linux ] |