[ Index ] |
|
Code source de SPIP Agora 1.4 |
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ 3 // +----------------------------------------------------------------------+ 4 // | PHP Version 4 | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 1997-2004 The PHP Group | 7 // +----------------------------------------------------------------------+ 8 // | This source file is subject to version 2.02 of the PHP license, | 9 // | that is bundled with this package in the file LICENSE, and is | 10 // | available at through the world-wide-web at | 11 // | http://www.php.net/license/2_02.txt. | 12 // | If you did not receive a copy of the PHP license and are unable to | 13 // | obtain it through the world-wide-web, please send a note to | 14 // | license@php.net so we can mail you a copy immediately. | 15 // +----------------------------------------------------------------------+ 16 // | Authors: Sterling Hughes <sterling@php.net> | 17 // | Antônio Carlos Venâncio Júnior <floripa@php.net> | 18 // | Maintainer: Daniel Convissor <danielc@php.net> | 19 // +----------------------------------------------------------------------+ 20 // 21 // $Id: sybase.php,v 1.52 2004/07/12 19:07:34 danielc Exp $ 22 23 24 // TODO 25 // - This driver may fail with multiple connections under the same 26 // user/pass/host and different databases 27 28 29 require_once 'DB/common.php'; 30 31 /** 32 * Database independent query interface definition for PHP's Sybase 33 * extension. 34 * 35 * @package DB 36 * @version $Id: sybase.php,v 1.52 2004/07/12 19:07:34 danielc Exp $ 37 * @category Database 38 * @author Sterling Hughes <sterling@php.net> 39 * @author Antônio Carlos Venâncio Júnior <floripa@php.net> 40 */ 41 class DB_sybase extends DB_common 42 { 43 // {{{ properties 44 45 var $connection; 46 var $phptype, $dbsyntax; 47 var $prepare_tokens = array(); 48 var $prepare_types = array(); 49 var $transaction_opcount = 0; 50 var $autocommit = true; 51 52 // }}} 53 // {{{ constructor 54 55 /** 56 * DB_sybase constructor. 57 * 58 * @access public 59 */ 60 function DB_sybase() 61 { 62 $this->DB_common(); 63 $this->phptype = 'sybase'; 64 $this->dbsyntax = 'sybase'; 65 $this->features = array( 66 'prepare' => false, 67 'pconnect' => true, 68 'transactions' => false, 69 'limit' => 'emulate' 70 ); 71 $this->errorcode_map = array( 72 ); 73 } 74 75 // }}} 76 // {{{ connect() 77 78 /** 79 * Connect to a database and log in as the specified user. 80 * 81 * @param $dsn the data source name (see DB::parseDSN for syntax) 82 * @param $persistent (optional) whether the connection should 83 * be persistent 84 * @access public 85 * @return int DB_OK on success, a DB error on failure 86 */ 87 function connect($dsninfo, $persistent = false) 88 { 89 if (!DB::assertExtension('sybase') && 90 !DB::assertExtension('sybase_ct')) 91 { 92 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); 93 } 94 95 $this->dsn = $dsninfo; 96 97 $interface = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost'; 98 $connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect'; 99 $dsninfo['password'] = !empty($dsninfo['password']) ? $dsninfo['password'] : false; 100 $dsninfo['charset'] = isset($dsninfo['charset']) ? $dsninfo['charset'] : false; 101 $dsninfo['appname'] = isset($dsninfo['appname']) ? $dsninfo['appname'] : false; 102 103 if ($interface && $dsninfo['username']) { 104 $conn = @$connect_function($interface, $dsninfo['username'], 105 $dsninfo['password'], 106 $dsninfo['charset'], 107 $dsninfo['appname']); 108 } else { 109 $conn = false; 110 } 111 112 if (!$conn) { 113 return $this->raiseError(DB_ERROR_CONNECT_FAILED); 114 } 115 116 if ($dsninfo['database']) { 117 if (!@sybase_select_db($dsninfo['database'], $conn)) { 118 return $this->raiseError(DB_ERROR_NODBSELECTED, null, 119 null, null, @sybase_get_last_message()); 120 } 121 $this->_db = $dsninfo['database']; 122 } 123 124 $this->connection = $conn; 125 return DB_OK; 126 } 127 128 // }}} 129 // {{{ disconnect() 130 131 /** 132 * Log out and disconnect from the database. 133 * 134 * @access public 135 * 136 * @return bool true on success, false if not connected. 137 */ 138 function disconnect() 139 { 140 $ret = @sybase_close($this->connection); 141 $this->connection = null; 142 return $ret; 143 } 144 145 // }}} 146 // {{{ errorNative() 147 148 /** 149 * Get the last server error messge (if any) 150 * 151 * @return string sybase last error message 152 */ 153 function errorNative() 154 { 155 return @sybase_get_last_message(); 156 } 157 158 // }}} 159 // {{{ errorCode() 160 161 /** 162 * Determine PEAR::DB error code from the database's text error message. 163 * 164 * @param string $errormsg error message returned from the database 165 * @return integer an error number from a DB error constant 166 */ 167 function errorCode($errormsg) 168 { 169 static $error_regexps; 170 if (!isset($error_regexps)) { 171 $error_regexps = array( 172 '/Incorrect syntax near/' 173 => DB_ERROR_SYNTAX, 174 '/^Unclosed quote before the character string [\"\'].*[\"\']\./' 175 => DB_ERROR_SYNTAX, 176 '/Implicit conversion from datatype [\"\'].+[\"\'] to [\"\'].+[\"\'] is not allowed\./' 177 => DB_ERROR_INVALID_NUMBER, 178 '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./' 179 => DB_ERROR_NOSUCHTABLE, 180 '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./' 181 => DB_ERROR_ACCESS_VIOLATION, 182 '/^.+ permission denied on object .+, database .+, owner .+/' 183 => DB_ERROR_ACCESS_VIOLATION, 184 '/^.* permission denied, database .+, owner .+/' 185 => DB_ERROR_ACCESS_VIOLATION, 186 '/[^.*] not found\./' 187 => DB_ERROR_NOSUCHTABLE, 188 '/There is already an object named/' 189 => DB_ERROR_ALREADY_EXISTS, 190 '/Invalid column name/' 191 => DB_ERROR_NOSUCHFIELD, 192 '/does not allow null values/' 193 => DB_ERROR_CONSTRAINT_NOT_NULL, 194 '/Command has been aborted/' 195 => DB_ERROR_CONSTRAINT, 196 ); 197 } 198 199 foreach ($error_regexps as $regexp => $code) { 200 if (preg_match($regexp, $errormsg)) { 201 return $code; 202 } 203 } 204 return DB_ERROR; 205 } 206 207 // }}} 208 // {{{ sybaseRaiseError() 209 210 /** 211 * Gather information about an error, then use that info to create a 212 * DB error object and finally return that object. 213 * 214 * @param integer $errno PEAR error number (usually a DB constant) if 215 * manually raising an error 216 * @return object DB error object 217 * @see errorNative() 218 * @see errorCode() 219 * @see DB_common::raiseError() 220 */ 221 function sybaseRaiseError($errno = null) 222 { 223 $native = $this->errorNative(); 224 if ($errno === null) { 225 $errno = $this->errorCode($native); 226 } 227 return $this->raiseError($errno, null, null, null, $native); 228 } 229 230 // }}} 231 // {{{ simpleQuery() 232 233 /** 234 * Send a query to Sybase and return the results as a Sybase resource 235 * identifier. 236 * 237 * @param the SQL query 238 * 239 * @access public 240 * 241 * @return mixed returns a valid Sybase result for successful SELECT 242 * queries, DB_OK for other successful queries. A DB error is 243 * returned on failure. 244 */ 245 function simpleQuery($query) 246 { 247 $ismanip = DB::isManip($query); 248 $this->last_query = $query; 249 if (!@sybase_select_db($this->_db, $this->connection)) { 250 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); 251 } 252 $query = $this->modifyQuery($query); 253 if (!$this->autocommit && $ismanip) { 254 if ($this->transaction_opcount == 0) { 255 $result = @sybase_query('BEGIN TRANSACTION', $this->connection); 256 if (!$result) { 257 return $this->sybaseRaiseError(); 258 } 259 } 260 $this->transaction_opcount++; 261 } 262 $result = @sybase_query($query, $this->connection); 263 if (!$result) { 264 return $this->sybaseRaiseError(); 265 } 266 if (is_resource($result)) { 267 $numrows = $this->numRows($result); 268 if (is_object($numrows)) { 269 return $numrows; 270 } 271 $this->num_rows[(int)$result] = $numrows; 272 return $result; 273 } 274 // Determine which queries that should return data, and which 275 // should return an error code only. 276 return $ismanip ? DB_OK : $result; 277 } 278 279 // }}} 280 // {{{ nextResult() 281 282 /** 283 * Move the internal sybase result pointer to the next available result 284 * 285 * @param a valid sybase result resource 286 * 287 * @access public 288 * 289 * @return true if a result is available otherwise return false 290 */ 291 function nextResult($result) 292 { 293 return false; 294 } 295 296 // }}} 297 // {{{ fetchInto() 298 299 /** 300 * Fetch a row and insert the data into an existing array. 301 * 302 * Formating of the array and the data therein are configurable. 303 * See DB_result::fetchInto() for more information. 304 * 305 * @param resource $result query result identifier 306 * @param array $arr (reference) array where data from the row 307 * should be placed 308 * @param int $fetchmode how the resulting array should be indexed 309 * @param int $rownum the row number to fetch 310 * 311 * @return mixed DB_OK on success, null when end of result set is 312 * reached or on failure 313 * 314 * @see DB_result::fetchInto() 315 * @access private 316 */ 317 function fetchInto($result, &$arr, $fetchmode, $rownum=null) 318 { 319 if ($rownum !== null) { 320 if (!@sybase_data_seek($result, $rownum)) { 321 return null; 322 } 323 } 324 if ($fetchmode & DB_FETCHMODE_ASSOC) { 325 if (function_exists('sybase_fetch_assoc')) { 326 $arr = @sybase_fetch_assoc($result); 327 } else { 328 if ($arr = @sybase_fetch_array($result)) { 329 foreach ($arr as $key => $value) { 330 if (is_int($key)) { 331 unset($arr[$key]); 332 } 333 } 334 } 335 } 336 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { 337 $arr = array_change_key_case($arr, CASE_LOWER); 338 } 339 } else { 340 $arr = @sybase_fetch_row($result); 341 } 342 if (!$arr) { 343 // reported not work as seems that sybase_get_last_message() 344 // always return a message here 345 //if ($errmsg = @sybase_get_last_message()) { 346 // return $this->sybaseRaiseError($errmsg); 347 //} else { 348 return null; 349 //} 350 } 351 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { 352 $this->_rtrimArrayValues($arr); 353 } 354 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { 355 $this->_convertNullArrayValuesToEmpty($arr); 356 } 357 return DB_OK; 358 } 359 360 // }}} 361 // {{{ freeResult() 362 363 /** 364 * Free the internal resources associated with $result. 365 * 366 * @param $result Sybase result identifier 367 * 368 * @access public 369 * 370 * @return bool true on success, false if $result is invalid 371 */ 372 function freeResult($result) 373 { 374 unset($this->num_rows[(int)$result]); 375 return @sybase_free_result($result); 376 } 377 378 // }}} 379 // {{{ numCols() 380 381 /** 382 * Get the number of columns in a result set. 383 * 384 * @param $result Sybase result identifier 385 * 386 * @access public 387 * 388 * @return int the number of columns per row in $result 389 */ 390 function numCols($result) 391 { 392 $cols = @sybase_num_fields($result); 393 if (!$cols) { 394 return $this->sybaseRaiseError(); 395 } 396 return $cols; 397 } 398 399 // }}} 400 // {{{ numRows() 401 402 /** 403 * Get the number of rows in a result set. 404 * 405 * @param $result Sybase result identifier 406 * 407 * @access public 408 * 409 * @return int the number of rows in $result 410 */ 411 function numRows($result) 412 { 413 $rows = @sybase_num_rows($result); 414 if ($rows === false) { 415 return $this->sybaseRaiseError(); 416 } 417 return $rows; 418 } 419 420 // }}} 421 // {{{ affectedRows() 422 423 /** 424 * Gets the number of rows affected by the data manipulation 425 * query. For other queries, this function returns 0. 426 * 427 * @return number of rows affected by the last query 428 */ 429 function affectedRows() 430 { 431 if (DB::isManip($this->last_query)) { 432 $result = @sybase_affected_rows($this->connection); 433 } else { 434 $result = 0; 435 } 436 return $result; 437 } 438 439 // }}} 440 // {{{ nextId() 441 442 /** 443 * Returns the next free id in a sequence 444 * 445 * @param string $seq_name name of the sequence 446 * @param boolean $ondemand when true, the seqence is automatically 447 * created if it does not exist 448 * 449 * @return int the next id number in the sequence. DB_Error if problem. 450 * 451 * @internal 452 * @see DB_common::nextID() 453 * @access public 454 */ 455 function nextId($seq_name, $ondemand = true) 456 { 457 $seqname = $this->getSequenceName($seq_name); 458 if (!@sybase_select_db($this->_db, $this->connection)) { 459 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); 460 } 461 $repeat = 0; 462 do { 463 $this->pushErrorHandling(PEAR_ERROR_RETURN); 464 $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); 465 $this->popErrorHandling(); 466 if ($ondemand && DB::isError($result) && 467 ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) 468 { 469 $repeat = 1; 470 $result = $this->createSequence($seq_name); 471 if (DB::isError($result)) { 472 return $this->raiseError($result); 473 } 474 } elseif (!DB::isError($result)) { 475 $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); 476 $repeat = 0; 477 } else { 478 $repeat = false; 479 } 480 } while ($repeat); 481 if (DB::isError($result)) { 482 return $this->raiseError($result); 483 } 484 $result = $result->fetchRow(DB_FETCHMODE_ORDERED); 485 return $result[0]; 486 } 487 488 /** 489 * Creates a new sequence 490 * 491 * @param string $seq_name name of the new sequence 492 * 493 * @return int DB_OK on success. A DB_Error object is returned if 494 * problems arise. 495 * 496 * @internal 497 * @see DB_common::createSequence() 498 * @access public 499 */ 500 function createSequence($seq_name) 501 { 502 $seqname = $this->getSequenceName($seq_name); 503 return $this->query("CREATE TABLE $seqname ". 504 '(id numeric(10,0) IDENTITY NOT NULL ,' . 505 'vapor int NULL)'); 506 } 507 508 // }}} 509 // {{{ dropSequence() 510 511 /** 512 * Deletes a sequence 513 * 514 * @param string $seq_name name of the sequence to be deleted 515 * 516 * @return int DB_OK on success. DB_Error if problems. 517 * 518 * @internal 519 * @see DB_common::dropSequence() 520 * @access public 521 */ 522 function dropSequence($seq_name) 523 { 524 $seqname = $this->getSequenceName($seq_name); 525 return $this->query("DROP TABLE $seqname"); 526 } 527 528 // }}} 529 // {{{ getSpecialQuery() 530 531 /** 532 * Returns the query needed to get some backend info 533 * @param string $type What kind of info you want to retrieve 534 * @return string The SQL query string 535 */ 536 function getSpecialQuery($type) 537 { 538 switch ($type) { 539 case 'tables': 540 return "select name from sysobjects where type = 'U' order by name"; 541 case 'views': 542 return "select name from sysobjects where type = 'V'"; 543 default: 544 return null; 545 } 546 } 547 548 // }}} 549 // {{{ autoCommit() 550 551 /** 552 * Enable/disable automatic commits 553 */ 554 function autoCommit($onoff = false) 555 { 556 // XXX if $this->transaction_opcount > 0, we should probably 557 // issue a warning here. 558 $this->autocommit = $onoff ? true : false; 559 return DB_OK; 560 } 561 562 // }}} 563 // {{{ commit() 564 565 /** 566 * Commit the current transaction. 567 */ 568 function commit() 569 { 570 if ($this->transaction_opcount > 0) { 571 if (!@sybase_select_db($this->_db, $this->connection)) { 572 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); 573 } 574 $result = @sybase_query('COMMIT', $this->connection); 575 $this->transaction_opcount = 0; 576 if (!$result) { 577 return $this->sybaseRaiseError(); 578 } 579 } 580 return DB_OK; 581 } 582 583 // }}} 584 // {{{ rollback() 585 586 /** 587 * Roll back (undo) the current transaction. 588 */ 589 function rollback() 590 { 591 if ($this->transaction_opcount > 0) { 592 if (!@sybase_select_db($this->_db, $this->connection)) { 593 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); 594 } 595 $result = @sybase_query('ROLLBACK', $this->connection); 596 $this->transaction_opcount = 0; 597 if (!$result) { 598 return $this->sybaseRaiseError(); 599 } 600 } 601 return DB_OK; 602 } 603 604 // }}} 605 // {{{ tableInfo() 606 607 /** 608 * Returns information about a table or a result set. 609 * 610 * NOTE: only supports 'table' and 'flags' if <var>$result</var> 611 * is a table name. 612 * 613 * @param object|string $result DB_result object from a query or a 614 * string containing the name of a table 615 * @param int $mode a valid tableInfo mode 616 * @return array an associative array with the information requested 617 * or an error object if something is wrong 618 * @access public 619 * @internal 620 * @since 1.6.0 621 * @see DB_common::tableInfo() 622 */ 623 function tableInfo($result, $mode = null) 624 { 625 if (isset($result->result)) { 626 /* 627 * Probably received a result object. 628 * Extract the result resource identifier. 629 */ 630 $id = $result->result; 631 $got_string = false; 632 } elseif (is_string($result)) { 633 /* 634 * Probably received a table name. 635 * Create a result resource identifier. 636 */ 637 if (!@sybase_select_db($this->_db, $this->connection)) { 638 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); 639 } 640 $id = @sybase_query("SELECT * FROM $result WHERE 1=0", 641 $this->connection); 642 $got_string = true; 643 } else { 644 /* 645 * Probably received a result resource identifier. 646 * Copy it. 647 * Deprecated. Here for compatibility only. 648 */ 649 $id = $result; 650 $got_string = false; 651 } 652 653 if (!is_resource($id)) { 654 return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA); 655 } 656 657 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { 658 $case_func = 'strtolower'; 659 } else { 660 $case_func = 'strval'; 661 } 662 663 $count = @sybase_num_fields($id); 664 665 // made this IF due to performance (one if is faster than $count if's) 666 if (!$mode) { 667 668 for ($i=0; $i<$count; $i++) { 669 $f = @sybase_fetch_field($id, $i); 670 671 // column_source is often blank 672 if ($got_string) { 673 $res[$i]['table'] = $case_func($result); 674 } else { 675 $res[$i]['table'] = $case_func($f->column_source); 676 } 677 $res[$i]['name'] = $case_func($f->name); 678 $res[$i]['type'] = $f->type; 679 $res[$i]['len'] = $f->max_length; 680 if ($res[$i]['table']) { 681 $res[$i]['flags'] = $this->_sybase_field_flags( 682 $res[$i]['table'], $res[$i]['name']); 683 } else { 684 $res[$i]['flags'] = ''; 685 } 686 } 687 688 } else { 689 // get full info 690 691 $res['num_fields'] = $count; 692 693 for ($i=0; $i<$count; $i++) { 694 $f = @sybase_fetch_field($id, $i); 695 696 // column_source is often blank 697 if ($got_string) { 698 $res[$i]['table'] = $case_func($result); 699 } else { 700 $res[$i]['table'] = $case_func($f->column_source); 701 } 702 $res[$i]['name'] = $case_func($f->name); 703 $res[$i]['type'] = $f->type; 704 $res[$i]['len'] = $f->max_length; 705 if ($res[$i]['table']) { 706 $res[$i]['flags'] = $this->_sybase_field_flags( 707 $res[$i]['table'], $res[$i]['name']); 708 } else { 709 $res[$i]['flags'] = ''; 710 } 711 712 if ($mode & DB_TABLEINFO_ORDER) { 713 $res['order'][$res[$i]['name']] = $i; 714 } 715 if ($mode & DB_TABLEINFO_ORDERTABLE) { 716 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 717 } 718 } 719 } 720 721 // free the result only if we were called on a table 722 if ($got_string) { 723 @sybase_free_result($id); 724 } 725 return $res; 726 } 727 728 // }}} 729 // {{{ _sybase_field_flags() 730 731 /** 732 * Get the flags for a field. 733 * 734 * Currently supports: 735 * + <samp>unique_key</samp> (unique index, unique check or primary_key) 736 * + <samp>multiple_key</samp> (multi-key index) 737 * 738 * @param string $table table name 739 * @param string $column field name 740 * @return string space delimited string of flags. Empty string if none. 741 * @access private 742 */ 743 function _sybase_field_flags($table, $column) 744 { 745 static $tableName = null; 746 static $flags = array(); 747 748 if ($table != $tableName) { 749 $flags = array(); 750 $tableName = $table; 751 752 // get unique/primary keys 753 $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC); 754 755 if (!isset($res[0]['index_description'])) { 756 return ''; 757 } 758 759 foreach ($res as $val) { 760 $keys = explode(', ', trim($val['index_keys'])); 761 762 if (sizeof($keys) > 1) { 763 foreach ($keys as $key) { 764 $this->_add_flag($flags[$key], 'multiple_key'); 765 } 766 } 767 768 if (strpos($val['index_description'], 'unique')) { 769 foreach ($keys as $key) { 770 $this->_add_flag($flags[$key], 'unique_key'); 771 } 772 } 773 } 774 775 } 776 777 if (array_key_exists($column, $flags)) { 778 return(implode(' ', $flags[$column])); 779 } 780 781 return ''; 782 } 783 784 // }}} 785 // {{{ _add_flag() 786 787 /** 788 * Adds a string to the flags array if the flag is not yet in there 789 * - if there is no flag present the array is created. 790 * 791 * @param array $array reference of flags array to add a value to 792 * @param mixed $value value to add to the flag array 793 * @access private 794 */ 795 function _add_flag(&$array, $value) 796 { 797 if (!is_array($array)) { 798 $array = array($value); 799 } elseif (!in_array($value, $array)) { 800 array_push($array, $value); 801 } 802 } 803 804 // }}} 805 // {{{ quoteIdentifier() 806 807 /** 808 * Quote a string so it can be safely used as a table / column name 809 * 810 * Quoting style depends on which database driver is being used. 811 * 812 * @param string $str identifier name to be quoted 813 * 814 * @return string quoted identifier string 815 * 816 * @since 1.6.0 817 * @access public 818 */ 819 function quoteIdentifier($str) 820 { 821 return '[' . str_replace(']', ']]', $str) . ']'; 822 } 823 824 // }}} 825 826 } 827 828 /* 829 * Local variables: 830 * tab-width: 4 831 * c-basic-offset: 4 832 * End: 833 */ 834 835 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Feb 24 14:40:03 2007 | par Balluche grâce à PHPXref 0.7 |