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