[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 // vim: set et ts=4 sw=4 fdm=marker: 3 // +----------------------------------------------------------------------+ 4 // | PHP Version 4 | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | 7 // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | 8 // | All rights reserved. | 9 // +----------------------------------------------------------------------+ 10 // | MDB is a merge of PEAR DB and Metabases that provides a unified DB | 11 // | API as well as database abstraction for PHP applications. | 12 // | This LICENSE is in the BSD license style. | 13 // | | 14 // | Redistribution and use in source and binary forms, with or without | 15 // | modification, are permitted provided that the following conditions | 16 // | are met: | 17 // | | 18 // | Redistributions of source code must retain the above copyright | 19 // | notice, this list of conditions and the following disclaimer. | 20 // | | 21 // | Redistributions in binary form must reproduce the above copyright | 22 // | notice, this list of conditions and the following disclaimer in the | 23 // | documentation and/or other materials provided with the distribution. | 24 // | | 25 // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | 26 // | Lukas Smith nor the names of his contributors may be used to endorse | 27 // | or promote products derived from this software without specific prior| 28 // | written permission. | 29 // | | 30 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 31 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 32 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 33 // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 34 // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 35 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 36 // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| 37 // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 38 // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 39 // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| 40 // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 41 // | POSSIBILITY OF SUCH DAMAGE. | 42 // +----------------------------------------------------------------------+ 43 // | Author: Frank M. Kromann <frank@kromann.info> | 44 // +----------------------------------------------------------------------+ 45 // 46 // $Id: mssql.php,v 1.6.4.30 2004/04/10 07:57:16 lsmith Exp $ 47 // 48 49 require_once ('MDB/Common.php'); 50 51 /** 52 * MDB MSSQL Server driver 53 * 54 * Notes: 55 * - Until at least version 6.5, the only kind of table changes that the 56 * ALTER TABLE SQL statement of Microsoft SQL server supports is new field 57 and constraint additions. 58 * 59 * - The driver alterTable method does not implement table or column renaming, 60 * column definitions changes or column dropping. In the future versions of 61 * this driver those capabilities may be emulated using other SQL statements 62 * to recreate the tables with a new definition. 63 * 64 * MDB_Manager_mssql::getTableFieldDefinition() is still alpha quality 65 * 66 * @package MDB 67 * @category Database 68 * @author Frank M. Kromann <frank@kromann.info> 69 */ 70 class MDB_mssql extends MDB_Common 71 { 72 // {{{ properties 73 74 var $connection = 0; 75 var $connected_host; 76 var $connected_user; 77 var $connected_password; 78 var $connected_port; 79 var $opened_persistent = ''; 80 81 var $escape_quotes = "'"; 82 83 var $highest_fetched_row = array(); 84 var $columns = array(); 85 86 // }}} 87 // {{{ constructor 88 89 /** 90 * Constructor 91 */ 92 function MDB_mssql() 93 { 94 $this->MDB_Common(); 95 $this->phptype = 'mssql'; 96 $this->dbsyntax = 'mssql'; 97 98 $this->supported['Sequences'] = 1; 99 $this->supported['Indexes'] = 1; 100 $this->supported['AffectedRows'] = 1; 101 $this->supported['Transactions'] = 1; 102 $this->supported['Summaryfunctions'] = 1; 103 $this->supported['OrderByText'] = 0; 104 $this->supported['CurrId'] = 0; 105 $this->supported['SelectRowRanges'] = 1; 106 $this->supported['LOBs'] = 1; 107 $this->supported['Replace'] = 1; 108 $this->supported['SubSelects'] = 1; 109 110 $this->errorcode_map = array( 111 207 => MDB_ERROR_NOSUCHFIELD, 112 208 => MDB_ERROR_NOSUCHTABLE, 113 245 => MDB_ERROR_INVALID_NUMBER, 114 515 => MDB_ERROR_CONSTRAINT_NOT_NULL, 115 547 => MDB_ERROR_CONSTRAINT, 116 1205 => MDB_ERROR_DEADLOCK, 117 2627 => MDB_ERROR_CONSTRAINT, 118 2714 => MDB_ERROR_ALREADY_EXISTS, 119 3701 => MDB_ERROR_NOSUCHTABLE, 120 8134 => MDB_ERROR_DIVZERO, 121 ); 122 } 123 124 // }}} 125 // {{{ errorNative() 126 127 /** 128 * Get the native error code of the last error (if any) that 129 * occured on the current connection. 130 * 131 * @access public 132 * 133 * @return int native FrontBase error code 134 */ 135 function errorNative() 136 { 137 $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection); 138 if ($res) { 139 $row = @mssql_fetch_row($res); 140 if (is_array($row) && $row[0] > 0) { 141 return $row[0]; 142 } 143 } 144 return NULL; 145 } 146 147 // }}} 148 // {{{ mssqlRaiseError() 149 150 /** 151 * This method is used to communicate an error and invoke error 152 * callbacks etc. Basically a wrapper for MDB::raiseError 153 * that checks for native error msgs. 154 * 155 * @param string $message userinfo message 156 * @param integer $errno error code 157 * @return object a PEAR error object 158 * @access public 159 * @see PEAR_Error 160 */ 161 function mssqlRaiseError($errno = NULL, $message = NULL) 162 { 163 if ($errno == NULL) { 164 $errno = $this->errorNative(); 165 } 166 $error = @mssql_get_last_message(); 167 return $this->raiseError($this->errorCode(), NULL, NULL, 168 $message, $error); 169 } 170 171 // }}} 172 // {{{ quoteIdentifier() 173 174 /** 175 * Quote a string so it can be safely used as a table / column name 176 * 177 * Quoting style depends on which database driver is being used. 178 * 179 * @param string $str identifier name to be quoted 180 * 181 * @return string quoted identifier string 182 * 183 * @since 1.6.0 184 * @access public 185 */ 186 function quoteIdentifier($str) 187 { 188 return '[' . str_replace(']', ']]', $str) . ']'; 189 } 190 191 // }}} 192 // {{{ autoCommit() 193 194 /** 195 * Define whether database changes done on the database be automatically 196 * committed. This function may also implicitly start or end a transaction. 197 * 198 * @param boolean $auto_commit flag that indicates whether the database 199 * changes should be committed right after 200 * executing every query statement. If this 201 * argument is 0 a transaction implicitly 202 * started. Otherwise, if a transaction is 203 * in progress it is ended by committing any 204 * database changes that were pending. 205 * 206 * @access public 207 * 208 * @return mixed MDB_OK on success, a MDB error on failure 209 */ 210 function autoCommit($auto_commit) 211 { 212 $this->debug("AutoCommit: ".($auto_commit ? "On" : "Off")); 213 if (!isset($this->supported['Transactions'])) { 214 return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 215 'Auto-commit transactions: transactions are not in use')); 216 } 217 if ($this->auto_commit == $auto_commit) { 218 return(MDB_OK); 219 } 220 if ($this->connection) { 221 if ($auto_commit) { 222 $result = $this->query('COMMIT TRANSACTION'); 223 } else { 224 $result = $this->query('BEGIN TRANSACTION'); 225 } 226 if (MDB::isError($result)) { 227 return($result); 228 } 229 } 230 $this->auto_commit = $auto_commit; 231 $this->in_transaction = !$auto_commit; 232 return(MDB_OK); 233 } 234 235 // }}} 236 // {{{ commit() 237 238 /** 239 * Commit the database changes done during a transaction that is in 240 * progress. This function may only be called when auto-committing is 241 * disabled, otherwise it will fail. Therefore, a new transaction is 242 * implicitly started after committing the pending changes. 243 * 244 * @access public 245 * 246 * @return mixed MDB_OK on success, a MDB error on failure 247 */ 248 function commit() 249 { 250 $this->debug("Commit Transaction"); 251 if (!isset($this->supported['Transactions'])) { 252 return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 253 'Commit transactions: transactions are not in use')); 254 } 255 if ($this->auto_commit) { 256 return($this->raiseError(MDB_ERROR, NULL, NULL, 257 'Commit transactions: transaction changes are being auto commited')); 258 } 259 $result = $this->query('COMMIT TRANSACTION'); 260 if (MDB::isError($result)) { 261 return($result); 262 } 263 return($this->query('BEGIN TRANSACTION')); 264 } 265 266 // }}} 267 // {{{ rollback() 268 269 /** 270 * Cancel any database changes done during a transaction that is in 271 * progress. This function may only be called when auto-committing is 272 * disabled, otherwise it will fail. Therefore, a new transaction is 273 * implicitly started after canceling the pending changes. 274 * 275 * @access public 276 * 277 * @return mixed MDB_OK on success, a MDB error on failure 278 */ 279 function rollback() 280 { 281 $this->debug("Rollback Transaction"); 282 if (!isset($this->supported['Transactions'])) { 283 return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 284 'Rollback transactions: transactions are not in use')); 285 } 286 if ($this->auto_commit) { 287 return($this->raiseError(MDB_ERROR, NULL, NULL, 288 'Rollback transactions: transactions can not be rolled back when changes are auto commited')); 289 } 290 $result = $this->query('ROLLBACK TRANSACTION'); 291 if (MDB::isError($result)) { 292 return($result); 293 } 294 return($this->query('BEGIN TRANSACTION')); 295 } 296 297 function _doQuery($query) 298 { 299 $this->current_row = $this->affected_rows = -1; 300 return(@mssql_query($query, $this->connection)); 301 } 302 303 // }}} 304 // {{{ connect() 305 306 /** 307 * Connect to the database 308 * 309 * @return TRUE on success, MDB_Error on failure 310 **/ 311 function connect() 312 { 313 $port = (isset($this->port) ? $this->port : ''); 314 if($this->connection != 0) { 315 if (!strcmp($this->connected_host, $this->host) 316 && !strcmp($this->connected_user, $this->user) 317 && !strcmp($this->connected_password, $this->password) 318 && !strcmp($this->connected_port, $port) 319 && $this->opened_persistent == $this->options['persistent']) 320 { 321 return(MDB_OK); 322 } 323 @mssql_close($this->connection); 324 $this->connection = 0; 325 $this->affected_rows = -1; 326 } 327 328 if(!PEAR::loadExtension($this->phptype)) { 329 return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND, 330 NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP', 331 'MDB_Error', TRUE)); 332 } 333 334 $function = ($this->options['persistent'] ? 'mssql_pconnect' : 'mssql_connect'); 335 if (!function_exists($function)) { 336 return($this->raiseError(MDB_ERROR_UNSUPPORTED)); 337 } 338 339 @ini_set('track_errors', TRUE); 340 $this->connection = @$function( 341 $this->host.(!strcmp($port,'') ? '' : ':'.$port), 342 $this->user, $this->password); 343 @ini_restore('track_errors'); 344 if ($this->connection <= 0) { 345 return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL, 346 $php_errormsg)); 347 } 348 349 if(isset($this->supported['Transactions']) && !$this->auto_commit 350 && !$this->_doQuery("BEGIN TRANSACTION")) 351 { 352 @mssql_close($this->connection); 353 $this->connection = 0; 354 $this->affected_rows = -1; 355 return($this->raiseError("Connect: Could not begin the initial transaction")); 356 } 357 $this->connected_host = $this->host; 358 $this->connected_user = $this->user; 359 $this->connected_password = $this->password; 360 $this->connected_port = $port; 361 $this->selected_database = $this->database_name; 362 $this->opened_persistent = $this->getoption('persistent'); 363 return(MDB_OK); 364 } 365 366 // }}} 367 // {{{ _close() 368 /** 369 * all the RDBMS specific things needed close a DB connection 370 * 371 * @return boolean 372 * @access private 373 **/ 374 function _close() 375 { 376 if ($this->connection != 0) { 377 if (isset($this->supported['Transactions']) && !$this->auto_commit) { 378 $result = $this->_doQuery("ROLLBACK TRANSACTION"); 379 } 380 @mssql_close($this->connection); 381 $this->connection = 0; 382 $this->affected_rows = $this->current_row = -1; 383 384 if (isset($result) && MDB::isError($result)) { 385 return($result); 386 } 387 unset($GLOBALS['_MDB_databases'][$this->database]); 388 return(TRUE); 389 } 390 return(FALSE); 391 } 392 393 function standaloneQuery($query) 394 { 395 if(!PEAR::loadExtension($this->phptype)) { 396 return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND, 397 NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP', 398 'MDB_Error', TRUE)); 399 } 400 $connection = @mssql_connect($this->host,$this->user,$this->password); 401 if($connection == 0) { 402 return($this->mssqlRaiseError(NULL, "Query: Could not connect to the Microsoft SQL server")); 403 } 404 $result = @mssql_query($query, $connection); 405 if(!$result) { 406 return($this->mssqlRaiseError(NULL, "Query: Could not query a Microsoft SQL server")); 407 } 408 @mssql_close($connection); 409 return(MDB_OK); 410 } 411 412 // }}} 413 // {{{ query() 414 415 /** 416 * Send a query to the database and return any results 417 * 418 * @access public 419 * 420 * @param string $query the SQL query 421 * @param mixed $types array that contains the types of the columns in 422 * the result set 423 * 424 * @return mixed a result handle or MDB_OK on success, a MDB error on failure 425 */ 426 function query($query, $types = NULL) 427 { 428 $this->debug("Query: $query"); 429 if ($this->database_name) { 430 $ismanip = MDB::isManip($query); 431 $this->last_query = $query; 432 $first = $this->first_selected_row; 433 $limit = $this->selected_row_limit; 434 $this->first_selected_row = $this->selected_row_limit = 0; 435 436 $last_connection = $this->connection; 437 $result = $this->connect(); 438 if (MDB::isError($result)) { 439 return($result); 440 } 441 if($limit > 0) { 442 $fetch = $first + $limit; 443 if (!$ismanip) { 444 $query = str_replace('SELECT', "SELECT TOP $fetch", $query); 445 } 446 } 447 if( $last_connection != $this->connection 448 || !strcmp($this->selected_database, '') 449 || strcmp($this->selected_database, $this->database_name)) 450 { 451 if(!@mssql_select_db($this->database_name, $this->connection)) { 452 return($this->mssqlRaiseError()); 453 } 454 } 455 if ($result = $this->_doQuery($query)) { 456 if ($ismanip) { 457 $this->affected_rows = @mssql_rows_affected($this->connection); 458 return(MDB_OK); 459 } else { 460 $result_value = intval($result); 461 if($first > 0 || $limit > 0) { 462 $this->limits[$result_value] = array($first, $limit); 463 } 464 $this->highest_fetched_row[$result_value] = -1; 465 if ($types != NULL) { 466 if (!is_array($types)) { 467 $types = array($types); 468 } 469 $err = $this->setResultTypes($result, $types); 470 if (MDB::isError($err)) { 471 $this->freeResult($result); 472 return($err); 473 } 474 } 475 return($result); 476 } 477 } 478 } 479 480 return($this->mssqlRaiseError()); 481 } 482 483 // }}} 484 // {{{ getColumnNames() 485 486 /** 487 * Retrieve the names of columns returned by the DBMS in a query result. 488 * 489 * @param resource $result result identifier 490 * @return mixed an associative array variable 491 * that will hold the names of columns. The 492 * indexes of the array are the column names 493 * mapped to lower case and the values are the 494 * respective numbers of the columns starting 495 * from 0. Some DBMS may not return any 496 * columns when the result set does not 497 * contain any rows. 498 * 499 * a MDB error on failure 500 * @access public 501 */ 502 function getColumnNames($result) 503 { 504 $result_value = intval($result); 505 if (!isset($this->highest_fetched_row[$result_value])) { 506 return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL, 507 'Get column names: it was specified an inexisting result set')); 508 } 509 if (!isset($this->columns[$result_value])) { 510 $this->columns[$result_value] = array(); 511 $columns = @mssql_num_fields($result); 512 for($column = 0; $column < $columns; $column++) { 513 $field_name = @mssql_field_name($result, $column); 514 if ($this->options['optimize'] == 'portability') { 515 $field_name = strtolower($field_name); 516 } 517 $this->columns[$result_value][$field_name] = $column; 518 } 519 } 520 return($this->columns[$result_value]); 521 } 522 523 // }}} 524 // {{{ numCols() 525 526 /** 527 * Count the number of columns returned by the DBMS in a query result. 528 * 529 * @param resource $result result identifier 530 * @access public 531 * @return mixed integer value with the number of columns, a MDB error 532 * on failure 533 */ 534 function numCols($result) 535 { 536 if (!isset($this->highest_fetched_row[intval($result)])) { 537 return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL, 538 'numCols: it was specified an inexisting result set')); 539 } 540 return(@mssql_num_fields($result)); 541 } 542 543 // }}} 544 // {{{ endOfResult() 545 546 /** 547 * check if the end of the result set has been reached 548 * 549 * @param resource $result result identifier 550 * @return mixed TRUE or FALSE on sucess, a MDB error on failure 551 * @access public 552 */ 553 function endOfResult($result) 554 { 555 $result_value = intval($result); 556 if (!isset($this->highest_fetched_row[$result_value])) { 557 return($this->raiseError(MDB_ERROR, NULL, NULL, 558 'End of result: attempted to check the end of an unknown result')); 559 } 560 return($this->highest_fetched_row[$result_value] >= $this->numRows($result)-1); 561 } 562 563 // }}} 564 // {{{ fetch() 565 566 /** 567 * fetch value from a result set 568 * 569 * @param resource $result result identifier 570 * @param int $row number of the row where the data can be found 571 * @param int $field field number where the data can be found 572 * @return mixed string on success, a MDB error on failure 573 * @access public 574 */ 575 function fetch($result, $row, $field) 576 { 577 $result_value = intval($result); 578 $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row); 579 if (isset($this->limits[$result_value])) { 580 $row += $this->limits[$result_value][0]; 581 } 582 $res = @mssql_result($result, $row, $field); 583 if ($res === FALSE && $res != NULL) { 584 return($this->mssqlRaiseError()); 585 } 586 return($res); 587 } 588 589 // }}} 590 // {{{ fetchClob() 591 592 /** 593 * fetch a clob value from a result set 594 * 595 * @param resource $result result identifier 596 * @param int $row number of the row where the data can be found 597 * @param int $field field number where the data can be found 598 * @return mixed content of the specified data cell, a MDB error on failure, 599 * a MDB error on failure 600 * @access public 601 */ 602 function fetchClob($result, $row, $field) 603 { 604 return($this->fetchLob($result, $row, $field)); 605 } 606 607 // }}} 608 // {{{ fetchBlob() 609 610 /** 611 * fetch a blob value from a result set 612 * 613 * @param resource $result result identifier 614 * @param int $row number of the row where the data can be found 615 * @param int $field field number where the data can be found 616 * @return mixed content of the specified data cell, a MDB error on failure 617 * @access public 618 */ 619 function fetchBlob($result, $row, $field) 620 { 621 return($this->fetchLob($result, $row, $field)); 622 } 623 624 // }}} 625 // {{{ convertResult() 626 627 /** 628 * convert a value to a RDBMS indepdenant MDB type 629 * 630 * @param mixed $value value to be converted 631 * @param int $type constant that specifies which type to convert to 632 * @return mixed converted value 633 * @access public 634 */ 635 function convertResult($value, $type) 636 { 637 switch($type) { 638 case MDB_TYPE_BOOLEAN: 639 return ($value == '1') ? TRUE : FALSE; 640 case MDB_TYPE_DATE: 641 if(strlen($value) > 10) { 642 $value=substr($value,0,10); 643 } 644 return($value); 645 case MDB_TYPE_TIME: 646 if(strlen($value) > 8) { 647 $value=substr($value,11,8); 648 } 649 return($value); 650 case MDB_TYPE_TIMESTAMP: 651 return($value); 652 default: 653 return($this->_baseConvertResult($value,$type)); 654 } 655 } 656 657 // }}} 658 // {{{ numRows() 659 660 /** 661 * returns the number of rows in a result object 662 * 663 * @param ressource $result a valid result ressouce pointer 664 * @return mixed MDB_Error or the number of rows 665 * @access public 666 */ 667 function numRows($result) 668 { 669 $result_value = intval($result); 670 $rows = @mssql_num_rows($result); 671 if (isset($this->limits[$result_value])) { 672 $rows -= $this->limits[$result_value][0]; 673 if ($rows < 0) $rows = 0; 674 } 675 return($rows); 676 } 677 678 // }}} 679 // {{{ freeResult() 680 681 /** 682 * Free the internal resources associated with $result. 683 * 684 * @param $result result identifier 685 * @return boolean TRUE on success, FALSE if $result is invalid 686 * @access public 687 */ 688 function freeResult($result) 689 { 690 $result_value = intval($result); 691 if(isset($this->fetched_row[$result_value])) { 692 unset($this->fetched_row[$result_value]); 693 } 694 if(isset($this->highest_fetched_row[$result_value])) { 695 unset($this->highest_fetched_row[$result_value]); 696 } 697 if(isset($this->columns[$result_value])) { 698 unset($this->columns[$result_value]); 699 } 700 if(isset($this->result_types[$result_value])) { 701 unset($this->result_types[$result_value]); 702 } 703 return(@mssql_free_result($result)); 704 } 705 706 // }}} 707 // {{{ getIntegerDeclaration() 708 709 /** 710 * Obtain DBMS specific SQL code portion needed to declare an integer type 711 * field to be used in statements like CREATE TABLE. 712 * 713 * @param string $name name the field to be declared. 714 * @param string $field associative array with the name of the properties 715 * of the field being declared as array indexes. 716 * Currently, the types of supported field 717 * properties are as follows: 718 * 719 * unsigned 720 * Boolean flag that indicates whether the field 721 * should be declared as unsigned integer if 722 * possible. 723 * 724 * default 725 * Integer value to be used as default for this 726 * field. 727 * 728 * notnull 729 * Boolean flag that indicates whether this field is 730 * constrained to not be set to NULL. 731 * @return string DBMS specific SQL code portion that should be used to 732 * declare the specified field. 733 * @access public 734 */ 735 function getIntegerDeclaration($name, $field) 736 { 737 if (isset($field['unsigned'])) { 738 $this->warnings[] = "unsigned integer field \"$name\" is being 739 declared as signed integer"; 740 } 741 return("$name INT".(isset($field["default"]) ? " DEFAULT ".$field["default"] : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 742 } 743 744 // }}} 745 // {{{ getTextDeclaration() 746 747 /** 748 * Obtain DBMS specific SQL code portion needed to declare an text type 749 * field to be used in statements like CREATE TABLE. 750 * 751 * @param string $name name the field to be declared. 752 * @param string $field associative array with the name of the properties 753 * of the field being declared as array indexes. Currently, the types 754 * of supported field properties are as follows: 755 * 756 * length 757 * Integer value that determines the maximum length of the text 758 * field. If this argument is missing the field should be 759 * declared to have the longest length allowed by the DBMS. 760 * 761 * default 762 * Text value to be used as default for this field. 763 * 764 * notnull 765 * Boolean flag that indicates whether this field is constrained 766 * to not be set to NULL. 767 * @return string DBMS specific SQL code portion that should be used to 768 * declare the specified field. 769 * @access public 770 */ 771 function getTextDeclaration($name, $field) 772 { 773 return((isset($field["length"]) ? "$name VARCHAR (".$field["length"].")" : "$name TEXT").(isset($field["default"]) ? " DEFAULT ".$this->GetTextValue($field["default"]) : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 774 } 775 776 // }}} 777 // {{{ getClobDeclaration() 778 779 /** 780 * Obtain DBMS specific SQL code portion needed to declare an character 781 * large object type field to be used in statements like CREATE TABLE. 782 * 783 * @param string $name name the field to be declared. 784 * @param string $field associative array with the name of the 785 * properties of the field being declared as array 786 * indexes. Currently, the types of supported field 787 * properties are as follows: 788 * 789 * length 790 * Integer value that determines the maximum length 791 * of the large object field. If this argument is 792 * missing the field should be declared to have the 793 * longest length allowed by the DBMS. 794 * 795 * notnull 796 * Boolean flag that indicates whether this field 797 * is constrained to not be set to NULL. 798 * @return string DBMS specific SQL code portion that should be used to 799 * declare the specified field. 800 * @access public 801 */ 802 function getClobDeclaration($name, $field) 803 { 804 if (isset($field["length"])) { 805 $length = $field["length"]; 806 if ($length <= 8000) { 807 $type = "VARCHAR($length)"; 808 } else { 809 $type = "TEXT"; 810 } 811 } else { 812 $type = "TEXT"; 813 } 814 return("$name $type".(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 815 } 816 817 // }}} 818 // {{{ getBlobDeclaration() 819 820 /** 821 * Obtain DBMS specific SQL code portion needed to declare an binary large 822 * object type field to be used in statements like CREATE TABLE. 823 * 824 * @param string $name name the field to be declared. 825 * @param string $field associative array with the name of the properties 826 * of the field being declared as array indexes. 827 * Currently, the types of supported field 828 * properties are as follows: 829 * 830 * length 831 * Integer value that determines the maximum length 832 * of the large object field. If this argument is 833 * missing the field should be declared to have the 834 * longest length allowed by the DBMS. 835 * 836 * notnull 837 * Boolean flag that indicates whether this field is 838 * constrained to not be set to NULL. 839 * @return string DBMS specific SQL code portion that should be used to 840 * declare the specified field. 841 * @access public 842 */ 843 function getBlobDeclaration($name, $field) 844 { 845 if(isset($field["length"])) { 846 $length = $field["length"]; 847 if($length <= 8000) { 848 $type = "VARBINARY($length)"; 849 } else { 850 $type = "IMAGE"; 851 } 852 } else { 853 $type = "IMAGE"; 854 } 855 return("$name $type".(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 856 } 857 858 // }}} 859 // {{{ getBooleanDeclaration() 860 861 /** 862 * Obtain DBMS specific SQL code portion needed to declare a boolean type 863 * field to be used in statements like CREATE TABLE. 864 * 865 * @param string $name name the field to be declared. 866 * @param string $field associative array with the name of the properties 867 * of the field being declared as array indexes. Currently, the types 868 * of supported field properties are as follows: 869 * 870 * default 871 * Boolean value to be used as default for this field. 872 * 873 * notnullL 874 * Boolean flag that indicates whether this field is constrained 875 * to not be set to NULL. 876 * @return string DBMS specific SQL code portion that should be used to 877 * declare the specified field. 878 * @access public 879 */ 880 function getBooleanDeclaration($name, $field) 881 { 882 return("$name BIT".(isset($field["default"]) ? " DEFAULT ".$field["default"] : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 883 } 884 885 // }}} 886 // {{{ getDateDeclaration() 887 888 /** 889 * Obtain DBMS specific SQL code portion needed to declare an date type 890 * field to be used in statements like CREATE TABLE. 891 * 892 * @param string $name name the field to be declared. 893 * @param string $field associative array with the name of the properties 894 * of the field being declared as array indexes. 895 * Currently, the types of supported field properties 896 * are as follows: 897 * 898 * default 899 * Date value to be used as default for this field. 900 * 901 * notnull 902 * Boolean flag that indicates whether this field is 903 * constrained to not be set to NULL. 904 * @return string DBMS specific SQL code portion that should be used to 905 * declare the specified field. 906 * @access public 907 */ 908 function getDateDeclaration($name, $field) 909 { 910 return("$name CHAR (".strlen("YYYY-MM-DD").")".(isset($field["default"]) ? " DEFAULT ".$this->getDateValue($field["default"]) : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 911 } 912 913 // }}} 914 // {{{ getTimestampDeclaration() 915 916 /** 917 * Obtain DBMS specific SQL code portion needed to declare an timestamp 918 * type field to be used in statements like CREATE TABLE. 919 * 920 * @param string $name name the field to be declared. 921 * @param string $field associative array with the name of the properties 922 * of the field being declared as array indexes. 923 * Currently, the types of supported field 924 * properties are as follows: 925 * 926 * default 927 * Time stamp value to be used as default for this 928 * field. 929 * 930 * notnull 931 * Boolean flag that indicates whether this field is 932 * constrained to not be set to NULL. 933 * @return string DBMS specific SQL code portion that should be used to 934 * declare the specified field. 935 * @access public 936 */ 937 function getTimestampDeclaration($name, $field) 938 { 939 return("$name CHAR (".strlen("YYYY-MM-DD HH:MM:SS").")".(isset($field["default"]) ? " DEFAULT ".$this->getTimestampValue($field["default"]) : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 940 } 941 942 // }}} 943 // {{{ getTimeDeclaration() 944 945 /** 946 * Obtain DBMS specific SQL code portion needed to declare an time type 947 * field to be used in statements like CREATE TABLE. 948 * 949 * @param string $name name the field to be declared. 950 * @param string $field associative array with the name of the properties 951 * of the field being declared as array indexes. 952 * Currently, the types of supported field 953 * properties are as follows: 954 * 955 * default 956 * Time value to be used as default for this field. 957 * 958 * notnull 959 * Boolean flag that indicates whether this field is 960 * constrained to not be set to NULL. 961 * @return string DBMS specific SQL code portion that should be used to 962 * declare the specified field. 963 * @access public 964 */ 965 function getTimeDeclaration($name, $field) 966 { 967 return("$name CHAR (".strlen("HH:MM:SS").")".(isset($field["default"]) ? " DEFAULT ".$this->getTimeValue($field["default"]) : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 968 } 969 970 // }}} 971 // {{{ getFloatDeclaration() 972 973 /** 974 * Obtain DBMS specific SQL code portion needed to declare an float type 975 * field to be used in statements like CREATE TABLE. 976 * 977 * @param string $name name the field to be declared. 978 * @param string $field associative array with the name of the properties 979 * of the field being declared as array indexes. 980 * Currently, the types of supported field 981 * properties are as follows: 982 * 983 * default 984 * Integer value to be used as default for this 985 * field. 986 * 987 * notnull 988 * Boolean flag that indicates whether this field is 989 * constrained to not be set to NULL. 990 * @return string DBMS specific SQL code portion that should be used to 991 * declare the specified field. 992 * @access public 993 */ 994 function getFloatDeclaration($name, $field) 995 { 996 return("$name FLOAT".(isset($field["default"]) ? " DEFAULT ".$field["default"] : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 997 } 998 999 // }}} 1000 // {{{ getDecimalDeclaration() 1001 1002 /** 1003 * Obtain DBMS specific SQL code portion needed to declare an decimal type 1004 * field to be used in statements like CREATE TABLE. 1005 * 1006 * @param string $name name the field to be declared. 1007 * @param string $field associative array with the name of the properties 1008 * of the field being declared as array indexes. 1009 * Currently, the types of supported field 1010 * properties are as follows: 1011 * 1012 * default 1013 * Integer value to be used as default for this 1014 * field. 1015 * 1016 * notnull 1017 * Boolean flag that indicates whether this field is 1018 * constrained to not be set to NULL. 1019 * @return string DBMS specific SQL code portion that should be used to 1020 * declare the specified field. 1021 * @access public 1022 */ 1023 function getDecimalDeclaration($name, $field) 1024 { 1025 return("$name DECIMAL(18,".$this->decimal_places.")".(isset($field["default"]) ? " DEFAULT ".$this->getDecimalValue($field["default"]) : "").(isset($field["notnull"]) ? " NOT NULL" : " NULL")); 1026 } 1027 1028 // }}} 1029 // {{{ getClobValue() 1030 1031 /** 1032 * Convert a text value into a DBMS specific format that is suitable to 1033 * compose query statements. 1034 * 1035 * @param resource $prepared_query query handle from prepare() 1036 * @param $parameter 1037 * @param $clob 1038 * @return string text string that represents the given argument value in 1039 * a DBMS specific format. 1040 * @access public 1041 */ 1042 function getClobValue($prepared_query, $parameter, $clob) 1043 { 1044 $value="'"; 1045 while(!$this->endOfLob($clob)) { 1046 if (MDB::isError($result = $this->readLob($clob, $data, $this->options['lob_buffer_length']))) { 1047 return($result); 1048 } 1049 $value .= $this->_quote($data); 1050 } 1051 $value .= "'"; 1052 return($value); 1053 } 1054 1055 // }}} 1056 // {{{ freeClobValue() 1057 1058 /** 1059 * free a character large object 1060 * 1061 * @param resource $prepared_query query handle from prepare() 1062 * @param string $clob 1063 * @return MDB_OK 1064 * @access public 1065 */ 1066 function freeClobValue($prepared_query, $clob) 1067 { 1068 unset($this->lobs[$clob]); 1069 return(MDB_OK); 1070 } 1071 1072 // }}} 1073 // {{{ getBlobValue() 1074 1075 /** 1076 * Convert a text value into a DBMS specific format that is suitable to 1077 * compose query statements. 1078 * 1079 * @param resource $prepared_query query handle from prepare() 1080 * @param $parameter 1081 * @param $blob 1082 * @return string text string that represents the given argument value in 1083 * a DBMS specific format. 1084 * @access public 1085 */ 1086 function getBlobValue($prepared_query, $parameter, $blob) 1087 { 1088 $value = "0x"; 1089 while(!$this->endOfLob($blob)) 1090 { 1091 if (MDB::isError($result = $this->readLob($blob, $data, $this->options['lob_buffer_length']))) { 1092 return($result); 1093 } 1094 $value.= Bin2Hex($data); 1095 } 1096 return($value); 1097 } 1098 1099 // }}} 1100 // {{{ freeBlobValue() 1101 1102 /** 1103 * free a binary large object 1104 * 1105 * @param resource $prepared_query query handle from prepare() 1106 * @param string $blob 1107 * @return MDB_OK 1108 * @access public 1109 */ 1110 function freeBlobValue($prepared_query, $blob) 1111 { 1112 unset($this->lobs[$blob]); 1113 return(MDB_OK); 1114 } 1115 1116 // }}} 1117 // {{{ getBooleanValue() 1118 1119 /** 1120 * Convert a text value into a DBMS specific format that is suitable to 1121 * compose query statements. 1122 * 1123 * @param string $value text string value that is intended to be converted. 1124 * @return string text string that represents the given argument value in 1125 * a DBMS specific format. 1126 * @access public 1127 */ 1128 function getBooleanValue($value) 1129 { 1130 return(($value === NULL) ? 'NULL' : $value); 1131 } 1132 1133 // }}} 1134 // {{{ getFloatValue() 1135 1136 /** 1137 * Convert a text value into a DBMS specific format that is suitable to 1138 * compose query statements. 1139 * 1140 * @param string $value text string value that is intended to be converted. 1141 * @return string text string that represents the given argument value in 1142 * a DBMS specific format. 1143 * @access public 1144 */ 1145 function getFloatValue($value) 1146 { 1147 return(($value === NULL) ? 'NULL' : $value); 1148 } 1149 1150 // }}} 1151 // {{{ getDecimalValue() 1152 1153 /** 1154 * Convert a text value into a DBMS specific format that is suitable to 1155 * compose query statements. 1156 * 1157 * @param string $value text string value that is intended to be converted. 1158 * @return string text string that represents the given argument value in 1159 * a DBMS specific format. 1160 * @access public 1161 */ 1162 function getDecimalValue($value) 1163 { 1164 return(($value === NULL) ? 'NULL' : $value); 1165 } 1166 1167 // }}} 1168 // {{{ nextId() 1169 1170 /** 1171 * returns the next free id of a sequence 1172 * 1173 * @param string $seq_name name of the sequence 1174 * @param boolean $ondemand when true the seqence is 1175 * automatic created, if it 1176 * not exists 1177 * 1178 * @return mixed MDB_Error or id 1179 * @access public 1180 */ 1181 function nextId($seq_name, $ondemand = TRUE) 1182 { 1183 $sequence_name = $this->getSequenceName($seq_name); 1184 $this->expectError(MDB_ERROR_NOSUCHTABLE); 1185 $result = $this->query("INSERT INTO $sequence_name DEFAULT VALUES"); 1186 $this->popExpect(); 1187 if ($ondemand && MDB::isError($result) && 1188 $result->getCode() == MDB_ERROR_NOSUCHTABLE) 1189 { 1190 // Since we are creating the sequence on demand 1191 // we know the first id = 1 so initialize the 1192 // sequence at 2 1193 $result = $this->createSequence($seq_name, 2); 1194 if (MDB::isError($result)) { 1195 return($this->raiseError(MDB_ERROR, NULL, NULL, 1196 'Next ID: on demand sequence could not be created')); 1197 } else { 1198 // First ID of a newly created sequence is 1 1199 return(1); 1200 } 1201 } 1202 $value = $this->queryOne("SELECT @@IDENTITY FROM $sequence_name", 'integer'); 1203 if (MDB::isError($value)) { 1204 return($value); 1205 } 1206 $result = $this->query("DELETE FROM $sequence_name WHERE ".$this->options['sequence_col_name']." < $value"); 1207 if (MDB::isError($result)) { 1208 $this->warnings[] = 'nextID: could not delete previous sequence table values'; 1209 } 1210 return($value); 1211 } 1212 1213 // }}} 1214 // {{{ fetchInto() 1215 1216 /** 1217 * Fetch a row and insert the data into an existing array. 1218 * 1219 * @param resource $result result identifier 1220 * @param int $fetchmode how the array data should be indexed 1221 * @param int $rownum the row number to fetch 1222 * @return int data array on success, a MDB error on failure 1223 * @access public 1224 */ 1225 function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL) 1226 { 1227 $result_value = intval($result); 1228 if (is_null($rownum)) { 1229 ++$this->highest_fetched_row[$result_value]; 1230 } else { 1231 $this->highest_fetched_row[$result_value] = 1232 max($this->highest_fetched_row[$result_value], $rownum); 1233 if (isset($this->limits[$result_value])) { 1234 $rownum = $rownum + $this->limits[$result_value][0]; 1235 } 1236 if (!@mssql_data_seek($result, $rownum)) { 1237 return(NULL); 1238 } 1239 } 1240 if ($fetchmode == MDB_FETCHMODE_DEFAULT) { 1241 $fetchmode = $this->fetchmode; 1242 } 1243 if ($fetchmode & MDB_FETCHMODE_ASSOC) { 1244 $row = @mssql_fetch_assoc($result); 1245 if (is_array($row) && $this->options['optimize'] == 'portability') { 1246 $row = array_change_key_case($row, CASE_LOWER); 1247 } 1248 } else { 1249 $row = @mssql_fetch_row($result); 1250 } 1251 if (!$row) { 1252 if($this->options['autofree']) { 1253 $this->freeResult($result); 1254 } 1255 return(NULL); 1256 } 1257 if (isset($this->result_types[$result_value])) { 1258 $row = $this->convertResultRow($result, $row); 1259 } 1260 return($row); 1261 } 1262 1263 // }}} 1264 // {{{ tableInfo() 1265 1266 /** 1267 * Returns information about a table or a result set 1268 * 1269 * NOTE: doesn't support table name and flags if called from a db_result 1270 * 1271 * @param mixed $resource SQL Server result identifier or table name 1272 * @param int $mode A valid tableInfo mode (MDB_TABLEINFO_ORDERTABLE or 1273 * MDB_TABLEINFO_ORDER) 1274 * 1275 * @return array An array with all the information 1276 */ 1277 function tableInfo($result, $mode = NULL) 1278 { 1279 1280 $count = 0; 1281 $id = 0; 1282 $res = array(); 1283 1284 /* 1285 * depending on $mode, metadata returns the following values: 1286 * 1287 * - mode is false (default): 1288 * $result[]: 1289 * [0]['table'] table name 1290 * [0]['name'] field name 1291 * [0]['type'] field type 1292 * [0]['len'] field length 1293 * [0]['flags'] field flags 1294 * 1295 * - mode is MDB_TABLEINFO_ORDER 1296 * $result[]: 1297 * ["num_fields"] number of metadata records 1298 * [0]['table'] table name 1299 * [0]['name'] field name 1300 * [0]['type'] field type 1301 * [0]['len'] field length 1302 * [0]['flags'] field flags 1303 * ['order'][field name] index of field named "field name" 1304 * The last one is used, if you have a field name, but no index. 1305 * Test: if (isset($result['meta']['myfield'])) { ... 1306 * 1307 * - mode is MDB_TABLEINFO_ORDERTABLE 1308 * the same as above. but additionally 1309 * ["ordertable"][table name][field name] index of field 1310 * named "field name" 1311 * 1312 * this is, because if you have fields from different 1313 * tables with the same field name * they override each 1314 * other with MDB_TABLEINFO_ORDER 1315 * 1316 * you can combine MDB_TABLEINFO_ORDER and 1317 * MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER | 1318 * MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL 1319 */ 1320 1321 // if $result is a string, then we want information about a 1322 // table without a resultset 1323 1324 if (is_string($result)) { 1325 if (!@mssql_select_db($this->database_name, $this->connection)) { 1326 return $this->mssqlRaiseError(); 1327 } 1328 $id = @mssql_query("SELECT * FROM $result", $this->connection); 1329 if (empty($id)) { 1330 return($this->mssqlRaiseError()); 1331 } 1332 } else { // else we want information about a resultset 1333 $id = $result; 1334 if (empty($id)) { 1335 return($this->mssqlRaiseError()); 1336 } 1337 } 1338 1339 $count = @mssql_num_fields($id); 1340 1341 // made this IF due to performance (one if is faster than $count if's) 1342 if (empty($mode)) { 1343 1344 for ($i=0; $i<$count; $i++) { 1345 $res[$i]['table'] = (is_string($result)) ? $result : ''; 1346 $res[$i]['name'] = @mssql_field_name($id, $i); 1347 $res[$i]['type'] = @mssql_field_type($id, $i); 1348 $res[$i]['len'] = @mssql_field_length($id, $i); 1349 // We only support flags for tables 1350 $res[$i]['flags'] = is_string($result) ? $this->_mssql_field_flags($result, $res[$i]['name']) : ''; 1351 } 1352 1353 } else { // full 1354 $res['num_fields']= $count; 1355 1356 for ($i=0; $i<$count; $i++) { 1357 $res[$i]['table'] = (is_string($result)) ? $result : ''; 1358 $res[$i]['name'] = @mssql_field_name($id, $i); 1359 $res[$i]['type'] = @mssql_field_type($id, $i); 1360 $res[$i]['len'] = @mssql_field_length($id, $i); 1361 // We only support flags for tables 1362 $res[$i]['flags'] = is_string($result) ? $this->_mssql_field_flags($result, $res[$i]['name']) : ''; 1363 if ($mode & MDB_TABLEINFO_ORDER) { 1364 $res['order'][$res[$i]['name']] = $i; 1365 } 1366 if ($mode & MDB_TABLEINFO_ORDERTABLE) { 1367 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 1368 } 1369 } 1370 } 1371 1372 // free the result only if we were called on a table 1373 if (is_string($result)) { 1374 @mssql_free_result($id); 1375 } 1376 return($res); 1377 } 1378 1379 // }}} 1380 // {{{ _mssql_field_flags() 1381 /** 1382 * Get the flags for a field, currently only supports "isnullable" and "primary_key" 1383 * 1384 * @param string The table name 1385 * @param string The field 1386 * @access private 1387 */ 1388 function _mssql_field_flags($table, $column) 1389 { 1390 static $current_table = NULL; 1391 static $flags; 1392 // At the first call we discover the flags for all fields 1393 if ($table != $current_table) { 1394 $flags = array(); 1395 // find nullable fields 1396 $q_nulls = "SELECT syscolumns.name, syscolumns.isnullable 1397 FROM sysobjects 1398 INNER JOIN syscolumns ON sysobjects.id = syscolumns.id 1399 WHERE sysobjects.name ='$table' AND syscolumns.isnullable = 1"; 1400 $res = $this->query($q_nulls, NULL, FALSE); 1401 $res = $this->fetchAll($res, MDB_FETCHMODE_ASSOC); 1402 foreach ($res as $data) { 1403 if ($data['isnullable'] == 1) { 1404 $flags[$data['name']][] = 'isnullable'; 1405 } 1406 } 1407 // find primary keys 1408 $res2 = $this->query("EXEC SP_PKEYS[$table]", NULL, FALSE); 1409 $res2 = $this->fetchAll($res, MDB_FETCHMODE_ASSOC); 1410 foreach ($res2 as $data) { 1411 if (!empty($data['COLUMN_NAME'])) { 1412 $flags[$data['COLUMN_NAME']][] = 'primary_key'; 1413 } 1414 } 1415 $current_table = $table; 1416 } 1417 if (isset($flags[$column])) { 1418 return(implode(',', $flags[$column])); 1419 } 1420 return(''); 1421 } 1422 // }}} 1423 } 1424 1425 ?>
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 |