[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5 /** 6 * The PEAR DB driver for PHP's mssql extension 7 * for interacting with Microsoft SQL Server databases 8 * 9 * PHP versions 4 and 5 10 * 11 * LICENSE: This source file is subject to version 3.0 of the PHP license 12 * that is available through the world-wide-web at the following URI: 13 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 14 * the PHP License and are unable to obtain it through the web, please 15 * send a note to license@php.net so we can mail you a copy immediately. 16 * 17 * @category Database 18 * @package DB 19 * @author Sterling Hughes <sterling@php.net> 20 * @author Daniel Convissor <danielc@php.net> 21 * @copyright 1997-2005 The PHP Group 22 * @license http://www.php.net/license/3_0.txt PHP License 3.0 23 * @version CVS: $Id: mssql.php,v 1.90 2007/01/12 05:16:22 aharvey Exp $ 24 * @link http://pear.php.net/package/DB 25 */ 26 27 /** 28 * Obtain the DB_common class so it can be extended from 29 */ 30 require_once 'DB/common.php'; 31 32 /** 33 * The methods PEAR DB uses to interact with PHP's mssql extension 34 * for interacting with Microsoft SQL Server databases 35 * 36 * These methods overload the ones declared in DB_common. 37 * 38 * DB's mssql driver is only for Microsfoft SQL Server databases. 39 * 40 * If you're connecting to a Sybase database, you MUST specify "sybase" 41 * as the "phptype" in the DSN. 42 * 43 * This class only works correctly if you have compiled PHP using 44 * --with-mssql=[dir_to_FreeTDS]. 45 * 46 * @category Database 47 * @package DB 48 * @author Sterling Hughes <sterling@php.net> 49 * @author Daniel Convissor <danielc@php.net> 50 * @copyright 1997-2005 The PHP Group 51 * @license http://www.php.net/license/3_0.txt PHP License 3.0 52 * @version Release: 1.7.9 53 * @link http://pear.php.net/package/DB 54 */ 55 class DB_mssql extends DB_common 56 { 57 // {{{ properties 58 59 /** 60 * The DB driver type (mysql, oci8, odbc, etc.) 61 * @var string 62 */ 63 var $phptype = 'mssql'; 64 65 /** 66 * The database syntax variant to be used (db2, access, etc.), if any 67 * @var string 68 */ 69 var $dbsyntax = 'mssql'; 70 71 /** 72 * The capabilities of this DB implementation 73 * 74 * The 'new_link' element contains the PHP version that first provided 75 * new_link support for this DBMS. Contains false if it's unsupported. 76 * 77 * Meaning of the 'limit' element: 78 * + 'emulate' = emulate with fetch row by number 79 * + 'alter' = alter the query 80 * + false = skip rows 81 * 82 * @var array 83 */ 84 var $features = array( 85 'limit' => 'emulate', 86 'new_link' => false, 87 'numrows' => true, 88 'pconnect' => true, 89 'prepare' => false, 90 'ssl' => false, 91 'transactions' => true, 92 ); 93 94 /** 95 * A mapping of native error codes to DB error codes 96 * @var array 97 */ 98 // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX 99 var $errorcode_map = array( 100 102 => DB_ERROR_SYNTAX, 101 110 => DB_ERROR_VALUE_COUNT_ON_ROW, 102 155 => DB_ERROR_NOSUCHFIELD, 103 156 => DB_ERROR_SYNTAX, 104 170 => DB_ERROR_SYNTAX, 105 207 => DB_ERROR_NOSUCHFIELD, 106 208 => DB_ERROR_NOSUCHTABLE, 107 245 => DB_ERROR_INVALID_NUMBER, 108 319 => DB_ERROR_SYNTAX, 109 321 => DB_ERROR_NOSUCHFIELD, 110 325 => DB_ERROR_SYNTAX, 111 336 => DB_ERROR_SYNTAX, 112 515 => DB_ERROR_CONSTRAINT_NOT_NULL, 113 547 => DB_ERROR_CONSTRAINT, 114 1018 => DB_ERROR_SYNTAX, 115 1035 => DB_ERROR_SYNTAX, 116 1913 => DB_ERROR_ALREADY_EXISTS, 117 2209 => DB_ERROR_SYNTAX, 118 2223 => DB_ERROR_SYNTAX, 119 2248 => DB_ERROR_SYNTAX, 120 2256 => DB_ERROR_SYNTAX, 121 2257 => DB_ERROR_SYNTAX, 122 2627 => DB_ERROR_CONSTRAINT, 123 2714 => DB_ERROR_ALREADY_EXISTS, 124 3607 => DB_ERROR_DIVZERO, 125 3701 => DB_ERROR_NOSUCHTABLE, 126 7630 => DB_ERROR_SYNTAX, 127 8134 => DB_ERROR_DIVZERO, 128 9303 => DB_ERROR_SYNTAX, 129 9317 => DB_ERROR_SYNTAX, 130 9318 => DB_ERROR_SYNTAX, 131 9331 => DB_ERROR_SYNTAX, 132 9332 => DB_ERROR_SYNTAX, 133 15253 => DB_ERROR_SYNTAX, 134 ); 135 136 /** 137 * The raw database connection created by PHP 138 * @var resource 139 */ 140 var $connection; 141 142 /** 143 * The DSN information for connecting to a database 144 * @var array 145 */ 146 var $dsn = array(); 147 148 149 /** 150 * Should data manipulation queries be committed automatically? 151 * @var bool 152 * @access private 153 */ 154 var $autocommit = true; 155 156 /** 157 * The quantity of transactions begun 158 * 159 * {@internal While this is private, it can't actually be designated 160 * private in PHP 5 because it is directly accessed in the test suite.}} 161 * 162 * @var integer 163 * @access private 164 */ 165 var $transaction_opcount = 0; 166 167 /** 168 * The database specified in the DSN 169 * 170 * It's a fix to allow calls to different databases in the same script. 171 * 172 * @var string 173 * @access private 174 */ 175 var $_db = null; 176 177 178 // }}} 179 // {{{ constructor 180 181 /** 182 * This constructor calls <kbd>$this->DB_common()</kbd> 183 * 184 * @return void 185 */ 186 function DB_mssql() 187 { 188 $this->DB_common(); 189 } 190 191 // }}} 192 // {{{ connect() 193 194 /** 195 * Connect to the database server, log in and open the database 196 * 197 * Don't call this method directly. Use DB::connect() instead. 198 * 199 * @param array $dsn the data source name 200 * @param bool $persistent should the connection be persistent? 201 * 202 * @return int DB_OK on success. A DB_Error object on failure. 203 */ 204 function connect($dsn, $persistent = false) 205 { 206 if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase') 207 && !PEAR::loadExtension('sybase_ct')) 208 { 209 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); 210 } 211 212 $this->dsn = $dsn; 213 if ($dsn['dbsyntax']) { 214 $this->dbsyntax = $dsn['dbsyntax']; 215 } 216 217 $params = array( 218 $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost', 219 $dsn['username'] ? $dsn['username'] : null, 220 $dsn['password'] ? $dsn['password'] : null, 221 ); 222 if ($dsn['port']) { 223 $params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':') 224 . $dsn['port']; 225 } 226 227 $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect'; 228 229 $this->connection = @call_user_func_array($connect_function, $params); 230 231 if (!$this->connection) { 232 return $this->raiseError(DB_ERROR_CONNECT_FAILED, 233 null, null, null, 234 @mssql_get_last_message()); 235 } 236 if ($dsn['database']) { 237 if (!@mssql_select_db($dsn['database'], $this->connection)) { 238 return $this->raiseError(DB_ERROR_NODBSELECTED, 239 null, null, null, 240 @mssql_get_last_message()); 241 } 242 $this->_db = $dsn['database']; 243 } 244 return DB_OK; 245 } 246 247 // }}} 248 // {{{ disconnect() 249 250 /** 251 * Disconnects from the database server 252 * 253 * @return bool TRUE on success, FALSE on failure 254 */ 255 function disconnect() 256 { 257 $ret = @mssql_close($this->connection); 258 $this->connection = null; 259 return $ret; 260 } 261 262 // }}} 263 // {{{ simpleQuery() 264 265 /** 266 * Sends a query to the database server 267 * 268 * @param string the SQL query string 269 * 270 * @return mixed + a PHP result resrouce for successful SELECT queries 271 * + the DB_OK constant for other successful queries 272 * + a DB_Error object on failure 273 */ 274 function simpleQuery($query) 275 { 276 $ismanip = $this->_checkManip($query); 277 $this->last_query = $query; 278 if (!@mssql_select_db($this->_db, $this->connection)) { 279 return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); 280 } 281 $query = $this->modifyQuery($query); 282 if (!$this->autocommit && $ismanip) { 283 if ($this->transaction_opcount == 0) { 284 $result = @mssql_query('BEGIN TRAN', $this->connection); 285 if (!$result) { 286 return $this->mssqlRaiseError(); 287 } 288 } 289 $this->transaction_opcount++; 290 } 291 $result = @mssql_query($query, $this->connection); 292 if (!$result) { 293 return $this->mssqlRaiseError(); 294 } 295 // Determine which queries that should return data, and which 296 // should return an error code only. 297 return $ismanip ? DB_OK : $result; 298 } 299 300 // }}} 301 // {{{ nextResult() 302 303 /** 304 * Move the internal mssql result pointer to the next available result 305 * 306 * @param a valid fbsql result resource 307 * 308 * @access public 309 * 310 * @return true if a result is available otherwise return false 311 */ 312 function nextResult($result) 313 { 314 return @mssql_next_result($result); 315 } 316 317 // }}} 318 // {{{ fetchInto() 319 320 /** 321 * Places a row from the result set into the given array 322 * 323 * Formating of the array and the data therein are configurable. 324 * See DB_result::fetchInto() for more information. 325 * 326 * This method is not meant to be called directly. Use 327 * DB_result::fetchInto() instead. It can't be declared "protected" 328 * because DB_result is a separate object. 329 * 330 * @param resource $result the query result resource 331 * @param array $arr the referenced array to put the data in 332 * @param int $fetchmode how the resulting array should be indexed 333 * @param int $rownum the row number to fetch (0 = first row) 334 * 335 * @return mixed DB_OK on success, NULL when the end of a result set is 336 * reached or on failure 337 * 338 * @see DB_result::fetchInto() 339 */ 340 function fetchInto($result, &$arr, $fetchmode, $rownum = null) 341 { 342 if ($rownum !== null) { 343 if (!@mssql_data_seek($result, $rownum)) { 344 return null; 345 } 346 } 347 if ($fetchmode & DB_FETCHMODE_ASSOC) { 348 $arr = @mssql_fetch_assoc($result); 349 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { 350 $arr = array_change_key_case($arr, CASE_LOWER); 351 } 352 } else { 353 $arr = @mssql_fetch_row($result); 354 } 355 if (!$arr) { 356 return null; 357 } 358 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { 359 $this->_rtrimArrayValues($arr); 360 } 361 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { 362 $this->_convertNullArrayValuesToEmpty($arr); 363 } 364 return DB_OK; 365 } 366 367 // }}} 368 // {{{ freeResult() 369 370 /** 371 * Deletes the result set and frees the memory occupied by the result set 372 * 373 * This method is not meant to be called directly. Use 374 * DB_result::free() instead. It can't be declared "protected" 375 * because DB_result is a separate object. 376 * 377 * @param resource $result PHP's query result resource 378 * 379 * @return bool TRUE on success, FALSE if $result is invalid 380 * 381 * @see DB_result::free() 382 */ 383 function freeResult($result) 384 { 385 return is_resource($result) ? mssql_free_result($result) : false; 386 } 387 388 // }}} 389 // {{{ numCols() 390 391 /** 392 * Gets the number of columns in a result set 393 * 394 * This method is not meant to be called directly. Use 395 * DB_result::numCols() instead. It can't be declared "protected" 396 * because DB_result is a separate object. 397 * 398 * @param resource $result PHP's query result resource 399 * 400 * @return int the number of columns. A DB_Error object on failure. 401 * 402 * @see DB_result::numCols() 403 */ 404 function numCols($result) 405 { 406 $cols = @mssql_num_fields($result); 407 if (!$cols) { 408 return $this->mssqlRaiseError(); 409 } 410 return $cols; 411 } 412 413 // }}} 414 // {{{ numRows() 415 416 /** 417 * Gets the number of rows in a result set 418 * 419 * This method is not meant to be called directly. Use 420 * DB_result::numRows() instead. It can't be declared "protected" 421 * because DB_result is a separate object. 422 * 423 * @param resource $result PHP's query result resource 424 * 425 * @return int the number of rows. A DB_Error object on failure. 426 * 427 * @see DB_result::numRows() 428 */ 429 function numRows($result) 430 { 431 $rows = @mssql_num_rows($result); 432 if ($rows === false) { 433 return $this->mssqlRaiseError(); 434 } 435 return $rows; 436 } 437 438 // }}} 439 // {{{ autoCommit() 440 441 /** 442 * Enables or disables automatic commits 443 * 444 * @param bool $onoff true turns it on, false turns it off 445 * 446 * @return int DB_OK on success. A DB_Error object if the driver 447 * doesn't support auto-committing transactions. 448 */ 449 function autoCommit($onoff = false) 450 { 451 // XXX if $this->transaction_opcount > 0, we should probably 452 // issue a warning here. 453 $this->autocommit = $onoff ? true : false; 454 return DB_OK; 455 } 456 457 // }}} 458 // {{{ commit() 459 460 /** 461 * Commits the current transaction 462 * 463 * @return int DB_OK on success. A DB_Error object on failure. 464 */ 465 function commit() 466 { 467 if ($this->transaction_opcount > 0) { 468 if (!@mssql_select_db($this->_db, $this->connection)) { 469 return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); 470 } 471 $result = @mssql_query('COMMIT TRAN', $this->connection); 472 $this->transaction_opcount = 0; 473 if (!$result) { 474 return $this->mssqlRaiseError(); 475 } 476 } 477 return DB_OK; 478 } 479 480 // }}} 481 // {{{ rollback() 482 483 /** 484 * Reverts the current transaction 485 * 486 * @return int DB_OK on success. A DB_Error object on failure. 487 */ 488 function rollback() 489 { 490 if ($this->transaction_opcount > 0) { 491 if (!@mssql_select_db($this->_db, $this->connection)) { 492 return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); 493 } 494 $result = @mssql_query('ROLLBACK TRAN', $this->connection); 495 $this->transaction_opcount = 0; 496 if (!$result) { 497 return $this->mssqlRaiseError(); 498 } 499 } 500 return DB_OK; 501 } 502 503 // }}} 504 // {{{ affectedRows() 505 506 /** 507 * Determines the number of rows affected by a data maniuplation query 508 * 509 * 0 is returned for queries that don't manipulate data. 510 * 511 * @return int the number of rows. A DB_Error object on failure. 512 */ 513 function affectedRows() 514 { 515 if ($this->_last_query_manip) { 516 $res = @mssql_query('select @@rowcount', $this->connection); 517 if (!$res) { 518 return $this->mssqlRaiseError(); 519 } 520 $ar = @mssql_fetch_row($res); 521 if (!$ar) { 522 $result = 0; 523 } else { 524 @mssql_free_result($res); 525 $result = $ar[0]; 526 } 527 } else { 528 $result = 0; 529 } 530 return $result; 531 } 532 533 // }}} 534 // {{{ nextId() 535 536 /** 537 * Returns the next free id in a sequence 538 * 539 * @param string $seq_name name of the sequence 540 * @param boolean $ondemand when true, the seqence is automatically 541 * created if it does not exist 542 * 543 * @return int the next id number in the sequence. 544 * A DB_Error object on failure. 545 * 546 * @see DB_common::nextID(), DB_common::getSequenceName(), 547 * DB_mssql::createSequence(), DB_mssql::dropSequence() 548 */ 549 function nextId($seq_name, $ondemand = true) 550 { 551 $seqname = $this->getSequenceName($seq_name); 552 if (!@mssql_select_db($this->_db, $this->connection)) { 553 return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); 554 } 555 $repeat = 0; 556 do { 557 $this->pushErrorHandling(PEAR_ERROR_RETURN); 558 $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); 559 $this->popErrorHandling(); 560 if ($ondemand && DB::isError($result) && 561 ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) 562 { 563 $repeat = 1; 564 $result = $this->createSequence($seq_name); 565 if (DB::isError($result)) { 566 return $this->raiseError($result); 567 } 568 } elseif (!DB::isError($result)) { 569 $result =& $this->query("SELECT IDENT_CURRENT('$seqname')"); 570 if (DB::isError($result)) { 571 /* Fallback code for MS SQL Server 7.0, which doesn't have 572 * IDENT_CURRENT. This is *not* safe for concurrent 573 * requests, and really, if you're using it, you're in a 574 * world of hurt. Nevertheless, it's here to ensure BC. See 575 * bug #181 for the gory details.*/ 576 $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); 577 } 578 $repeat = 0; 579 } else { 580 $repeat = false; 581 } 582 } while ($repeat); 583 if (DB::isError($result)) { 584 return $this->raiseError($result); 585 } 586 $result = $result->fetchRow(DB_FETCHMODE_ORDERED); 587 return $result[0]; 588 } 589 590 /** 591 * Creates a new sequence 592 * 593 * @param string $seq_name name of the new sequence 594 * 595 * @return int DB_OK on success. A DB_Error object on failure. 596 * 597 * @see DB_common::createSequence(), DB_common::getSequenceName(), 598 * DB_mssql::nextID(), DB_mssql::dropSequence() 599 */ 600 function createSequence($seq_name) 601 { 602 return $this->query('CREATE TABLE ' 603 . $this->getSequenceName($seq_name) 604 . ' ([id] [int] IDENTITY (1, 1) NOT NULL,' 605 . ' [vapor] [int] NULL)'); 606 } 607 608 // }}} 609 // {{{ dropSequence() 610 611 /** 612 * Deletes a sequence 613 * 614 * @param string $seq_name name of the sequence to be deleted 615 * 616 * @return int DB_OK on success. A DB_Error object on failure. 617 * 618 * @see DB_common::dropSequence(), DB_common::getSequenceName(), 619 * DB_mssql::nextID(), DB_mssql::createSequence() 620 */ 621 function dropSequence($seq_name) 622 { 623 return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); 624 } 625 626 // }}} 627 // {{{ quoteIdentifier() 628 629 /** 630 * Quotes a string so it can be safely used as a table or column name 631 * 632 * @param string $str identifier name to be quoted 633 * 634 * @return string quoted identifier string 635 * 636 * @see DB_common::quoteIdentifier() 637 * @since Method available since Release 1.6.0 638 */ 639 function quoteIdentifier($str) 640 { 641 return '[' . str_replace(']', ']]', $str) . ']'; 642 } 643 644 // }}} 645 // {{{ mssqlRaiseError() 646 647 /** 648 * Produces a DB_Error object regarding the current problem 649 * 650 * @param int $errno if the error is being manually raised pass a 651 * DB_ERROR* constant here. If this isn't passed 652 * the error information gathered from the DBMS. 653 * 654 * @return object the DB_Error object 655 * 656 * @see DB_common::raiseError(), 657 * DB_mssql::errorNative(), DB_mssql::errorCode() 658 */ 659 function mssqlRaiseError($code = null) 660 { 661 $message = @mssql_get_last_message(); 662 if (!$code) { 663 $code = $this->errorNative(); 664 } 665 return $this->raiseError($this->errorCode($code, $message), 666 null, null, null, "$code - $message"); 667 } 668 669 // }}} 670 // {{{ errorNative() 671 672 /** 673 * Gets the DBMS' native error code produced by the last query 674 * 675 * @return int the DBMS' error code 676 */ 677 function errorNative() 678 { 679 $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection); 680 if (!$res) { 681 return DB_ERROR; 682 } 683 $row = @mssql_fetch_row($res); 684 return $row[0]; 685 } 686 687 // }}} 688 // {{{ errorCode() 689 690 /** 691 * Determines PEAR::DB error code from mssql's native codes. 692 * 693 * If <var>$nativecode</var> isn't known yet, it will be looked up. 694 * 695 * @param mixed $nativecode mssql error code, if known 696 * @return integer an error number from a DB error constant 697 * @see errorNative() 698 */ 699 function errorCode($nativecode = null, $msg = '') 700 { 701 if (!$nativecode) { 702 $nativecode = $this->errorNative(); 703 } 704 if (isset($this->errorcode_map[$nativecode])) { 705 if ($nativecode == 3701 706 && preg_match('/Cannot drop the index/i', $msg)) 707 { 708 return DB_ERROR_NOT_FOUND; 709 } 710 return $this->errorcode_map[$nativecode]; 711 } else { 712 return DB_ERROR; 713 } 714 } 715 716 // }}} 717 // {{{ tableInfo() 718 719 /** 720 * Returns information about a table or a result set 721 * 722 * NOTE: only supports 'table' and 'flags' if <var>$result</var> 723 * is a table name. 724 * 725 * @param object|string $result DB_result object from a query or a 726 * string containing the name of a table. 727 * While this also accepts a query result 728 * resource identifier, this behavior is 729 * deprecated. 730 * @param int $mode a valid tableInfo mode 731 * 732 * @return array an associative array with the information requested. 733 * A DB_Error object on failure. 734 * 735 * @see DB_common::tableInfo() 736 */ 737 function tableInfo($result, $mode = null) 738 { 739 if (is_string($result)) { 740 /* 741 * Probably received a table name. 742 * Create a result resource identifier. 743 */ 744 if (!@mssql_select_db($this->_db, $this->connection)) { 745 return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); 746 } 747 $id = @mssql_query("SELECT * FROM $result WHERE 1=0", 748 $this->connection); 749 $got_string = true; 750 } elseif (isset($result->result)) { 751 /* 752 * Probably received a result object. 753 * Extract the result resource identifier. 754 */ 755 $id = $result->result; 756 $got_string = false; 757 } else { 758 /* 759 * Probably received a result resource identifier. 760 * Copy it. 761 * Deprecated. Here for compatibility only. 762 */ 763 $id = $result; 764 $got_string = false; 765 } 766 767 if (!is_resource($id)) { 768 return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA); 769 } 770 771 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { 772 $case_func = 'strtolower'; 773 } else { 774 $case_func = 'strval'; 775 } 776 777 $count = @mssql_num_fields($id); 778 $res = array(); 779 780 if ($mode) { 781 $res['num_fields'] = $count; 782 } 783 784 for ($i = 0; $i < $count; $i++) { 785 if ($got_string) { 786 $flags = $this->_mssql_field_flags($result, 787 @mssql_field_name($id, $i)); 788 if (DB::isError($flags)) { 789 return $flags; 790 } 791 } else { 792 $flags = ''; 793 } 794 795 $res[$i] = array( 796 'table' => $got_string ? $case_func($result) : '', 797 'name' => $case_func(@mssql_field_name($id, $i)), 798 'type' => @mssql_field_type($id, $i), 799 'len' => @mssql_field_length($id, $i), 800 'flags' => $flags, 801 ); 802 if ($mode & DB_TABLEINFO_ORDER) { 803 $res['order'][$res[$i]['name']] = $i; 804 } 805 if ($mode & DB_TABLEINFO_ORDERTABLE) { 806 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 807 } 808 } 809 810 // free the result only if we were called on a table 811 if ($got_string) { 812 @mssql_free_result($id); 813 } 814 return $res; 815 } 816 817 // }}} 818 // {{{ _mssql_field_flags() 819 820 /** 821 * Get a column's flags 822 * 823 * Supports "not_null", "primary_key", 824 * "auto_increment" (mssql identity), "timestamp" (mssql timestamp), 825 * "unique_key" (mssql unique index, unique check or primary_key) and 826 * "multiple_key" (multikey index) 827 * 828 * mssql timestamp is NOT similar to the mysql timestamp so this is maybe 829 * not useful at all - is the behaviour of mysql_field_flags that primary 830 * keys are alway unique? is the interpretation of multiple_key correct? 831 * 832 * @param string $table the table name 833 * @param string $column the field name 834 * 835 * @return string the flags 836 * 837 * @access private 838 * @author Joern Barthel <j_barthel@web.de> 839 */ 840 function _mssql_field_flags($table, $column) 841 { 842 static $tableName = null; 843 static $flags = array(); 844 845 if ($table != $tableName) { 846 847 $flags = array(); 848 $tableName = $table; 849 850 // get unique and primary keys 851 $res = $this->getAll("EXEC SP_HELPINDEX $table", DB_FETCHMODE_ASSOC); 852 if (DB::isError($res)) { 853 return $res; 854 } 855 856 foreach ($res as $val) { 857 $keys = explode(', ', $val['index_keys']); 858 859 if (sizeof($keys) > 1) { 860 foreach ($keys as $key) { 861 $this->_add_flag($flags[$key], 'multiple_key'); 862 } 863 } 864 865 if (strpos($val['index_description'], 'primary key')) { 866 foreach ($keys as $key) { 867 $this->_add_flag($flags[$key], 'primary_key'); 868 } 869 } elseif (strpos($val['index_description'], 'unique')) { 870 foreach ($keys as $key) { 871 $this->_add_flag($flags[$key], 'unique_key'); 872 } 873 } 874 } 875 876 // get auto_increment, not_null and timestamp 877 $res = $this->getAll("EXEC SP_COLUMNS $table", DB_FETCHMODE_ASSOC); 878 if (DB::isError($res)) { 879 return $res; 880 } 881 882 foreach ($res as $val) { 883 $val = array_change_key_case($val, CASE_LOWER); 884 if ($val['nullable'] == '0') { 885 $this->_add_flag($flags[$val['column_name']], 'not_null'); 886 } 887 if (strpos($val['type_name'], 'identity')) { 888 $this->_add_flag($flags[$val['column_name']], 'auto_increment'); 889 } 890 if (strpos($val['type_name'], 'timestamp')) { 891 $this->_add_flag($flags[$val['column_name']], 'timestamp'); 892 } 893 } 894 } 895 896 if (array_key_exists($column, $flags)) { 897 return(implode(' ', $flags[$column])); 898 } 899 return ''; 900 } 901 902 // }}} 903 // {{{ _add_flag() 904 905 /** 906 * Adds a string to the flags array if the flag is not yet in there 907 * - if there is no flag present the array is created 908 * 909 * @param array &$array the reference to the flag-array 910 * @param string $value the flag value 911 * 912 * @return void 913 * 914 * @access private 915 * @author Joern Barthel <j_barthel@web.de> 916 */ 917 function _add_flag(&$array, $value) 918 { 919 if (!is_array($array)) { 920 $array = array($value); 921 } elseif (!in_array($value, $array)) { 922 array_push($array, $value); 923 } 924 } 925 926 // }}} 927 // {{{ getSpecialQuery() 928 929 /** 930 * Obtains the query string needed for listing a given type of objects 931 * 932 * @param string $type the kind of objects you want to retrieve 933 * 934 * @return string the SQL query string or null if the driver doesn't 935 * support the object type requested 936 * 937 * @access protected 938 * @see DB_common::getListOf() 939 */ 940 function getSpecialQuery($type) 941 { 942 switch ($type) { 943 case 'tables': 944 return "SELECT name FROM sysobjects WHERE type = 'U'" 945 . ' ORDER BY name'; 946 case 'views': 947 return "SELECT name FROM sysobjects WHERE type = 'V'"; 948 default: 949 return null; 950 } 951 } 952 953 // }}} 954 } 955 956 /* 957 * Local variables: 958 * tab-width: 4 959 * c-basic-offset: 4 960 * End: 961 */ 962 963 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |