[ Index ]
 

Code source de PHP PEAR 1.4.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/DB/ -> mssql.php (source)

   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  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7