[ Index ] |
|
Code source de PHPonTrax 2.6.6-svn |
1 <?php 2 /** 3 * File for mock DB class 4 * 5 * This file has the same name as the file holding the {@link 6 * http://pear.php.net/package/DB PEAR DB class}. 7 * To use the mock DB, put this file in the PHP include path ahead of 8 * the PEAR library, so that any class which requires DB.php will 9 * load this version. 10 * 11 * (PHP 5) 12 * 13 * @package PHPonTraxTest 14 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 15 * @copyright (c) Walter O. Haas 2006 16 * @version $Id: DB.php 198 2006-04-20 16:20:30Z haas $ 17 * @author Walt Haas <haas@xmission.com> 18 */ 19 20 require_once 'PEAR.php'; 21 require_once 'PHPUnit2/Framework/Assert.php'; 22 23 /** 24 * The code returned by many methods upon success 25 */ 26 define('DB_OK', 1); 27 28 /** 29 * Unkown error 30 */ 31 define('DB_ERROR', -1); 32 33 /** 34 * Syntax error 35 */ 36 define('DB_ERROR_SYNTAX', -2); 37 38 /** 39 * Tried to insert a duplicate value into a primary or unique index 40 */ 41 define('DB_ERROR_CONSTRAINT', -3); 42 43 /** 44 * An identifier in the query refers to a non-existant object 45 */ 46 define('DB_ERROR_NOT_FOUND', -4); 47 48 /** 49 * Tried to create a duplicate object 50 */ 51 define('DB_ERROR_ALREADY_EXISTS', -5); 52 53 /** 54 * The current driver does not support the action you attempted 55 */ 56 define('DB_ERROR_UNSUPPORTED', -6); 57 58 /** 59 * The number of parameters does not match the number of placeholders 60 */ 61 define('DB_ERROR_MISMATCH', -7); 62 63 /** 64 * A literal submitted did not match the data type expected 65 */ 66 define('DB_ERROR_INVALID', -8); 67 68 /** 69 * The current DBMS does not support the action you attempted 70 */ 71 define('DB_ERROR_NOT_CAPABLE', -9); 72 73 /** 74 * A literal submitted was too long so the end of it was removed 75 */ 76 define('DB_ERROR_TRUNCATED', -10); 77 78 /** 79 * A literal number submitted did not match the data type expected 80 */ 81 define('DB_ERROR_INVALID_NUMBER', -11); 82 83 /** 84 * A literal date submitted did not match the data type expected 85 */ 86 define('DB_ERROR_INVALID_DATE', -12); 87 88 /** 89 * Attempt to divide something by zero 90 */ 91 define('DB_ERROR_DIVZERO', -13); 92 93 /** 94 * A database needs to be selected 95 */ 96 define('DB_ERROR_NODBSELECTED', -14); 97 98 /** 99 * Could not create the object requested 100 */ 101 define('DB_ERROR_CANNOT_CREATE', -15); 102 103 /** 104 * Could not drop the database requested because it does not exist 105 */ 106 define('DB_ERROR_CANNOT_DROP', -17); 107 108 /** 109 * An identifier in the query refers to a non-existant table 110 */ 111 define('DB_ERROR_NOSUCHTABLE', -18); 112 113 /** 114 * An identifier in the query refers to a non-existant column 115 */ 116 define('DB_ERROR_NOSUCHFIELD', -19); 117 118 /** 119 * The data submitted to the method was inappropriate 120 */ 121 define('DB_ERROR_NEED_MORE_DATA', -20); 122 123 /** 124 * The attempt to lock the table failed 125 */ 126 define('DB_ERROR_NOT_LOCKED', -21); 127 128 /** 129 * The number of columns doesn't match the number of values 130 */ 131 define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); 132 133 /** 134 * The DSN submitted has problems 135 */ 136 define('DB_ERROR_INVALID_DSN', -23); 137 138 /** 139 * Could not connect to the database 140 */ 141 define('DB_ERROR_CONNECT_FAILED', -24); 142 143 /** 144 * The PHP extension needed for this DBMS could not be found 145 */ 146 define('DB_ERROR_EXTENSION_NOT_FOUND',-25); 147 148 /** 149 * The present user has inadequate permissions to perform the task requestd 150 */ 151 define('DB_ERROR_ACCESS_VIOLATION', -26); 152 153 /** 154 * The database requested does not exist 155 */ 156 define('DB_ERROR_NOSUCHDB', -27); 157 158 /** 159 * Tried to insert a null value into a column that doesn't allow nulls 160 */ 161 define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); 162 163 /** 164 * Identifiers for the placeholders used in prepared statements. 165 * @see prepare() 166 */ 167 168 /** 169 * Indicates a scalar (<kbd>?</kbd>) placeholder was used 170 * 171 * Quote and escape the value as necessary. 172 */ 173 define('DB_PARAM_SCALAR', 1); 174 175 /** 176 * Indicates an opaque (<kbd>&</kbd>) placeholder was used 177 * 178 * The value presented is a file name. Extract the contents of that file 179 * and place them in this column. 180 */ 181 define('DB_PARAM_OPAQUE', 2); 182 183 /** 184 * Indicates a misc (<kbd>!</kbd>) placeholder was used 185 * 186 * The value should not be quoted or escaped. 187 */ 188 define('DB_PARAM_MISC', 3); 189 190 /** 191 * The different ways of returning binary data from queries. 192 */ 193 194 /** 195 * Sends the fetched data straight through to output 196 */ 197 define('DB_BINMODE_PASSTHRU', 1); 198 199 /** 200 * Lets you return data as usual 201 */ 202 define('DB_BINMODE_RETURN', 2); 203 204 /** 205 * Converts the data to hex format before returning it 206 * 207 * For example the string "123" would become "313233". 208 */ 209 define('DB_BINMODE_CONVERT', 3); 210 211 /** 212 * Fetchmode constants 213 */ 214 define('DB_FETCHMODE_DEFAULT', 0); 215 define('DB_FETCHMODE_ORDERED', 1); 216 define('DB_FETCHMODE_ASSOC', 2); 217 define('DB_FETCHMODE_OBJECT', 3); 218 219 /** 220 * For multi-dimensional results, make the column name the first level 221 * of the array and put the row number in the second level of the array 222 * 223 * This is flipped from the normal behavior, which puts the row numbers 224 * in the first level of the array and the column names in the second level. 225 */ 226 define('DB_FETCHMODE_FLIPPED', 4); 227 228 /** 229 * Old fetch modes. Left here for compatibility. 230 */ 231 define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); 232 define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); 233 define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); 234 235 /** 236 * The type of information to return from the tableInfo() method. 237 * 238 * Bitwised constants, so they can be combined using <kbd>|</kbd> 239 * and removed using <kbd>^</kbd>. 240 * 241 * @see tableInfo() 242 */ 243 define('DB_TABLEINFO_ORDER', 1); 244 define('DB_TABLEINFO_ORDERTABLE', 2); 245 define('DB_TABLEINFO_FULL', 3); 246 247 /** 248 * The type of query to create with the automatic query building methods. 249 * @see autoPrepare(), autoExecute() 250 */ 251 define('DB_AUTOQUERY_INSERT', 1); 252 define('DB_AUTOQUERY_UPDATE', 2); 253 254 /** 255 * Portability Modes. 256 * 257 * Bitwised constants, so they can be combined using <kbd>|</kbd> 258 * and removed using <kbd>^</kbd>. 259 * 260 * @see setOption() 261 */ 262 263 /** 264 * Turn off all portability features 265 */ 266 define('DB_PORTABILITY_NONE', 0); 267 268 /** 269 * Convert names of tables and fields to lower case 270 * when using the get*(), fetch*() and tableInfo() methods 271 */ 272 define('DB_PORTABILITY_LOWERCASE', 1); 273 274 /** 275 * Right trim the data output by get*() and fetch*() 276 */ 277 define('DB_PORTABILITY_RTRIM', 2); 278 279 /** 280 * Force reporting the number of rows deleted 281 */ 282 define('DB_PORTABILITY_DELETE_COUNT', 4); 283 284 /** 285 * Enable hack that makes numRows() work in Oracle 286 */ 287 define('DB_PORTABILITY_NUMROWS', 8); 288 289 /** 290 * Makes certain error messages in certain drivers compatible 291 * with those from other DBMS's 292 * 293 * + mysql, mysqli: change unique/primary key constraints 294 * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT 295 * 296 * + odbc(access): MS's ODBC driver reports 'no such field' as code 297 * 07001, which means 'too few parameters.' When this option is on 298 * that code gets mapped to DB_ERROR_NOSUCHFIELD. 299 */ 300 define('DB_PORTABILITY_ERRORS', 16); 301 302 /** 303 * Convert null values to empty strings in data output by 304 * get*() and fetch*() 305 */ 306 define('DB_PORTABILITY_NULL_TO_EMPTY', 32); 307 308 /** 309 * Turn on all portability features 310 */ 311 define('DB_PORTABILITY_ALL', 63); 312 313 /** 314 * Mock DB class for testing 315 * 316 * This class is a mock version of the 317 * {@link http://pear.php.net/package/DB PEAR DB class}. It is 318 * intended to provide the same interface as the real DB class, plus 319 * a small database sufficient to test software. 320 */ 321 322 class DB { 323 324 /** 325 * Create a new DB object for the specified database type but don't 326 * connect to the database 327 * 328 * @param string $type the database type (eg "mysql") 329 * @param array $options an associative array of option names and values 330 * @return object a new DB object. A DB_Error object on failure. 331 * @see DB_common::setOption() 332 * @todo Implement mock DB::factory 333 */ 334 public function &factory($type, $options = false) 335 { 336 // if (!is_array($options)) { 337 // $options = array('persistent' => $options); 338 // } 339 // 340 // if (isset($options['debug']) && $options['debug'] >= 2) { 341 // // expose php errors with sufficient debug level 342 // include_once "DB/{$type}.php"; 343 // } else { 344 // @include_once "DB/{$type}.php"; 345 // } 346 // 347 // $classname = "DB_${type}"; 348 // 349 // if (!class_exists($classname)) { 350 // $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, 351 // "Unable to include the DB/{$type}.php" 352 // . " file for '$dsn'", 353 // 'DB_Error', true); 354 // return $tmp; 355 // } 356 // 357 // @$obj =& new $classname; 358 // 359 // foreach ($options as $option => $value) { 360 // $test = $obj->setOption($option, $value); 361 // if (DB::isError($test)) { 362 // return $test; 363 // } 364 // } 365 // 366 // return $obj; 367 } 368 369 /** 370 * Create a new DB object including a connection to the specified database 371 * 372 * @param mixed $dsn the string "data source name" or array in the 373 * format returned by DB::parseDSN() 374 * @param array $options an associative array of option names and values 375 * @return object a new DB object. A DB_Error object on failure. 376 * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError() 377 * @todo Implement mock DB::connect 378 */ 379 function &connect($dsn, $options = array()) 380 { 381 $dsninfo = DB::parseDSN($dsn); 382 $type = $dsninfo['phptype']; 383 384 // only support MySQL at the moment 385 PHPUnit2_Framework_Assert::assertEquals($type,'mysql'); 386 @$obj =& new DB_mysql; 387 388 foreach ($options as $option => $value) { 389 $test = $obj->setOption($option, $value); 390 if (DB::isError($test)) { 391 return $test; 392 } 393 } 394 395 // $err = $obj->connect($dsninfo, $obj->getOption('persistent')); 396 // if (DB::isError($err)) { 397 // $err->addUserInfo($dsn); 398 // return $err; 399 // } 400 // 401 return $obj; 402 } 403 404 /** 405 * Return the DB API version 406 * 407 * @return string the DB API version number 408 */ 409 function apiVersion() 410 { 411 return '1.7.6'; 412 } 413 414 /** 415 * Determines if a variable is a DB_Error object 416 * 417 * @param mixed $value the variable to check 418 * @return bool whether $value is DB_Error object 419 */ 420 function isError($value) 421 { 422 return is_a($value, 'DB_Error'); 423 } 424 425 /** 426 * Determines if a value is a DB_<driver> object 427 * 428 * @param mixed $value the value to test 429 * @return bool whether $value is a DB_<driver> object 430 * @todo Implement mock DB::isConnection 431 */ 432 function isConnection($value) 433 { 434 // return (is_object($value) && 435 // is_subclass_of($value, 'db_common') && 436 // method_exists($value, 'simpleQuery')); 437 } 438 439 /** 440 * Tell whether a query is a data manipulation or data definition query 441 * 442 * @param string $query the query 443 * @return boolean whether $query is a data manipulation query 444 */ 445 function isManip($query) 446 { 447 $manips = 'INSERT|UPDATE|DELETE|REPLACE|' 448 . 'CREATE|DROP|' 449 . 'LOAD DATA|SELECT .* INTO|COPY|' 450 . 'ALTER|GRANT|REVOKE|' 451 . 'LOCK|UNLOCK'; 452 if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { 453 return true; 454 } 455 return false; 456 } 457 458 /** 459 * Return a textual error message for a DB error code 460 * 461 * @param integer $value the DB error code 462 * @return string the error message or false if the error code was 463 * not recognized 464 * @todo Implement mock DB::errorMessage 465 */ 466 public function errorMessage($value) 467 { 468 static $errorMessages; 469 if (!isset($errorMessages)) { 470 $errorMessages = array( 471 DB_ERROR => 'unknown error', 472 DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', 473 DB_ERROR_ALREADY_EXISTS => 'already exists', 474 DB_ERROR_CANNOT_CREATE => 'can not create', 475 DB_ERROR_CANNOT_DROP => 'can not drop', 476 DB_ERROR_CONNECT_FAILED => 'connect failed', 477 DB_ERROR_CONSTRAINT => 'constraint violation', 478 DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', 479 DB_ERROR_DIVZERO => 'division by zero', 480 DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', 481 DB_ERROR_INVALID => 'invalid', 482 DB_ERROR_INVALID_DATE => 'invalid date or time', 483 DB_ERROR_INVALID_DSN => 'invalid DSN', 484 DB_ERROR_INVALID_NUMBER => 'invalid number', 485 DB_ERROR_MISMATCH => 'mismatch', 486 DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', 487 DB_ERROR_NODBSELECTED => 'no database selected', 488 DB_ERROR_NOSUCHDB => 'no such database', 489 DB_ERROR_NOSUCHFIELD => 'no such field', 490 DB_ERROR_NOSUCHTABLE => 'no such table', 491 DB_ERROR_NOT_CAPABLE => 'DB backend not capable', 492 DB_ERROR_NOT_FOUND => 'not found', 493 DB_ERROR_NOT_LOCKED => 'not locked', 494 DB_ERROR_SYNTAX => 'syntax error', 495 DB_ERROR_UNSUPPORTED => 'not supported', 496 DB_ERROR_TRUNCATED => 'truncated', 497 DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', 498 DB_OK => 'no error', 499 ); 500 } 501 502 // if (DB::isError($value)) { 503 // $value = $value->getCode(); 504 // } 505 // 506 // return isset($errorMessages[$value]) ? $errorMessages[$value] 507 // : $errorMessages[DB_ERROR]; 508 } 509 510 /** 511 * Parse a data source name 512 * 513 * @param string $dsn Data Source Name to be parsed 514 * @return array an associative array with the following keys: 515 * + phptype: Database backend used in PHP (mysql, odbc etc.) 516 * + dbsyntax: Database used with regards to SQL syntax etc. 517 * + protocol: Communication protocol to use (tcp, unix etc.) 518 * + hostspec: Host specification (hostname[:port]) 519 * + database: Database to use on the DBMS server 520 * + username: User name for login 521 * + password: Password for login 522 * @todo Implement mock DB::parseDSN 523 */ 524 public function parseDSN($dsn) 525 { 526 $parsed = array( 527 'phptype' => false, 528 'dbsyntax' => false, 529 'username' => false, 530 'password' => false, 531 'protocol' => false, 532 'hostspec' => false, 533 'port' => false, 534 'socket' => false, 535 'database' => false, 536 ); 537 538 if (is_array($dsn)) { 539 $dsn = array_merge($parsed, $dsn); 540 if (!$dsn['dbsyntax']) { 541 $dsn['dbsyntax'] = $dsn['phptype']; 542 } 543 return $dsn; 544 } 545 546 // Find phptype and dbsyntax 547 if (($pos = strpos($dsn, '://')) !== false) { 548 $str = substr($dsn, 0, $pos); 549 $dsn = substr($dsn, $pos + 3); 550 } else { 551 $str = $dsn; 552 $dsn = null; 553 } 554 555 // Get phptype and dbsyntax 556 // $str => phptype(dbsyntax) 557 if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { 558 $parsed['phptype'] = $arr[1]; 559 $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; 560 } else { 561 $parsed['phptype'] = $str; 562 $parsed['dbsyntax'] = $str; 563 } 564 565 if (!count($dsn)) { 566 return $parsed; 567 } 568 569 // Get (if found): username and password 570 // $dsn => username:password@protocol+hostspec/database 571 if (($at = strrpos($dsn,'@')) !== false) { 572 $str = substr($dsn, 0, $at); 573 $dsn = substr($dsn, $at + 1); 574 if (($pos = strpos($str, ':')) !== false) { 575 $parsed['username'] = rawurldecode(substr($str, 0, $pos)); 576 $parsed['password'] = rawurldecode(substr($str, $pos + 1)); 577 } else { 578 $parsed['username'] = rawurldecode($str); 579 } 580 } 581 582 // Find protocol and hostspec 583 584 if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { 585 // $dsn => proto(proto_opts)/database 586 $proto = $match[1]; 587 $proto_opts = $match[2] ? $match[2] : false; 588 $dsn = $match[3]; 589 590 } else { 591 // $dsn => protocol+hostspec/database (old format) 592 if (strpos($dsn, '+') !== false) { 593 list($proto, $dsn) = explode('+', $dsn, 2); 594 } 595 if (strpos($dsn, '/') !== false) { 596 list($proto_opts, $dsn) = explode('/', $dsn, 2); 597 } else { 598 $proto_opts = $dsn; 599 $dsn = null; 600 } 601 } 602 603 // process the different protocol options 604 $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; 605 $proto_opts = rawurldecode($proto_opts); 606 if ($parsed['protocol'] == 'tcp') { 607 if (strpos($proto_opts, ':') !== false) { 608 list($parsed['hostspec'], 609 $parsed['port']) = explode(':', $proto_opts); 610 } else { 611 $parsed['hostspec'] = $proto_opts; 612 } 613 } elseif ($parsed['protocol'] == 'unix') { 614 $parsed['socket'] = $proto_opts; 615 } 616 617 // Get dabase if any 618 // $dsn => database 619 if ($dsn) { 620 if (($pos = strpos($dsn, '?')) === false) { 621 // /database 622 $parsed['database'] = rawurldecode($dsn); 623 } else { 624 // /database?param1=value1¶m2=value2 625 $parsed['database'] = rawurldecode(substr($dsn, 0, $pos)); 626 $dsn = substr($dsn, $pos + 1); 627 if (strpos($dsn, '&') !== false) { 628 $opts = explode('&', $dsn); 629 } else { // database?param1=value1 630 $opts = array($dsn); 631 } 632 foreach ($opts as $opt) { 633 list($key, $value) = explode('=', $opt); 634 if (!isset($parsed[$key])) { 635 // don't allow params overwrite 636 $parsed[$key] = rawurldecode($value); 637 } 638 } 639 } 640 } 641 642 return $parsed; 643 } 644 } 645 646 /** 647 * Mock DB_common for testing 648 * @todo Implement mock DB_common class 649 */ 650 class DB_common extends PEAR { 651 652 /** 653 * Mock Database 654 */ 655 protected static $database = 656 // Person names table 657 array('person_names' => 658 // Description 659 array('info' => 660 array(array('table' => 'person_names', 661 'name' => 'id', 662 'type' => 'int', 663 'len' => '11', 664 'flags' => 'primary_key not_null'), 665 array('table' => 'person_names', 666 'name' => 'prefix', 667 'type' => 'string', 668 'len' => '20', 669 'flags' => ''), 670 array('table' => 'person_names', 671 'name' => 'first_name', 672 'type' => 'string', 673 'len' => '40', 674 'flags' => ''), 675 array('table' => 'person_names', 676 'name' => 'mi', 677 'type' => 'string', 678 'len' => '1', 679 'flags' => ''), 680 array('table' => 'person_names', 681 'name' => 'last_name', 682 'type' => 'string', 683 'len' => '40', 684 'flags' => ''), 685 array('table' => 'person_names', 686 'name' => 'suffix', 687 'type' => 'string', 688 'len' => '20', 689 'flags' => ''), 690 ), 691 'data' => 692 array() 693 ), 694 695 // Data types table 696 'data_types' => 697 698 // Description 699 array('info' => 700 array(array("table" => "data_types", 701 "name" => "id", 702 "type" => "int", 703 "len" => '11', 704 "flags" => "not_null primary_key auto_increment"), 705 array("table" => "data_types", 706 "name" => "bit_type", 707 "type" => "int", 708 "len" => '1', 709 "flags" => ""), 710 array("table" => "data_types", 711 "name" => "tinyint_type", 712 "type" => "int", 713 "len" => '4', 714 "flags" => ""), 715 array("table" => "data_types", 716 "name" => "bool_type", 717 "type" => "int", 718 "len" => '1', 719 "flags" => ""), 720 array("table" => "data_types", 721 "name" => "boolean_type", 722 "type" => "int", 723 "len" => '1', 724 "flags" => ""), 725 array("table" => "data_types", 726 "name" => "smallint_type", 727 "type" => "int", 728 "len" => '6', 729 "flags" => ""), 730 array("table" => "data_types", 731 "name" => "mediumint_type", 732 "type" => "int", 733 "len" => '9', 734 "flags" => ""), 735 array("table" => "data_types", 736 "name" => "int_type", 737 "type" => "int", 738 "len" => '11', 739 "flags" => ""), 740 array("table" => "data_types", 741 "name" => "integer_type", 742 "type" => "int", 743 "len" => '11', 744 "flags" => ""), 745 array("table" => "data_types", 746 "name" => "bigint_type", 747 "type" => "int", 748 "len" => '20', 749 "flags" => ""), 750 array("table" => "data_types", 751 "name" => "float_type", 752 "type" => "real", 753 "len" => '12', 754 "flags" => ""), 755 array("table" => "data_types", 756 "name" => "double_type", 757 "type" => "real", 758 "len" => '22', 759 "flags" => ""), 760 array("table" => "data_types", 761 "name" => "double_precision_type", 762 "type" => "real", 763 "len" => '22', 764 "flags" => ""), 765 array("table" => "data_types", 766 "name" => "decimal_type", 767 "type" => "real", 768 "len" => '11', 769 "flags" => ""), 770 array("table" => "data_types", 771 "name" => "dec_type", 772 "type" => "real", 773 "len" => '11', 774 "flags" => ""), 775 array("table" => "data_types", 776 "name" => "numeric_type", 777 "type" => "real", 778 "len" => '11', 779 "flags" => ""), 780 array("table" => "data_types", 781 "name" => "fixed_type", 782 "type" => "real", 783 "len" => '11', 784 "flags" => ""), 785 array("table" => "data_types", 786 "name" => "date_type", 787 "type" => "date", 788 "len" => '10', 789 "flags" => "binary"), 790 array("table" => "data_types", 791 "name" => "datetime_type", 792 "type" => "datetime", 793 "len" => '19', 794 "flags" => "binary"), 795 array("table" => "data_types", 796 "name" => "timestamp_type", 797 "type" => "timestamp", 798 "len" => '19', 799 "flags" => "unsigned zerofill binary"), 800 array("table" => "data_types", 801 "name" => "time_type", 802 "type" => "time", 803 "len" => '8', 804 "flags" => "binary"), 805 array("table" => "data_types", 806 "name" => "year_type", 807 "type" => "year", 808 "len" => '4', 809 "flags" => "unsigned zerofill"), 810 array("table" => "data_types", 811 "name" => "char_type", 812 "type" => "string", 813 "len" => '20', 814 "flags" => ""), 815 array("table" => "data_types", 816 "name" => "varchar_type", 817 "type" => "string", 818 "len" => '20', 819 "flags" => ""), 820 array("table" => "data_types", 821 "name" => "nchar_type", 822 "type" => "string", 823 "len" => '20', 824 "flags" => ""), 825 array("table" => "data_types", 826 "name" => "binary_type", 827 "type" => "string", 828 "len" => '20', 829 "flags" => "binary"), 830 array("table" => "data_types", 831 "name" => "varbinary_type", 832 "type" => "string", 833 "len" => '20', 834 "flags" => "binary"), 835 array("table" => "data_types", 836 "name" => "tinyblob_type", 837 "type" => "blob", 838 "len" => '255', 839 "flags" => "blob binary"), 840 array("table" => "data_types", 841 "name" => "tinytext_type", 842 "type" => "blob", 843 "len" => '255', 844 "flags" => "blob"), 845 array("table" => "data_types", 846 "name" => "blob_type", 847 "type" => "blob", 848 "len" => '65535', 849 "flags" => "blob binary"), 850 array("table" => "data_types", 851 "name" => "text_type", 852 "type" => "blob", 853 "len" => '65535', 854 "flags" => "blob"), 855 array("table" => "data_types", 856 "name" => "mediumblob_type", 857 "type" => "blob", 858 "len" => '16777215', 859 "flags" => "blob binary"), 860 array("table" => "data_types", 861 "name" => "mediumtext_type", 862 "type" => "blob", 863 "len" => '16777215', 864 "flags" => "blob"), 865 array("table" => "data_types", 866 "name" => "longblob_type", 867 "type" => "blob", 868 "len" => '-1', 869 "flags" => "blob binary"), 870 array("table" => "data_types", 871 "name" => "longtext_type", 872 "type" => "blob", 873 "len" => '-1', 874 "flags" => "blob"), 875 array("table" => "data_types", 876 "name" => "enum_type", 877 "type" => "string", 878 "len" => '3', 879 "flags" => "enum"), 880 array("table" => "data_types", 881 "name" => "set_type", 882 "type" => "string", 883 "len" => '7', 884 "flags" => "set"), 885 ), 886 'data' => 887 array() 888 ), 889 ); 890 891 /** 892 * Run-time configuration options 893 * 894 * @var array 895 * @see DB_common::setOption() 896 */ 897 var $options = array( 898 'result_buffering' => 500, 899 'persistent' => false, 900 'ssl' => false, 901 'debug' => 0, 902 'seqname_format' => '%s_seq', 903 'autofree' => false, 904 'portability' => DB_PORTABILITY_NONE, 905 'optimize' => 'performance', // Deprecated. Use 'portability'. 906 ); 907 908 /** 909 * List of expected queries and returns 910 */ 911 private $expected_list = null; 912 913 /** 914 * Cursor in list of expected queries and returns 915 */ 916 private $expected_list_cursor = null; 917 918 /** 919 * Expected query 920 * @var string 921 */ 922 private $expected_query = null; 923 924 /** 925 * Result to be returned from expected query 926 * @var string 927 */ 928 private $expected_result = null; 929 930 /** 931 * This constructor calls <kbd>$this->PEAR('DB_Error')</kbd> 932 * 933 * @return void 934 */ 935 function DB_common() 936 { 937 $this->PEAR('DB_Error'); 938 } 939 940 /** 941 * Automatically indicates which properties should be saved 942 * when PHP's serialize() function is called 943 * 944 * @return array the array of properties names that should be saved 945 * @todo Implement mock DB_common::__sleep 946 */ 947 function __sleep() 948 { 949 // if ($this->connection) { 950 // // Don't disconnect(), people use serialize() for many reasons 951 // $this->was_connected = true; 952 // } else { 953 // $this->was_connected = false; 954 // } 955 // if (isset($this->autocommit)) { 956 // return array('autocommit', 957 // 'dbsyntax', 958 // 'dsn', 959 // 'features', 960 // 'fetchmode', 961 // 'fetchmode_object_class', 962 // 'options', 963 // 'was_connected', 964 // ); 965 // } else { 966 // return array('dbsyntax', 967 // 'dsn', 968 // 'features', 969 // 'fetchmode', 970 // 'fetchmode_object_class', 971 // 'options', 972 // 'was_connected', 973 // ); 974 // } 975 } 976 977 /** 978 * Automatically reconnects to the database when PHP's unserialize() 979 * function is called 980 * 981 * @return void 982 * @todo Implement mock DB_common::__wakeup 983 */ 984 function __wakeup() 985 { 986 // if ($this->was_connected) { 987 // $this->connect($this->dsn, $this->options); 988 // } 989 } 990 991 /** 992 * Automatic string conversion for PHP 5 993 * 994 * @return string a string describing the current PEAR DB object 995 * @todo Implement mock DB_common::__toString 996 */ 997 public function __toString() 998 { 999 // $info = strtolower(get_class($this)); 1000 // $info .= ': (phptype=' . $this->phptype . 1001 // ', dbsyntax=' . $this->dbsyntax . 1002 // ')'; 1003 // if ($this->connection) { 1004 // $info .= ' [connected]'; 1005 // } 1006 // return $info; 1007 } 1008 1009 /** 1010 * Quotes a string so it can be safely used as a table or column name 1011 * 1012 * @param string $str the identifier name to be quoted 1013 * @return string the quoted identifier 1014 */ 1015 public function quoteIdentifier($str) 1016 { 1017 return '"' . str_replace('"', '""', $str) . '"'; 1018 } 1019 1020 /** 1021 * Formats input so it can be safely used in a query 1022 * 1023 * @see DB_common::escapeSimple() 1024 * @todo Implement mock DB_common::quoteSmart 1025 */ 1026 public function quoteSmart($in) 1027 { 1028 // if (is_int($in) || is_double($in)) { 1029 // return $in; 1030 // } elseif (is_bool($in)) { 1031 // return $in ? 1 : 0; 1032 // } elseif (is_null($in)) { 1033 // return 'NULL'; 1034 // } else { 1035 // return "'" . $this->escapeSimple($in) . "'"; 1036 // } 1037 } 1038 1039 /** 1040 * Escapes a string according to the current DBMS's standards 1041 * 1042 * @param string $str the string to be escaped 1043 * @return string the escaped string 1044 * @see DB_common::quoteSmart() 1045 * @todo Implement mock DB_common::escapeSimple 1046 */ 1047 public function escapeSimple($str) 1048 { 1049 // return str_replace("'", "''", $str); 1050 } 1051 1052 /** 1053 * Tells whether the present driver supports a given feature 1054 * 1055 * @param string $feature the feature you're curious about 1056 * @return bool whether this driver supports $feature 1057 * @todo Implement mock DB_common::provides 1058 */ 1059 public function provides($feature) 1060 { 1061 // return $this->features[$feature]; 1062 } 1063 1064 /** 1065 * Sets the fetch mode that should be used by default for query results 1066 * 1067 * @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC 1068 * or DB_FETCHMODE_OBJECT 1069 * @param string $object_class the class name of the object to be returned 1070 * by the fetch methods when the 1071 * DB_FETCHMODE_OBJECT mode is selected. 1072 * If no class is specified by default a cast 1073 * to object from the assoc array row will be 1074 * done. There is also the posibility to use 1075 * and extend the 'DB_row' class. 1076 * 1077 * @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT 1078 * @todo Implement mock DB_common::setFetchMode 1079 */ 1080 public function setFetchMode($fetchmode, $object_class = 'stdClass') 1081 { 1082 // switch ($fetchmode) { 1083 // case DB_FETCHMODE_OBJECT: 1084 // $this->fetchmode_object_class = $object_class; 1085 // case DB_FETCHMODE_ORDERED: 1086 // case DB_FETCHMODE_ASSOC: 1087 // $this->fetchmode = $fetchmode; 1088 // break; 1089 // default: 1090 // return $this->raiseError('invalid fetchmode mode'); 1091 // } 1092 } 1093 1094 /** 1095 * Sets run-time configuration options for PEAR DB 1096 * 1097 * @param string $option option name 1098 * @param mixed $value value for the option 1099 * @return int DB_OK on success. A DB_Error object on failure. 1100 * @see DB_common::$options 1101 * @todo Implement mock DB_common::setOption 1102 */ 1103 public function setOption($option, $value) 1104 { 1105 if (isset($this->options[$option])) { 1106 $this->options[$option] = $value; 1107 return DB_OK; 1108 } 1109 PHPUnit2_Framework_Assert::fail("DB_common::setOption called" 1110 ." with unknown option $option"); 1111 } 1112 1113 /** 1114 * Returns the value of an option 1115 * 1116 * @param string $option the option name you're curious about 1117 * @return mixed the option's value 1118 * @todo Implement mock DB_common::getOption 1119 */ 1120 public function getOption($option) 1121 { 1122 // if (isset($this->options[$option])) { 1123 // return $this->options[$option]; 1124 // } 1125 // return $this->raiseError("unknown option $option"); 1126 } 1127 1128 /** 1129 * Prepares a query for multiple execution with execute() 1130 * 1131 * @param string $query the query to be prepared 1132 * @return mixed DB statement resource on success. A DB_Error object 1133 * on failure. 1134 * @see DB_common::execute() 1135 * @todo Implement mock DB_common::prepare 1136 */ 1137 public function prepare($query) 1138 { 1139 PHPUnit2_Framework_Assert::fail("DB does not support" 1140 . " multiple execution"); 1141 // $tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, 1142 // PREG_SPLIT_DELIM_CAPTURE); 1143 // $token = 0; 1144 // $types = array(); 1145 // $newtokens = array(); 1146 // 1147 // foreach ($tokens as $val) { 1148 // switch ($val) { 1149 // case '?': 1150 // $types[$token++] = DB_PARAM_SCALAR; 1151 // break; 1152 // case '&': 1153 // $types[$token++] = DB_PARAM_OPAQUE; 1154 // break; 1155 // case '!': 1156 // $types[$token++] = DB_PARAM_MISC; 1157 // break; 1158 // default: 1159 // $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val); 1160 // } 1161 // } 1162 // 1163 // $this->prepare_tokens[] = &$newtokens; 1164 // end($this->prepare_tokens); 1165 // 1166 // $k = key($this->prepare_tokens); 1167 // $this->prepare_types[$k] = $types; 1168 // $this->prepared_queries[$k] = implode(' ', $newtokens); 1169 // 1170 // return $k; 1171 } 1172 1173 1174 /** 1175 * Automaticaly generates an insert or update query and pass it to 1176 * prepare() 1177 * 1178 * @param string $table the table name 1179 * @param array $table_fields the array of field names 1180 * @param int $mode a type of query to make: 1181 * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE 1182 * @param string $where for update queries: the WHERE clause to 1183 * append to the SQL statement. Don't 1184 * include the "WHERE" keyword. 1185 * 1186 * @return resource the query handle 1187 * @uses DB_common::prepare(), DB_common::buildManipSQL() 1188 * @todo Implement mock DB_common::autoPrepare 1189 */ 1190 public function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, 1191 $where = false) 1192 { 1193 // $query = $this->buildManipSQL($table, $table_fields, $mode, $where); 1194 // if (DB::isError($query)) { 1195 // return $query; 1196 // } 1197 // return $this->prepare($query); 1198 } 1199 1200 /** 1201 * Automaticaly generates an insert or update query and call prepare() 1202 * and execute() with it 1203 * 1204 * @param string $table the table name 1205 * @param array $fields_values the associative array where $key is a 1206 * field name and $value its value 1207 * @param int $mode a type of query to make: 1208 * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE 1209 * @param string $where for update queries: the WHERE clause to 1210 * append to the SQL statement. Don't 1211 * include the "WHERE" keyword. 1212 * 1213 * @return mixed a new DB_result object for successful SELECT queries 1214 * or DB_OK for successul data manipulation queries. 1215 * A DB_Error object on failure. 1216 * 1217 * @uses DB_common::autoPrepare(), DB_common::execute() 1218 * @todo Implement mock DB_common::autoExecute 1219 */ 1220 public function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, 1221 $where = false) 1222 { 1223 PHPUnit2_Framework_Assert::fail("DB does not support" 1224 . " multiple execution"); 1225 // $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, 1226 // $where); 1227 // if (DB::isError($sth)) { 1228 // return $sth; 1229 // } 1230 // $ret =& $this->execute($sth, array_values($fields_values)); 1231 // $this->freePrepared($sth); 1232 // return $ret; 1233 } 1234 1235 /** 1236 * Produces an SQL query string for autoPrepare() 1237 * 1238 * @param string $table the table name 1239 * @param array $table_fields the array of field names 1240 * @param int $mode a type of query to make: 1241 * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE 1242 * @param string $where for update queries: the WHERE clause to 1243 * append to the SQL statement. Don't 1244 * include the "WHERE" keyword. 1245 * 1246 * @return string the sql query for autoPrepare() 1247 * @todo Implement mock DB_common::buildManipSQL 1248 */ 1249 public function buildManipSQL($table, $table_fields, $mode, $where = false) 1250 { 1251 // if (count($table_fields) == 0) { 1252 // return $this->raiseError(DB_ERROR_NEED_MORE_DATA); 1253 // } 1254 // $first = true; 1255 // switch ($mode) { 1256 // case DB_AUTOQUERY_INSERT: 1257 // $values = ''; 1258 // $names = ''; 1259 // foreach ($table_fields as $value) { 1260 // if ($first) { 1261 // $first = false; 1262 // } else { 1263 // $names .= ','; 1264 // $values .= ','; 1265 // } 1266 // $names .= $value; 1267 // $values .= '?'; 1268 // } 1269 // return "INSERT INTO $table ($names) VALUES ($values)"; 1270 // case DB_AUTOQUERY_UPDATE: 1271 // $set = ''; 1272 // foreach ($table_fields as $value) { 1273 // if ($first) { 1274 // $first = false; 1275 // } else { 1276 // $set .= ','; 1277 // } 1278 // $set .= "$value = ?"; 1279 // } 1280 // $sql = "UPDATE $table SET $set"; 1281 // if ($where) { 1282 // $sql .= " WHERE $where"; 1283 // } 1284 // return $sql; 1285 // default: 1286 // return $this->raiseError(DB_ERROR_SYNTAX); 1287 // } 1288 } 1289 1290 /** 1291 * Executes a DB statement prepared with prepare() 1292 * 1293 * @param resource $stmt a DB statement resource returned from prepare() 1294 * @param mixed $data array, string or numeric data to be used in 1295 * execution of the statement. Quantity of items 1296 * passed must match quantity of placeholders in 1297 * query: meaning 1 placeholder for non-array 1298 * parameters or 1 placeholder per array element. 1299 * 1300 * @return mixed a new DB_result object for successful SELECT queries 1301 * or DB_OK for successul data manipulation queries. 1302 * A DB_Error object on failure. 1303 * 1304 * @see DB_common::prepare() 1305 * @todo Implement mock DB_common::execute 1306 */ 1307 public function &execute($stmt, $data = array()) 1308 { 1309 PHPUnit2_Framework_Assert::fail("DB does not support" 1310 . " multiple execution"); 1311 // $realquery = $this->executeEmulateQuery($stmt, $data); 1312 // if (DB::isError($realquery)) { 1313 // return $realquery; 1314 // } 1315 // $result = $this->simpleQuery($realquery); 1316 // 1317 // if ($result === DB_OK || DB::isError($result)) { 1318 // return $result; 1319 // } else { 1320 // $tmp =& new DB_result($this, $result); 1321 // return $tmp; 1322 // } 1323 } 1324 1325 /** 1326 * Emulates executing prepared statements if the DBMS not support them 1327 * 1328 * @param resource $stmt a DB statement resource returned from execute() 1329 * @param mixed $data array, string or numeric data to be used in 1330 * execution of the statement. Quantity of items 1331 * passed must match quantity of placeholders in 1332 * query: meaning 1 placeholder for non-array 1333 * parameters or 1 placeholder per array element. 1334 * 1335 * @return mixed a string containing the real query run when emulating 1336 * prepare/execute. A DB_Error object on failure. 1337 * 1338 * @see DB_common::execute() 1339 * @todo Implement mock DB_common::executeEmulateQuery 1340 */ 1341 protected function executeEmulateQuery($stmt, $data = array()) 1342 { 1343 PHPUnit2_Framework_Assert::fail("DB does not support" 1344 . " multiple execution"); 1345 // $stmt = (int)$stmt; 1346 // $data = (array)$data; 1347 // $this->last_parameters = $data; 1348 // 1349 // if (count($this->prepare_types[$stmt]) != count($data)) { 1350 // $this->last_query = $this->prepared_queries[$stmt]; 1351 // return $this->raiseError(DB_ERROR_MISMATCH); 1352 // } 1353 // 1354 // $realquery = $this->prepare_tokens[$stmt][0]; 1355 // 1356 // $i = 0; 1357 // foreach ($data as $value) { 1358 // if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { 1359 // $realquery .= $this->quoteSmart($value); 1360 // } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { 1361 // $fp = @fopen($value, 'rb'); 1362 // if (!$fp) { 1363 // return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); 1364 // } 1365 // $realquery .= $this->quoteSmart(fread($fp, filesize($value))); 1366 // fclose($fp); 1367 // } else { 1368 // $realquery .= $value; 1369 // } 1370 // 1371 // $realquery .= $this->prepare_tokens[$stmt][++$i]; 1372 // } 1373 // 1374 // return $realquery; 1375 } 1376 1377 /** 1378 * Performs several execute() calls on the same statement handle 1379 * 1380 * @param resource $stmt query handle from prepare() 1381 * @param array $data numeric array containing the 1382 * data to insert into the query 1383 * @return int DB_OK on success. A DB_Error object on failure. 1384 * @see DB_common::prepare(), DB_common::execute() 1385 * @todo Implement mock DB_common::executeMultiple 1386 */ 1387 function executeMultiple($stmt, $data) 1388 { 1389 PHPUnit2_Framework_Assert::fail("DB does not support" 1390 . " multiple execution"); 1391 // foreach ($data as $value) { 1392 // $res =& $this->execute($stmt, $value); 1393 // if (DB::isError($res)) { 1394 // return $res; 1395 // } 1396 // } 1397 // return DB_OK; 1398 } 1399 1400 /** 1401 * Frees the internal resources associated with a prepared query 1402 * 1403 * @param resource $stmt the prepared statement's PHP resource 1404 * @param bool $free_resource should the PHP resource be freed too? 1405 * Use false if you need to get data 1406 * from the result set later. 1407 * @return bool TRUE on success, FALSE if $result is invalid 1408 * @see DB_common::prepare() 1409 * @todo Implement mock DB_common::freePrepared 1410 */ 1411 function freePrepared($stmt, $free_resource = true) 1412 { 1413 PHPUnit2_Framework_Assert::fail("DB does not support" 1414 . " multiple execution"); 1415 // $stmt = (int)$stmt; 1416 // if (isset($this->prepare_tokens[$stmt])) { 1417 // unset($this->prepare_tokens[$stmt]); 1418 // unset($this->prepare_types[$stmt]); 1419 // unset($this->prepared_queries[$stmt]); 1420 // return true; 1421 // } 1422 // return false; 1423 } 1424 1425 /** 1426 * Changes a query string for various DBMS specific reasons 1427 * 1428 * @param string $query the query string to modify 1429 * @return string the modified query string 1430 * @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(), 1431 * DB_sqlite::modifyQuery() 1432 * @todo Implement mock DB_common::modifyQuery 1433 */ 1434 protected function modifyQuery($query) 1435 { 1436 // return $query; 1437 } 1438 1439 /** 1440 * Adds LIMIT clauses to a query string according to current DBMS standards 1441 * 1442 * @param string $query the query to modify 1443 * @param int $from the row to start to fetching (0 = the first row) 1444 * @param int $count the numbers of rows to fetch 1445 * @param mixed $params array, string or numeric data to be used in 1446 * execution of the statement. Quantity of items 1447 * passed must match quantity of placeholders in 1448 * query: meaning 1 placeholder for non-array 1449 * parameters or 1 placeholder per array element. 1450 * 1451 * @return string the query string with LIMIT clauses added 1452 * @todo Implement mock DB_common::modifyLimitQuery 1453 */ 1454 protected function modifyLimitQuery($query, $from, $count, $params = array()) 1455 { 1456 // return $query; 1457 } 1458 1459 /** 1460 * Set expected query and return 1461 * 1462 * This is a test routine that does not exist in the PEAR DB package. 1463 * @param string $expected Expected query 1464 * @param string $result Result to be returned when expected 1465 * query is received. 1466 */ 1467 public function expect_query($expected, $result) { 1468 $this->expected_query = $expected; 1469 $this->expected_result = $result; 1470 } 1471 1472 /** 1473 * Set list of expected queries and returns 1474 * 1475 * This is a test routine that does not exist in the PEAR DB package. 1476 * @param string $list Expected queries and returns 1477 */ 1478 public function expect_queries($list) { 1479 $this->expected_list = $list; 1480 $this->expected_list_cursor = 0; 1481 $this->expect_query($this->expected_list[0]['query'], 1482 $this->expected_list[0]['result']); 1483 } 1484 1485 /** 1486 * Verify that all expected queries have been received 1487 * 1488 * This is a test routine that does not exist in the PEAR DB package. 1489 */ 1490 public function tally_queries() { 1491 if ($this->expected_list_cursor < count($this->expected_list)) { 1492 PHPUnit2_Framework_Assert::fail("DB_mysql::expected query was" 1493 ." not received. expected $this->expected_query"); 1494 } 1495 } 1496 1497 /** 1498 * Sends a query to the database server 1499 * 1500 * @param string $query the SQL query or the statement to prepare 1501 * @param mixed $params array, string or numeric data to be used in 1502 * execution of the statement. Quantity of items 1503 * passed must match quantity of placeholders in 1504 * query: meaning 1 placeholder for non-array 1505 * parameters or 1 placeholder per array element. 1506 * 1507 * @return mixed a new DB_result object for successful SELECT queries 1508 * or DB_OK for successul data manipulation queries. 1509 * A DB_Error object on failure. 1510 * 1511 * @see DB_result, DB_common::prepare(), DB_common::execute() 1512 * @todo Implement mock DB_common::query 1513 */ 1514 public function &query($query, $params = array()) 1515 { 1516 $params = (array)$params; 1517 if (sizeof($params) > 0) { 1518 PHPUnit2_Framework_Assert::fail("DB does not support" 1519 . " multiple execution"); 1520 } 1521 if (!is_null($this->expected_list)) { 1522 // We are working through a list of queries. If the 1523 // number of queries received is greater than the number 1524 // on the list, that's an error 1525 if ($this->expected_list_cursor >= count($this->expected_list)) { 1526 PHPUnit2_Framework_Assert::fail( 1527 "DB_mysql::query called with" 1528 ."$query, exceeding number of queries expected"); 1529 } 1530 } 1531 if ($query != $this->expected_query) { 1532 PHPUnit2_Framework_Assert::fail('DB_mysql::query() called with' 1533 .' "'.$query.'", expected "'.$this->expected_query.'"'); 1534 } 1535 $result = $this->expected_result; 1536 if (!is_null($this->expected_list)) { 1537 // More queries are expected. Advance the cursor 1538 $this->expected_list_cursor++; 1539 $this->expect_query( 1540 $this->expected_list[$this->expected_list_cursor]['query'], 1541 $this->expected_list[$this->expected_list_cursor]['result']); 1542 } 1543 return $result; 1544 // if (sizeof($params) > 0) { 1545 // $sth = $this->prepare($query); 1546 // if (DB::isError($sth)) { 1547 // return $sth; 1548 // } 1549 // $ret =& $this->execute($sth, $params); 1550 // $this->freePrepared($sth, false); 1551 // return $ret; 1552 // } else { 1553 // $this->last_parameters = array(); 1554 // $result = $this->simpleQuery($query); 1555 // if ($result === DB_OK || DB::isError($result)) { 1556 // return $result; 1557 // } else { 1558 // $tmp =& new DB_result($this, $result); 1559 // return $tmp; 1560 // } 1561 // } 1562 } 1563 1564 /** 1565 * Generates and executes a LIMIT query 1566 * 1567 * @param string $query the query 1568 * @param intr $from the row to start to fetching (0 = the first row) 1569 * @param int $count the numbers of rows to fetch 1570 * @param mixed $params array, string or numeric data to be used in 1571 * execution of the statement. Quantity of items 1572 * passed must match quantity of placeholders in 1573 * query: meaning 1 placeholder for non-array 1574 * parameters or 1 placeholder per array element. 1575 * 1576 * @return mixed a new DB_result object for successful SELECT queries 1577 * or DB_OK for successul data manipulation queries. 1578 * A DB_Error object on failure. 1579 * @todo Implement mock DB_common::limitQuery 1580 */ 1581 public function &limitQuery($query, $from, $count, $params = array()) 1582 { 1583 // $query = $this->modifyLimitQuery($query, $from, $count, $params); 1584 // if (DB::isError($query)){ 1585 // return $query; 1586 // } 1587 // $result =& $this->query($query, $params); 1588 // if (is_a($result, 'DB_result')) { 1589 // $result->setOption('limit_from', $from); 1590 // $result->setOption('limit_count', $count); 1591 // } 1592 // return $result; 1593 } 1594 1595 /** 1596 * Fetches the first column of the first row from a query result 1597 * 1598 * @param string $query the SQL query 1599 * @param mixed $params array, string or numeric data to be used in 1600 * execution of the statement. Quantity of items 1601 * passed must match quantity of placeholders in 1602 * query: meaning 1 placeholder for non-array 1603 * parameters or 1 placeholder per array element. 1604 * 1605 * @return mixed the returned value of the query. 1606 * A DB_Error object on failure. 1607 * @todo Implement mock DB_common::getOne 1608 */ 1609 function &getOne($query, $params = array()) 1610 { 1611 return $this->query($query,$params); 1612 1613 // $sth = $this->prepare($query); 1614 // if (DB::isError($sth)) { 1615 // return $sth; 1616 // } 1617 // $res =& $this->execute($sth, $params); 1618 // $this->freePrepared($sth); 1619 // } else { 1620 // $res =& $this->query($query); 1621 // } 1622 // 1623 // if (DB::isError($res)) { 1624 // return $res; 1625 // } 1626 // 1627 // $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); 1628 // $res->free(); 1629 // 1630 // if ($err !== DB_OK) { 1631 // return $err; 1632 // } 1633 // 1634 // return $row[0]; 1635 } 1636 1637 /** 1638 * Fetches the first row of data returned from a query result 1639 * 1640 * @param string $query the SQL query 1641 * @param mixed $params array, string or numeric data to be used in 1642 * execution of the statement. Quantity of items 1643 * passed must match quantity of placeholders in 1644 * query: meaning 1 placeholder for non-array 1645 * parameters or 1 placeholder per array element. 1646 * @param int $fetchmode the fetch mode to use 1647 * 1648 * @return array the first row of results as an array. 1649 * A DB_Error object on failure. 1650 * @todo Implement mock DB_common::getRow 1651 */ 1652 public function &getRow($query, $params = array(), 1653 $fetchmode = DB_FETCHMODE_DEFAULT) 1654 { 1655 // // compat check, the params and fetchmode parameters used to 1656 // // have the opposite order 1657 // if (!is_array($params)) { 1658 // if (is_array($fetchmode)) { 1659 // if ($params === null) { 1660 // $tmp = DB_FETCHMODE_DEFAULT; 1661 // } else { 1662 // $tmp = $params; 1663 // } 1664 // $params = $fetchmode; 1665 // $fetchmode = $tmp; 1666 // } elseif ($params !== null) { 1667 // $fetchmode = $params; 1668 // $params = array(); 1669 // } 1670 // } 1671 // // modifyLimitQuery() would be nice here, but it causes BC issues 1672 // if (sizeof($params) > 0) { 1673 // $sth = $this->prepare($query); 1674 // if (DB::isError($sth)) { 1675 // return $sth; 1676 // } 1677 // $res =& $this->execute($sth, $params); 1678 // $this->freePrepared($sth); 1679 // } else { 1680 // $res =& $this->query($query); 1681 // } 1682 // 1683 // if (DB::isError($res)) { 1684 // return $res; 1685 // } 1686 // 1687 // $err = $res->fetchInto($row, $fetchmode); 1688 // 1689 // $res->free(); 1690 // 1691 // if ($err !== DB_OK) { 1692 // return $err; 1693 // } 1694 // 1695 // return $row; 1696 } 1697 1698 /** 1699 * Fetches a single column from a query result and returns it as an 1700 * indexed array 1701 * 1702 * @param string $query the SQL query 1703 * @param mixed $col which column to return (integer [column number, 1704 * starting at 0] or string [column name]) 1705 * @param mixed $params array, string or numeric data to be used in 1706 * execution of the statement. Quantity of items 1707 * passed must match quantity of placeholders in 1708 * query: meaning 1 placeholder for non-array 1709 * parameters or 1 placeholder per array element. 1710 * 1711 * @return array the results as an array. A DB_Error object on failure. 1712 * 1713 * @see DB_common::query() 1714 * @todo Implement mock DB_common::getCol 1715 */ 1716 public function &getCol($query, $col = 0, $params = array()) 1717 { 1718 // $params = (array)$params; 1719 // if (sizeof($params) > 0) { 1720 // $sth = $this->prepare($query); 1721 // 1722 // if (DB::isError($sth)) { 1723 // return $sth; 1724 // } 1725 // 1726 // $res =& $this->execute($sth, $params); 1727 // $this->freePrepared($sth); 1728 // } else { 1729 // $res =& $this->query($query); 1730 // } 1731 // 1732 // if (DB::isError($res)) { 1733 // return $res; 1734 // } 1735 // 1736 // $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; 1737 // 1738 // if (!is_array($row = $res->fetchRow($fetchmode))) { 1739 // $ret = array(); 1740 // } else { 1741 // if (!array_key_exists($col, $row)) { 1742 // $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); 1743 // } else { 1744 // $ret = array($row[$col]); 1745 // while (is_array($row = $res->fetchRow($fetchmode))) { 1746 // $ret[] = $row[$col]; 1747 // } 1748 // } 1749 // } 1750 // 1751 // $res->free(); 1752 // 1753 // if (DB::isError($row)) { 1754 // $ret = $row; 1755 // } 1756 // 1757 // return $ret; 1758 } 1759 1760 /** 1761 * Fetches an entire query result and returns it as an 1762 * associative array using the first column as the key 1763 * 1764 * @param string $query the SQL query 1765 * @param bool $force_array used only when the query returns 1766 * exactly two columns. If true, the values 1767 * of the returned array will be one-element 1768 * arrays instead of scalars. 1769 * @param mixed $params array, string or numeric data to be used in 1770 * execution of the statement. Quantity of 1771 * items passed must match quantity of 1772 * placeholders in query: meaning 1 1773 * placeholder for non-array parameters or 1774 * 1 placeholder per array element. 1775 * @param int $fetchmode the fetch mode to use 1776 * @param bool $group if true, the values of the returned array 1777 * is wrapped in another array. If the same 1778 * key value (in the first column) repeats 1779 * itself, the values will be appended to 1780 * this array instead of overwriting the 1781 * existing values. 1782 * 1783 * @return array the associative array containing the query results. 1784 * A DB_Error object on failure. 1785 * @todo Implement mock DB_common::getAssoc 1786 */ 1787 public function &getAssoc($query, $force_array = false, $params = array(), 1788 $fetchmode = DB_FETCHMODE_DEFAULT, $group = false) 1789 { 1790 // $params = (array)$params; 1791 // if (sizeof($params) > 0) { 1792 // $sth = $this->prepare($query); 1793 // 1794 // if (DB::isError($sth)) { 1795 // return $sth; 1796 // } 1797 // 1798 // $res =& $this->execute($sth, $params); 1799 // $this->freePrepared($sth); 1800 // } else { 1801 // $res =& $this->query($query); 1802 // } 1803 // 1804 // if (DB::isError($res)) { 1805 // return $res; 1806 // } 1807 // if ($fetchmode == DB_FETCHMODE_DEFAULT) { 1808 // $fetchmode = $this->fetchmode; 1809 // } 1810 // $cols = $res->numCols(); 1811 // 1812 // if ($cols < 2) { 1813 // $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); 1814 // return $tmp; 1815 // } 1816 // 1817 // $results = array(); 1818 // 1819 // if ($cols > 2 || $force_array) { 1820 // // return array values 1821 // // XXX this part can be optimized 1822 // if ($fetchmode == DB_FETCHMODE_ASSOC) { 1823 // while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { 1824 // reset($row); 1825 // $key = current($row); 1826 // unset($row[key($row)]); 1827 // if ($group) { 1828 // $results[$key][] = $row; 1829 // } else { 1830 // $results[$key] = $row; 1831 // } 1832 // } 1833 // } elseif ($fetchmode == DB_FETCHMODE_OBJECT) { 1834 // while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { 1835 // $arr = get_object_vars($row); 1836 // $key = current($arr); 1837 // if ($group) { 1838 // $results[$key][] = $row; 1839 // } else { 1840 // $results[$key] = $row; 1841 // } 1842 // } 1843 // } else { 1844 // while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { 1845 // // we shift away the first element to get 1846 // // indices running from 0 again 1847 // $key = array_shift($row); 1848 // if ($group) { 1849 // $results[$key][] = $row; 1850 // } else { 1851 // $results[$key] = $row; 1852 // } 1853 // } 1854 // } 1855 // if (DB::isError($row)) { 1856 // $results = $row; 1857 // } 1858 // } else { 1859 // // return scalar values 1860 // while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { 1861 // if ($group) { 1862 // $results[$row[0]][] = $row[1]; 1863 // } else { 1864 // $results[$row[0]] = $row[1]; 1865 // } 1866 // } 1867 // if (DB::isError($row)) { 1868 // $results = $row; 1869 // } 1870 // } 1871 // 1872 // $res->free(); 1873 // 1874 // return $results; 1875 } 1876 1877 /** 1878 * Fetches all of the rows from a query result 1879 * 1880 * @param string $query the SQL query 1881 * @param mixed $params array, string or numeric data to be used in 1882 * execution of the statement. Quantity of 1883 * items passed must match quantity of 1884 * placeholders in query: meaning 1 1885 * placeholder for non-array parameters or 1886 * 1 placeholder per array element. 1887 * @param int $fetchmode the fetch mode to use: 1888 * + DB_FETCHMODE_ORDERED 1889 * + DB_FETCHMODE_ASSOC 1890 * + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED 1891 * + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED 1892 * 1893 * @return array the nested array. A DB_Error object on failure. 1894 * @todo Implement mock DB_common::getAll 1895 */ 1896 public function &getAll($query, $params = array(), 1897 $fetchmode = DB_FETCHMODE_DEFAULT) 1898 { 1899 // // compat check, the params and fetchmode parameters used to 1900 // // have the opposite order 1901 // if (!is_array($params)) { 1902 // if (is_array($fetchmode)) { 1903 // if ($params === null) { 1904 // $tmp = DB_FETCHMODE_DEFAULT; 1905 // } else { 1906 // $tmp = $params; 1907 // } 1908 // $params = $fetchmode; 1909 // $fetchmode = $tmp; 1910 // } elseif ($params !== null) { 1911 // $fetchmode = $params; 1912 // $params = array(); 1913 // } 1914 // } 1915 // 1916 // if (sizeof($params) > 0) { 1917 // $sth = $this->prepare($query); 1918 // 1919 // if (DB::isError($sth)) { 1920 // return $sth; 1921 // } 1922 // 1923 // $res =& $this->execute($sth, $params); 1924 // $this->freePrepared($sth); 1925 // } else { 1926 // $res =& $this->query($query); 1927 // } 1928 // 1929 // if ($res === DB_OK || DB::isError($res)) { 1930 // return $res; 1931 // } 1932 // 1933 // $results = array(); 1934 // while (DB_OK === $res->fetchInto($row, $fetchmode)) { 1935 // if ($fetchmode & DB_FETCHMODE_FLIPPED) { 1936 // foreach ($row as $key => $val) { 1937 // $results[$key][] = $val; 1938 // } 1939 // } else { 1940 // $results[] = $row; 1941 // } 1942 // } 1943 // 1944 // $res->free(); 1945 // 1946 // if (DB::isError($row)) { 1947 // $tmp =& $this->raiseError($row); 1948 // return $tmp; 1949 // } 1950 // return $results; 1951 } 1952 1953 /** 1954 * Enables or disables automatic commits 1955 * 1956 * @param bool $onoff true turns it on, false turns it off 1957 * @return int DB_OK on success. A DB_Error object if the driver 1958 * doesn't support auto-committing transactions. 1959 * @todo Implement mock DB_common::autoCommit 1960 */ 1961 public function autoCommit($onoff = false) 1962 { 1963 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 1964 } 1965 1966 /** 1967 * Commits the current transaction 1968 * 1969 * @return int DB_OK on success. A DB_Error object on failure. 1970 * @todo Implement mock DB_common::commit 1971 */ 1972 public function commit() 1973 { 1974 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 1975 } 1976 1977 /** 1978 * Reverts the current transaction 1979 * 1980 * @return int DB_OK on success. A DB_Error object on failure. 1981 * @todo Implement mock DB_common::rollback 1982 */ 1983 public function rollback() 1984 { 1985 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 1986 } 1987 1988 /** 1989 * Determines the number of rows in a query result 1990 * 1991 * @param resource $result the query result idenifier produced by PHP 1992 * @return int the number of rows. A DB_Error object on failure. 1993 * @todo Implement mock DB_common::numRows 1994 */ 1995 public function numRows($result) 1996 { 1997 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 1998 } 1999 2000 /** 2001 * Determines the number of rows affected by a data maniuplation query 2002 * 2003 * 0 is returned for queries that don't manipulate data. 2004 * 2005 * @return int the number of rows. A DB_Error object on failure. 2006 * @todo Implement mock DB_common::affectedRows 2007 */ 2008 public function affectedRows() 2009 { 2010 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2011 } 2012 2013 /** 2014 * Generates the name used inside the database for a sequence 2015 * 2016 * @param string $sqn the sequence's public name 2017 * @return string the sequence's name in the backend 2018 * @see DB_common::createSequence(), DB_common::dropSequence(), 2019 * DB_common::nextID(), DB_common::setOption() 2020 * @todo Implement mock DB_common::getSequenceName 2021 */ 2022 protected function getSequenceName($sqn) 2023 { 2024 // return sprintf($this->getOption('seqname_format'), 2025 // preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); 2026 } 2027 2028 /** 2029 * Returns the next free id in a sequence 2030 * 2031 * @param string $seq_name name of the sequence 2032 * @param boolean $ondemand when true, the seqence is automatically 2033 * created if it does not exist 2034 * 2035 * @return int the next id number in the sequence. 2036 * A DB_Error object on failure. 2037 * 2038 * @see DB_common::createSequence(), DB_common::dropSequence(), 2039 * DB_common::getSequenceName() 2040 * @todo Implement mock DB_common::nextID 2041 */ 2042 public function nextId($seq_name, $ondemand = true) 2043 { 2044 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2045 } 2046 2047 /** 2048 * Creates a new sequence 2049 * 2050 * @param string $seq_name name of the new sequence 2051 * @return int DB_OK on success. A DB_Error object on failure. 2052 * @see DB_common::dropSequence(), DB_common::getSequenceName(), 2053 * DB_common::nextID() 2054 * @todo Implement mock DB_common::createSequence 2055 */ 2056 public function createSequence($seq_name) 2057 { 2058 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2059 } 2060 2061 /** 2062 * Deletes a sequence 2063 * 2064 * @param string $seq_name name of the sequence to be deleted 2065 * @return int DB_OK on success. A DB_Error object on failure. 2066 * @see DB_common::createSequence(), DB_common::getSequenceName(), 2067 * DB_common::nextID() 2068 * @todo Implement mock DB_common::dropSequence 2069 */ 2070 public function dropSequence($seq_name) 2071 { 2072 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2073 } 2074 2075 /** 2076 * Communicates an error and invoke error callbacks, etc 2077 * 2078 * Basically a wrapper for PEAR::raiseError without the message string. 2079 * 2080 * @param mixed integer error code, or a PEAR error object (all 2081 * other parameters are ignored if this parameter is 2082 * an object 2083 * @param int error mode, see PEAR_Error docs 2084 * @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the 2085 * error level (E_USER_NOTICE etc). If error mode is 2086 * PEAR_ERROR_CALLBACK, this is the callback function, 2087 * either as a function name, or as an array of an 2088 * object and method name. For other error modes this 2089 * parameter is ignored. 2090 * @param string extra debug information. Defaults to the last 2091 * query and native error code. 2092 * @param mixed native error code, integer or string depending the 2093 * backend 2094 * 2095 * @return object the PEAR_Error object 2096 * @see PEAR_Error 2097 * @todo Implement mock DB_common::raiseError 2098 */ 2099 public function &raiseError($code = DB_ERROR, $mode = null, $options = null, 2100 $userinfo = null, $nativecode = null) 2101 { 2102 // // The error is yet a DB error object 2103 // if (is_object($code)) { 2104 // // because we the static PEAR::raiseError, our global 2105 // // handler should be used if it is set 2106 // if ($mode === null && !empty($this->_default_error_mode)) { 2107 // $mode = $this->_default_error_mode; 2108 // $options = $this->_default_error_options; 2109 // } 2110 // $tmp = PEAR::raiseError($code, null, $mode, $options, 2111 // null, null, true); 2112 // return $tmp; 2113 // } 2114 // 2115 // if ($userinfo === null) { 2116 // $userinfo = $this->last_query; 2117 // } 2118 // 2119 // if ($nativecode) { 2120 // $userinfo .= ' [nativecode=' . trim($nativecode) . ']'; 2121 // } else { 2122 // $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']'; 2123 // } 2124 // 2125 // $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, 2126 // 'DB_Error', true); 2127 // return $tmp; 2128 } 2129 2130 /** 2131 * Gets the DBMS' native error code produced by the last query 2132 * 2133 * @return mixed the DBMS' error code. A DB_Error object on failure. 2134 * @todo Implement mock DB_common::errorNative 2135 */ 2136 public function errorNative() 2137 { 2138 // return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2139 } 2140 2141 /** 2142 * Maps native error codes to DB's portable ones 2143 * 2144 * Uses the <var>$errorcode_map</var> property defined in each driver. 2145 * 2146 * @param string|int $nativecode the error code returned by the DBMS 2147 * 2148 * @return int the portable DB error code. Return DB_ERROR if the 2149 * current driver doesn't have a mapping for the 2150 * $nativecode submitted. 2151 * @todo Implement mock DB_common::errorCode 2152 */ 2153 public function errorCode($nativecode) 2154 { 2155 // if (isset($this->errorcode_map[$nativecode])) { 2156 // return $this->errorcode_map[$nativecode]; 2157 // } 2158 // Fall back to DB_ERROR if there was no mapping. 2159 return DB_ERROR; 2160 } 2161 2162 /** 2163 * Maps a DB error code to a textual message 2164 * 2165 * @param integer $dbcode the DB error code 2166 * @return string the error message corresponding to the error code 2167 * submitted. FALSE if the error code is unknown. 2168 * @see DB::errorMessage() 2169 * @todo Implement mock DB_common::errorMessage 2170 */ 2171 public function errorMessage($dbcode) 2172 { 2173 // return DB::errorMessage($this->errorcode_map[$dbcode]); 2174 } 2175 2176 /** 2177 * Returns information about a table or a result set 2178 * 2179 * @param object|string $result DB_result object from a query or a 2180 * string containing the name of a table. 2181 * While this also accepts a query result 2182 * resource identifier, this behavior is 2183 * deprecated. 2184 * @param int $mode either unused or one of the tableInfo modes: 2185 * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>, 2186 * <kbd>DB_TABLEINFO_ORDER</kbd> or 2187 * <kbd>DB_TABLEINFO_FULL</kbd> (which does both). 2188 * These are bitwise, so the first two can be 2189 * combined using <kbd>|</kbd>. 2190 * 2191 * @return array an associative array with the information requested. 2192 * A DB_Error object on failure. 2193 * 2194 * @see DB_common::setOption() 2195 * @todo Implement mock DB_common::tableInfo 2196 */ 2197 public function tableInfo($result, $mode = null) 2198 { 2199 /* 2200 * If the DB_<driver> class has a tableInfo() method, that one 2201 * overrides this one. But, if the driver doesn't have one, 2202 * this method runs and tells users about that fact. 2203 */ 2204 return $this->raiseError(DB_ERROR_NOT_CAPABLE); 2205 } 2206 2207 /** 2208 * Lists internal database information 2209 * 2210 * @param string $type type of information being sought. 2211 * Common items being sought are: 2212 * tables, databases, users, views, functions 2213 * Each DBMS's has its own capabilities. 2214 * 2215 * @return array an array listing the items sought. 2216 * A DB DB_Error object on failure. 2217 * @todo Implement mock DB_common::getListOf 2218 */ 2219 public function getListOf($type) 2220 { 2221 // $sql = $this->getSpecialQuery($type); 2222 // if ($sql === null) { 2223 // $this->last_query = ''; 2224 // return $this->raiseError(DB_ERROR_UNSUPPORTED); 2225 // } elseif (is_int($sql) || DB::isError($sql)) { 2226 // // Previous error 2227 // return $this->raiseError($sql); 2228 // } elseif (is_array($sql)) { 2229 // // Already the result 2230 // return $sql; 2231 // } 2232 // // Launch this query 2233 // return $this->getCol($sql); 2234 } 2235 2236 /** 2237 * Obtains the query string needed for listing a given type of objects 2238 * 2239 * @param string $type the kind of objects you want to retrieve 2240 * @return string the SQL query string or null if the driver doesn't 2241 * support the object type requested 2242 * @see DB_common::getListOf() 2243 * @todo Implement mock DB_common::getSpecialQuery 2244 */ 2245 protected function getSpecialQuery($type) 2246 { 2247 // return $this->raiseError(DB_ERROR_UNSUPPORTED); 2248 } 2249 2250 /** 2251 * Right-trims all strings in an array 2252 * 2253 * @param array $array the array to be trimmed (passed by reference) 2254 * @return void 2255 */ 2256 protected function _rtrimArrayValues(&$array) 2257 { 2258 foreach ($array as $key => $value) { 2259 if (is_string($value)) { 2260 $array[$key] = rtrim($value); 2261 } 2262 } 2263 } 2264 2265 /** 2266 * Converts all null values in an array to empty strings 2267 * 2268 * @param array $array the array to be de-nullified (passed by reference) 2269 * @return void 2270 */ 2271 protected function _convertNullArrayValuesToEmpty(&$array) 2272 { 2273 foreach ($array as $key => $value) { 2274 if (is_null($value)) { 2275 $array[$key] = ''; 2276 } 2277 } 2278 } 2279 } 2280 2281 /** 2282 * Mock DB_Error 2283 * @todo Implement mock DB_Error class 2284 */ 2285 class DB_Error extends PEAR_Error 2286 { 2287 /** 2288 * DB_Error constructor 2289 * 2290 * @param mixed $code DB error code, or string with error message 2291 * @param int $mode what "error mode" to operate in 2292 * @param int $level what error level to use for $mode & 2293 * PEAR_ERROR_TRIGGER 2294 * @param mixed $debuginfo additional debug info, such as the last query 2295 * @see PEAR_Error 2296 * @todo Implement DB_Error::constructor 2297 */ 2298 function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, 2299 $level = E_USER_NOTICE, $debuginfo = null) 2300 { 2301 // if (is_int($code)) { 2302 // $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, 2303 // $mode, $level, $debuginfo); 2304 // } else { 2305 // $this->PEAR_Error("DB Error: $code", DB_ERROR, 2306 // $mode, $level, $debuginfo); 2307 // } 2308 } 2309 } 2310 2311 /** 2312 * Mock DB_result 2313 * @todo Implement mock DB_result 2314 */ 2315 class DB_result 2316 { 2317 2318 /** 2319 * This constructor sets the object's properties 2320 * 2321 * @param object &$dbh the DB object reference 2322 * @param resource $result the result resource id 2323 * @param array $options an associative array with result options 2324 * @return void 2325 * @todo Implement mock DB_result::constructor 2326 */ 2327 function DB_result(&$dbh, $result, $options = array()) 2328 { 2329 } 2330 2331 /** 2332 * Set options for the DB_result object 2333 * 2334 * @param string $key the option to set 2335 * @param mixed $value the value to set the option to 2336 * @return void 2337 * @todo Implement mock DB_result::setOption() 2338 */ 2339 function setOption($key, $value = null) 2340 { 2341 switch ($key) { 2342 case 'limit_from': 2343 // $this->limit_from = $value; 2344 break; 2345 case 'limit_count': 2346 // $this->limit_count = $value; 2347 } 2348 } 2349 2350 /** 2351 * Fetch a row of data and return it by reference into an array 2352 * 2353 * @param int $fetchmode the constant indicating how to format the data 2354 * @param int $rownum the row number to fetch (index starts at 0) 2355 * 2356 * @return mixed an array or object containing the row's data, 2357 * NULL when the end of the result set is reached 2358 * or a DB_Error object on failure. 2359 * 2360 * @see DB_common::setOption(), DB_common::setFetchMode() 2361 * @todo Implement mock DB_result::fetchRow() 2362 */ 2363 function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) 2364 { 2365 // if ($fetchmode === DB_FETCHMODE_DEFAULT) { 2366 // $fetchmode = $this->fetchmode; 2367 // } 2368 // if ($fetchmode === DB_FETCHMODE_OBJECT) { 2369 // $fetchmode = DB_FETCHMODE_ASSOC; 2370 // $object_class = $this->fetchmode_object_class; 2371 // } 2372 // if ($this->limit_from !== null) { 2373 // if ($this->row_counter === null) { 2374 // $this->row_counter = $this->limit_from; 2375 // // Skip rows 2376 // if ($this->dbh->features['limit'] === false) { 2377 // $i = 0; 2378 // while ($i++ < $this->limit_from) { 2379 // $this->dbh->fetchInto($this->result, $arr, $fetchmode); 2380 // } 2381 // } 2382 // } 2383 // if ($this->row_counter >= ($this->limit_from + $this->limit_count)) 2384 // { 2385 // if ($this->autofree) { 2386 // $this->free(); 2387 // } 2388 // $tmp = null; 2389 // return $tmp; 2390 // } 2391 // if ($this->dbh->features['limit'] === 'emulate') { 2392 // $rownum = $this->row_counter; 2393 // } 2394 // $this->row_counter++; 2395 // } 2396 // $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); 2397 // if ($res === DB_OK) { 2398 // if (isset($object_class)) { 2399 // // The default mode is specified in the 2400 // // DB_common::fetchmode_object_class property 2401 // if ($object_class == 'stdClass') { 2402 // $arr = (object) $arr; 2403 // } else { 2404 // $arr = &new $object_class($arr); 2405 // } 2406 // } 2407 // return $arr; 2408 // } 2409 // if ($res == null && $this->autofree) { 2410 // $this->free(); 2411 // } 2412 // return $res; 2413 } 2414 2415 /** 2416 * Fetch a row of data into an array which is passed by reference 2417 * 2418 * @param array &$arr the variable where the data should be placed 2419 * @param int $fetchmode the constant indicating how to format the data 2420 * @param int $rownum the row number to fetch (index starts at 0) 2421 * @return mixed DB_OK if a row is processed, NULL when the end of the 2422 * result set is reached or a DB_Error object on failure 2423 * 2424 * @see DB_common::setOption(), DB_common::setFetchMode() 2425 * @todo Implement mock DB_result::fetchInto() 2426 */ 2427 function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) 2428 { 2429 // if ($fetchmode === DB_FETCHMODE_DEFAULT) { 2430 // $fetchmode = $this->fetchmode; 2431 // } 2432 // if ($fetchmode === DB_FETCHMODE_OBJECT) { 2433 // $fetchmode = DB_FETCHMODE_ASSOC; 2434 // $object_class = $this->fetchmode_object_class; 2435 // } 2436 // if ($this->limit_from !== null) { 2437 // if ($this->row_counter === null) { 2438 // $this->row_counter = $this->limit_from; 2439 // // Skip rows 2440 // if ($this->dbh->features['limit'] === false) { 2441 // $i = 0; 2442 // while ($i++ < $this->limit_from) { 2443 // $this->dbh->fetchInto($this->result, $arr, $fetchmode); 2444 // } 2445 // } 2446 // } 2447 // if ($this->row_counter >= ( 2448 // $this->limit_from + $this->limit_count)) 2449 // { 2450 // if ($this->autofree) { 2451 // $this->free(); 2452 // } 2453 // return null; 2454 // } 2455 // if ($this->dbh->features['limit'] === 'emulate') { 2456 // $rownum = $this->row_counter; 2457 // } 2458 // 2459 // $this->row_counter++; 2460 // } 2461 // $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); 2462 // if ($res === DB_OK) { 2463 // if (isset($object_class)) { 2464 // // default mode specified in the 2465 // // DB_common::fetchmode_object_class property 2466 // if ($object_class == 'stdClass') { 2467 // $arr = (object) $arr; 2468 // } else { 2469 // $arr = new $object_class($arr); 2470 // } 2471 // } 2472 // return DB_OK; 2473 // } 2474 // if ($res == null && $this->autofree) { 2475 // $this->free(); 2476 // } 2477 // return $res; 2478 } 2479 2480 /** 2481 * Get the the number of columns in a result set 2482 * 2483 * @return int the number of columns. A DB_Error object on failure. 2484 * @todo Implement mock DB_result::numCols() 2485 */ 2486 function numCols() 2487 { 2488 // return $this->dbh->numCols($this->result); 2489 } 2490 2491 /** 2492 * Get the number of rows in a result set 2493 * 2494 * @return int the number of rows. A DB_Error object on failure. 2495 * @todo Implement mock DB_result::numRows() 2496 */ 2497 function numRows() 2498 { 2499 // if ($this->dbh->features['numrows'] === 'emulate' 2500 // && $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS) 2501 // { 2502 // if ($this->dbh->features['prepare']) { 2503 // $res = $this->dbh->query($this->query, $this->parameters); 2504 // } else { 2505 // $res = $this->dbh->query($this->query); 2506 // } 2507 // if (DB::isError($res)) { 2508 // return $res; 2509 // } 2510 // $i = 0; 2511 // while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { 2512 // $i++; 2513 // } 2514 // return $i; 2515 // } else { 2516 // return $this->dbh->numRows($this->result); 2517 // } 2518 } 2519 2520 /** 2521 * Get the next result if a batch of queries was executed 2522 * 2523 * @return bool true if a new result is available or false if not 2524 * @todo Implement mock DB_result::nextResult() 2525 */ 2526 function nextResult() 2527 { 2528 // return $this->dbh->nextResult($this->result); 2529 } 2530 2531 /** 2532 * Frees the resources allocated for this result set 2533 * 2534 * @return bool true on success. A DB_Error object on failure. 2535 * @todo Implement mock DB_result::free() 2536 */ 2537 function free() 2538 { 2539 // $err = $this->dbh->freeResult($this->result); 2540 // if (DB::isError($err)) { 2541 // return $err; 2542 // } 2543 // $this->result = false; 2544 // $this->statement = false; 2545 // return true; 2546 } 2547 2548 /** 2549 * Determine the query string that created this result 2550 * 2551 * @return string the query string 2552 * @todo Implement mock DB_result::getQuery() 2553 */ 2554 function getQuery() 2555 { 2556 // return $this->query; 2557 } 2558 2559 /** 2560 * Tells which row number is currently being processed 2561 * 2562 * @return integer the current row being looked at. Starts at 1. 2563 * @todo Implement mock DB_result::getRowCounter() 2564 */ 2565 function getRowCounter() 2566 { 2567 // return $this->row_counter; 2568 } 2569 } 2570 2571 /** 2572 * Mock DB_row 2573 * @todo Implement mock DB_row 2574 */ 2575 class DB_row 2576 { 2577 2578 /** 2579 * The constructor places a row's data into properties of this object 2580 * 2581 * @param array the array containing the row's data 2582 * @return void 2583 * @todo Implement mock DB_row constructor 2584 */ 2585 function DB_row(&$arr) 2586 { 2587 // foreach ($arr as $key => $value) { 2588 // $this->$key = &$arr[$key]; 2589 // } 2590 } 2591 } 2592 2593 /** 2594 * Mock DB_mysql class 2595 */ 2596 class DB_mysql extends DB_common 2597 { 2598 2599 /** 2600 * This constructor calls <kbd>$this->DB_common()</kbd> 2601 * 2602 * @return void 2603 */ 2604 function DB_mysql() 2605 { 2606 $this->DB_common(); 2607 } 2608 2609 /** 2610 * Connect to the database server, log in and open the database 2611 * 2612 * @param array $dsn the data source name 2613 * @param bool $persistent should the connection be persistent? 2614 * @return int DB_OK on success. A DB_Error object on failure. 2615 * @todo Implement mock DB_mysql::connect() 2616 */ 2617 function connect($dsn, $persistent = false) 2618 { 2619 // if (!PEAR::loadExtension('mysql')) { 2620 // return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); 2621 // } 2622 // 2623 // $this->dsn = $dsn; 2624 // if ($dsn['dbsyntax']) { 2625 // $this->dbsyntax = $dsn['dbsyntax']; 2626 // } 2627 // 2628 // $params = array(); 2629 // if ($dsn['protocol'] && $dsn['protocol'] == 'unix') { 2630 // $params[0] = ':' . $dsn['socket']; 2631 // } else { 2632 // $params[0] = $dsn['hostspec'] ? $dsn['hostspec'] 2633 // : 'localhost'; 2634 // if ($dsn['port']) { 2635 // $params[0] .= ':' . $dsn['port']; 2636 // } 2637 // } 2638 // $params[] = $dsn['username'] ? $dsn['username'] : null; 2639 // $params[] = $dsn['password'] ? $dsn['password'] : null; 2640 // 2641 // if (!$persistent) { 2642 // if (isset($dsn['new_link']) 2643 // && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) 2644 // { 2645 // $params[] = true; 2646 // } else { 2647 // $params[] = false; 2648 // } 2649 // } 2650 // if (version_compare(phpversion(), '4.3.0', '>=')) { 2651 // $params[] = isset($dsn['client_flags']) 2652 // ? $dsn['client_flags'] : null; 2653 // } 2654 // 2655 // $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; 2656 // 2657 // $ini = ini_get('track_errors'); 2658 // $php_errormsg = ''; 2659 // if ($ini) { 2660 // $this->connection = @call_user_func_array($connect_function, 2661 // $params); 2662 // } else { 2663 // ini_set('track_errors', 1); 2664 // $this->connection = @call_user_func_array($connect_function, 2665 // $params); 2666 // ini_set('track_errors', $ini); 2667 // } 2668 // 2669 // if (!$this->connection) { 2670 // if (($err = @mysql_error()) != '') { 2671 // return $this->raiseError(DB_ERROR_CONNECT_FAILED, 2672 // null, null, null, 2673 // $err); 2674 // } else { 2675 // return $this->raiseError(DB_ERROR_CONNECT_FAILED, 2676 // null, null, null, 2677 // $php_errormsg); 2678 // } 2679 // } 2680 // 2681 // if ($dsn['database']) { 2682 // if (!@mysql_select_db($dsn['database'], $this->connection)) { 2683 // return $this->mysqlRaiseError(); 2684 // } 2685 // $this->_db = $dsn['database']; 2686 // } 2687 // 2688 // return DB_OK; 2689 } 2690 2691 /** 2692 * Disconnects from the database server 2693 * 2694 * @return bool TRUE on success, FALSE on failure 2695 * @todo Implement mock DB_mysql::disconnect() 2696 */ 2697 function disconnect() 2698 { 2699 // $ret = @mysql_close($this->connection); 2700 // $this->connection = null; 2701 // return $ret; 2702 } 2703 2704 /** 2705 * Sends a query to the database server 2706 * 2707 * Generally uses mysql_query(). If you want to use 2708 * mysql_unbuffered_query() set the "result_buffering" option to 0 using 2709 * setOptions(). This option was added in Release 1.7.0. 2710 * 2711 * @param string the SQL query string 2712 * 2713 * @return mixed + a PHP result resrouce for successful SELECT queries 2714 * + the DB_OK constant for other successful queries 2715 * + a DB_Error object on failure 2716 * @todo Implement mock DB_mysql::simpleQuery() 2717 */ 2718 function simpleQuery($query) 2719 { 2720 // $ismanip = DB::isManip($query); 2721 // $this->last_query = $query; 2722 // $query = $this->modifyQuery($query); 2723 // if ($this->_db) { 2724 // if (!@mysql_select_db($this->_db, $this->connection)) { 2725 // return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 2726 // } 2727 // } 2728 // if (!$this->autocommit && $ismanip) { 2729 // if ($this->transaction_opcount == 0) { 2730 // $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); 2731 // $result = @mysql_query('BEGIN', $this->connection); 2732 // if (!$result) { 2733 // return $this->mysqlRaiseError(); 2734 // } 2735 // } 2736 // $this->transaction_opcount++; 2737 // } 2738 // if (!$this->options['result_buffering']) { 2739 // $result = @mysql_unbuffered_query($query, $this->connection); 2740 // } else { 2741 // $result = @mysql_query($query, $this->connection); 2742 // } 2743 // if (!$result) { 2744 // return $this->mysqlRaiseError(); 2745 // } 2746 // if (is_resource($result)) { 2747 // return $result; 2748 // } 2749 return DB_OK; 2750 } 2751 2752 /** 2753 * Move the internal mysql result pointer to the next available result 2754 * 2755 * This method has not been implemented yet. 2756 * 2757 * @param a valid sql result resource 2758 * 2759 * @return false 2760 */ 2761 function nextResult($result) 2762 { 2763 return false; 2764 } 2765 2766 /** 2767 * Places a row from the result set into the given array 2768 * 2769 * @param resource $result the query result resource 2770 * @param array $arr the referenced array to put the data in 2771 * @param int $fetchmode how the resulting array should be indexed 2772 * @param int $rownum the row number to fetch (0 = first row) 2773 * @return mixed DB_OK on success, NULL when the end of a result set is 2774 * reached or on failure 2775 * 2776 * @see DB_result::fetchInto() 2777 * @todo Implement mock DB_mysql::fetchInto() 2778 */ 2779 function fetchInto($result, &$arr, $fetchmode, $rownum = null) 2780 { 2781 // if ($rownum !== null) { 2782 // if (!@mysql_data_seek($result, $rownum)) { 2783 // return null; 2784 // } 2785 // } 2786 // if ($fetchmode & DB_FETCHMODE_ASSOC) { 2787 // $arr = @mysql_fetch_array($result, MYSQL_ASSOC); 2788 // if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { 2789 // $arr = array_change_key_case($arr, CASE_LOWER); 2790 // } 2791 // } else { 2792 // $arr = @mysql_fetch_row($result); 2793 // } 2794 // if (!$arr) { 2795 // return null; 2796 // } 2797 // if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { 2798 // /* 2799 // * Even though this DBMS already trims output, we do this because 2800 // * a field might have intentional whitespace at the end that 2801 // * gets removed by DB_PORTABILITY_RTRIM under another driver. 2802 // */ 2803 // $this->_rtrimArrayValues($arr); 2804 // } 2805 // if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { 2806 // $this->_convertNullArrayValuesToEmpty($arr); 2807 // } 2808 return DB_OK; 2809 } 2810 2811 /** 2812 * Deletes the result set and frees the memory occupied by the result set 2813 * 2814 * This method is not meant to be called directly. Use 2815 * DB_result::free() instead. It can't be declared "protected" 2816 * because DB_result is a separate object. 2817 * 2818 * @param resource $result PHP's query result resource 2819 * 2820 * @return bool TRUE on success, FALSE if $result is invalid 2821 * 2822 * @see DB_result::free() 2823 * @todo Implement mock DB_mysql::freeResult() 2824 */ 2825 function freeResult($result) 2826 { 2827 // return @mysql_free_result($result); 2828 } 2829 2830 2831 /** 2832 * Gets the number of columns in a result set 2833 * 2834 * This method is not meant to be called directly. Use 2835 * DB_result::numCols() instead. It can't be declared "protected" 2836 * because DB_result is a separate object. 2837 * 2838 * @param resource $result PHP's query result resource 2839 * 2840 * @return int the number of columns. A DB_Error object on failure. 2841 * 2842 * @see DB_result::numCols() 2843 * @todo Implement mock DB_mysql::numCols() 2844 */ 2845 function numCols($result) 2846 { 2847 // $cols = @mysql_num_fields($result); 2848 // if (!$cols) { 2849 // return $this->mysqlRaiseError(); 2850 // } 2851 // return $cols; 2852 } 2853 2854 /** 2855 * Gets the number of rows in a result set 2856 * 2857 * This method is not meant to be called directly. Use 2858 * DB_result::numRows() instead. It can't be declared "protected" 2859 * because DB_result is a separate object. 2860 * 2861 * @param resource $result PHP's query result resource 2862 * 2863 * @return int the number of rows. A DB_Error object on failure. 2864 * 2865 * @see DB_result::numRows() 2866 * @todo Implement mock DB_mysql::numRows() 2867 */ 2868 function numRows($result) 2869 { 2870 // $rows = @mysql_num_rows($result); 2871 // if ($rows === null) { 2872 // return $this->mysqlRaiseError(); 2873 // } 2874 // return $rows; 2875 } 2876 2877 /** 2878 * Enables or disables automatic commits 2879 * 2880 * @param bool $onoff true turns it on, false turns it off 2881 * 2882 * @return int DB_OK on success. A DB_Error object if the driver 2883 * doesn't support auto-committing transactions. 2884 * @todo Implement mock DB_mysql::autoCommit() 2885 */ 2886 function autoCommit($onoff = false) 2887 { 2888 // // XXX if $this->transaction_opcount > 0, we should probably 2889 // // issue a warning here. 2890 // $this->autocommit = $onoff ? true : false; 2891 return DB_OK; 2892 } 2893 2894 /** 2895 * Commits the current transaction 2896 * 2897 * @return int DB_OK on success. A DB_Error object on failure. 2898 * @todo Implement mock DB_mysql::committ() 2899 */ 2900 function commit() 2901 { 2902 // if ($this->transaction_opcount > 0) { 2903 // if ($this->_db) { 2904 // if (!@mysql_select_db($this->_db, $this->connection)) { 2905 // return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 2906 // } 2907 // } 2908 // $result = @mysql_query('COMMIT', $this->connection); 2909 // $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); 2910 // $this->transaction_opcount = 0; 2911 // if (!$result) { 2912 // return $this->mysqlRaiseError(); 2913 // } 2914 // } 2915 return DB_OK; 2916 } 2917 2918 /** 2919 * Reverts the current transaction 2920 * 2921 * @return int DB_OK on success. A DB_Error object on failure. 2922 * @todo Implement mock DB_mysql::rollback() 2923 */ 2924 function rollback() 2925 { 2926 // if ($this->transaction_opcount > 0) { 2927 // if ($this->_db) { 2928 // if (!@mysql_select_db($this->_db, $this->connection)) { 2929 // return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); 2930 // } 2931 // } 2932 // $result = @mysql_query('ROLLBACK', $this->connection); 2933 // $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); 2934 // $this->transaction_opcount = 0; 2935 // if (!$result) { 2936 // return $this->mysqlRaiseError(); 2937 // } 2938 // } 2939 return DB_OK; 2940 } 2941 2942 /** 2943 * Determines the number of rows affected by a data maniuplation query 2944 * 2945 * 0 is returned for queries that don't manipulate data. 2946 * 2947 * @return int the number of rows. A DB_Error object on failure. 2948 * @todo Implement mock DB_mysql::affectedRows() 2949 */ 2950 function affectedRows() 2951 { 2952 // if (DB::isManip($this->last_query)) { 2953 // return @mysql_affected_rows($this->connection); 2954 // } else { 2955 // return 0; 2956 // } 2957 } 2958 2959 /** 2960 * Returns the next free id in a sequence 2961 * 2962 * @param string $seq_name name of the sequence 2963 * @param boolean $ondemand when true, the seqence is automatically 2964 * created if it does not exist 2965 * 2966 * @return int the next id number in the sequence. 2967 * A DB_Error object on failure. 2968 * 2969 * @see DB_common::nextID(), DB_common::getSequenceName(), 2970 * DB_mysql::createSequence(), DB_mysql::dropSequence() 2971 * @todo Implement mock DB_mysql::nextId() 2972 */ 2973 function nextId($seq_name, $ondemand = true) 2974 { 2975 // $seqname = $this->getSequenceName($seq_name); 2976 // do { 2977 // $repeat = 0; 2978 // $this->pushErrorHandling(PEAR_ERROR_RETURN); 2979 // $result = $this->query("UPDATE ${seqname} ". 2980 // 'SET id=LAST_INSERT_ID(id+1)'); 2981 // $this->popErrorHandling(); 2982 // if ($result === DB_OK) { 2983 // // COMMON CASE 2984 // $id = @mysql_insert_id($this->connection); 2985 // if ($id != 0) { 2986 // return $id; 2987 // } 2988 // // EMPTY SEQ TABLE 2989 // // Sequence table must be empty for some reason, so fill 2990 // // it and return 1 and obtain a user-level lock 2991 // $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); 2992 // if (DB::isError($result)) { 2993 // return $this->raiseError($result); 2994 // } 2995 // if ($result == 0) { 2996 // // Failed to get the lock 2997 // return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); 2998 // } 2999 // 3000 // // add the default value 3001 // $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)"); 3002 // if (DB::isError($result)) { 3003 // return $this->raiseError($result); 3004 // } 3005 // 3006 // // Release the lock 3007 // $result = $this->getOne('SELECT RELEASE_LOCK(' 3008 // . "'${seqname}_lock')"); 3009 // if (DB::isError($result)) { 3010 // return $this->raiseError($result); 3011 // } 3012 // // We know what the result will be, so no need to try again 3013 // return 1; 3014 // 3015 // } elseif ($ondemand && DB::isError($result) && 3016 // $result->getCode() == DB_ERROR_NOSUCHTABLE) 3017 // { 3018 // // ONDEMAND TABLE CREATION 3019 // $result = $this->createSequence($seq_name); 3020 // if (DB::isError($result)) { 3021 // return $this->raiseError($result); 3022 // } else { 3023 // $repeat = 1; 3024 // } 3025 // 3026 // } elseif (DB::isError($result) && 3027 // $result->getCode() == DB_ERROR_ALREADY_EXISTS) 3028 // { 3029 // // BACKWARDS COMPAT 3030 // // see _BCsequence() comment 3031 // $result = $this->_BCsequence($seqname); 3032 // if (DB::isError($result)) { 3033 // return $this->raiseError($result); 3034 // } 3035 // $repeat = 1; 3036 // } 3037 // } while ($repeat); 3038 // 3039 // return $this->raiseError($result); 3040 } 3041 3042 /** 3043 * Creates a new sequence 3044 * 3045 * @param string $seq_name name of the new sequence 3046 * 3047 * @return int DB_OK on success. A DB_Error object on failure. 3048 * 3049 * @see DB_common::createSequence(), DB_common::getSequenceName(), 3050 * DB_mysql::nextID(), DB_mysql::dropSequence() 3051 * @todo Implement mock DB_mysql::createSequence() 3052 */ 3053 function createSequence($seq_name) 3054 { 3055 // $seqname = $this->getSequenceName($seq_name); 3056 // $res = $this->query('CREATE TABLE ' . $seqname 3057 // . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' 3058 // . ' PRIMARY KEY(id))'); 3059 // if (DB::isError($res)) { 3060 // return $res; 3061 // } 3062 // // insert yields value 1, nextId call will generate ID 2 3063 // $res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); 3064 // if (DB::isError($res)) { 3065 // return $res; 3066 // } 3067 // // so reset to zero 3068 // return $this->query("UPDATE ${seqname} SET id = 0"); 3069 } 3070 3071 /** 3072 * Deletes a sequence 3073 * 3074 * @param string $seq_name name of the sequence to be deleted 3075 * 3076 * @return int DB_OK on success. A DB_Error object on failure. 3077 * 3078 * @see DB_common::dropSequence(), DB_common::getSequenceName(), 3079 * DB_mysql::nextID(), DB_mysql::createSequence() 3080 * @todo Implement mock DB_mysql::dropSequence() 3081 */ 3082 function dropSequence($seq_name) 3083 { 3084 // return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); 3085 } 3086 3087 /** 3088 * Backwards compatibility with old sequence emulation implementation 3089 * (clean up the dupes) 3090 * 3091 * @param string $seqname the sequence name to clean up 3092 * 3093 * @return bool true on success. A DB_Error object on failure. 3094 * @todo Implement mock DB_mysql::_BCsequence() 3095 */ 3096 private function _BCsequence($seqname) 3097 { 3098 // // Obtain a user-level lock... this will release any previous 3099 // // application locks, but unlike LOCK TABLES, it does not abort 3100 // // the current transaction and is much less frequently used. 3101 // $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); 3102 // if (DB::isError($result)) { 3103 // return $result; 3104 // } 3105 // if ($result == 0) { 3106 // // Failed to get the lock, can't do the conversion, bail 3107 // // with a DB_ERROR_NOT_LOCKED error 3108 // return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); 3109 // } 3110 // 3111 // $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); 3112 // if (DB::isError($highest_id)) { 3113 // return $highest_id; 3114 // } 3115 // // This should kill all rows except the highest 3116 // // We should probably do something if $highest_id isn't 3117 // // numeric, but I'm at a loss as how to handle that... 3118 // $result = $this->query('DELETE FROM ' . $seqname 3119 // . " WHERE id <> $highest_id"); 3120 // if (DB::isError($result)) { 3121 // return $result; 3122 // } 3123 // 3124 // // If another thread has been waiting for this lock, 3125 // // it will go thru the above procedure, but will have no 3126 // // real effect 3127 // $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); 3128 // if (DB::isError($result)) { 3129 // return $result; 3130 // } 3131 return true; 3132 } 3133 3134 /** 3135 * Quotes a string so it can be safely used as a table or column name 3136 * 3137 * MySQL can't handle the backtick character (<kbd>`</kbd>) in 3138 * table or column names. 3139 * 3140 * @param string $str identifier name to be quoted 3141 * @return string quoted identifier string 3142 * @see DB_common::quoteIdentifier() 3143 * @access private 3144 */ 3145 function quoteIdentifier($str) 3146 { 3147 return '`' . $str . '`'; 3148 } 3149 3150 /** 3151 * Escapes a string according to the current DBMS's standards 3152 * 3153 * @param string $str the string to be escaped 3154 * @return string the escaped string 3155 * @see DB_common::quoteSmart() 3156 * @todo Implement mock DB_mysql::escapeSimple() 3157 */ 3158 function escapeSimple($str) 3159 { 3160 // if (function_exists('mysql_real_escape_string')) { 3161 // return @mysql_real_escape_string($str, $this->connection); 3162 // } else { 3163 // return @mysql_escape_string($str); 3164 // } 3165 } 3166 3167 /** 3168 * Changes a query string for various DBMS specific reasons 3169 * 3170 * This little hack lets you know how many rows were deleted 3171 * when running a "DELETE FROM table" query. Only implemented 3172 * if the DB_PORTABILITY_DELETE_COUNT portability option is on. 3173 * 3174 * @param string $query the query string to modify 3175 * @return string the modified query string 3176 * @see DB_common::setOption() 3177 * @todo Implement mock DB_mysql::modifyQuery() 3178 */ 3179 protected function modifyQuery($query) 3180 { 3181 // if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { 3182 // // "DELETE FROM table" gives 0 affected rows in MySQL. 3183 // // This little hack lets you know how many rows were deleted. 3184 // if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { 3185 // $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', 3186 // 'DELETE FROM \1 WHERE 1=1', $query); 3187 // } 3188 // } 3189 // return $query; 3190 } 3191 3192 /** 3193 * Adds LIMIT clauses to a query string according to current DBMS standards 3194 * 3195 * @param string $query the query to modify 3196 * @param int $from the row to start to fetching (0 = the first row) 3197 * @param int $count the numbers of rows to fetch 3198 * @param mixed $params array, string or numeric data to be used in 3199 * execution of the statement. Quantity of items 3200 * passed must match quantity of placeholders in 3201 * query: meaning 1 placeholder for non-array 3202 * parameters or 1 placeholder per array element. 3203 * @return string the query string with LIMIT clauses added 3204 * @todo Implement mock DB_mysql::modifyLimitQuery() 3205 */ 3206 protected function modifyLimitQuery($query, $from, $count, $params = array()) 3207 { 3208 // if (DB::isManip($query)) { 3209 // return $query . " LIMIT $count"; 3210 // } else { 3211 // return $query . " LIMIT $from, $count"; 3212 // } 3213 } 3214 3215 /** 3216 * Produces a DB_Error object regarding the current problem 3217 * 3218 * @param int $errno if the error is being manually raised pass a 3219 * DB_ERROR* constant here. If this isn't passed 3220 * the error information gathered from the DBMS. 3221 * 3222 * @return object the DB_Error object 3223 * @see DB_common::raiseError(), 3224 * DB_mysql::errorNative(), DB_common::errorCode() 3225 * @todo Implement mock DB_mysql::mysqlRaiseError() 3226 */ 3227 function mysqlRaiseError($errno = null) 3228 { 3229 // if ($errno === null) { 3230 // if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { 3231 // $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; 3232 // $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; 3233 // $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; 3234 // } else { 3235 // // Doing this in case mode changes during runtime. 3236 // $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; 3237 // $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; 3238 // $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; 3239 // } 3240 // $errno = $this->errorCode(mysql_errno($this->connection)); 3241 // } 3242 // return $this->raiseError($errno, null, null, null, 3243 // @mysql_errno($this->connection) . ' ** ' . 3244 // @mysql_error($this->connection)); 3245 } 3246 3247 /** 3248 * Gets the DBMS' native error code produced by the last query 3249 * 3250 * @return int the DBMS' error code 3251 * @todo Implement mock DB_mysql::errorNative() 3252 */ 3253 function errorNative() 3254 { 3255 // return @mysql_errno($this->connection); 3256 } 3257 3258 /** 3259 * Returns information about a table or a result set 3260 * 3261 * @param object|string $result DB_result object from a query or a 3262 * string containing the name of a table. 3263 * While this also accepts a query result 3264 * resource identifier, this behavior is 3265 * deprecated. 3266 * @param int $mode a valid tableInfo mode 3267 * 3268 * @return array an associative array with the information requested. 3269 * A DB_Error object on failure. 3270 * 3271 * @see DB_common::tableInfo() 3272 * @todo Implement mock DB_mysql::tableInfo() 3273 */ 3274 function tableInfo($result, $mode = null) 3275 { 3276 // We only support the default mode 3277 PHPUnit2_Framework_Assert::assertNull($mode); 3278 3279 // We only support table name as first argument 3280 PHPUnit2_Framework_Assert::assertTrue(is_string($result)); 3281 3282 // Look up table name in the mock database 3283 foreach(self::$database as $table => $value) { 3284 if ($result == $table) { 3285 return $value['info']; 3286 } 3287 } 3288 PHPUnit2_Framework_Assert::fail("DB_mysql::tableInfo called" 3289 ." with unknown table $result"); 3290 } 3291 3292 /** 3293 * Obtains the query string needed for listing a given type of objects 3294 * 3295 * @param string $type the kind of objects you want to retrieve 3296 * 3297 * @return string the SQL query string or null if the driver doesn't 3298 * support the object type requested 3299 * 3300 * @see DB_common::getListOf() 3301 */ 3302 protected function getSpecialQuery($type) 3303 { 3304 switch ($type) { 3305 case 'tables': 3306 return 'SHOW TABLES'; 3307 case 'users': 3308 return 'SELECT DISTINCT User FROM mysql.user'; 3309 case 'databases': 3310 return 'SHOW DATABASES'; 3311 default: 3312 return null; 3313 } 3314 } 3315 } 3316 3317 // -- set Emacs parameters -- 3318 // Local variables: 3319 // tab-width: 4 3320 // c-basic-offset: 4 3321 // c-hanging-comment-ender-p: nil 3322 // indent-tabs-mode: nil 3323 // End: 3324 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 20:04:38 2007 | par Balluche grâce à PHPXref 0.7 |