[ Index ]
 

Code source de PHP PEAR 1.4.5

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

title

Body

[fermer]

/DB/ -> mysqli.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 mysqli extension
   7   * for interacting with MySQL 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     Daniel Convissor <danielc@php.net>
  20   * @copyright  1997-2005 The PHP Group
  21   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22   * @version    CVS: $Id: mysqli.php,v 1.78 2007/01/12 03:11:17 aharvey Exp $
  23   * @link       http://pear.php.net/package/DB
  24   */
  25  
  26  /**
  27   * Obtain the DB_common class so it can be extended from
  28   */
  29  require_once  'DB/common.php';
  30  
  31  /**
  32   * The methods PEAR DB uses to interact with PHP's mysqli extension
  33   * for interacting with MySQL databases
  34   *
  35   * This is for MySQL versions 4.1 and above.  Requires PHP 5.
  36   *
  37   * Note that persistent connections no longer exist.
  38   *
  39   * These methods overload the ones declared in DB_common.
  40   *
  41   * @category   Database
  42   * @package    DB
  43   * @author     Daniel Convissor <danielc@php.net>
  44   * @copyright  1997-2005 The PHP Group
  45   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  46   * @version    Release: 1.7.9
  47   * @link       http://pear.php.net/package/DB
  48   * @since      Class functional since Release 1.6.3
  49   */
  50  class DB_mysqli extends DB_common
  51  {
  52      // {{{ properties
  53  
  54      /**
  55       * The DB driver type (mysql, oci8, odbc, etc.)
  56       * @var string
  57       */
  58      var $phptype = 'mysqli';
  59  
  60      /**
  61       * The database syntax variant to be used (db2, access, etc.), if any
  62       * @var string
  63       */
  64      var $dbsyntax = 'mysqli';
  65  
  66      /**
  67       * The capabilities of this DB implementation
  68       *
  69       * The 'new_link' element contains the PHP version that first provided
  70       * new_link support for this DBMS.  Contains false if it's unsupported.
  71       *
  72       * Meaning of the 'limit' element:
  73       *   + 'emulate' = emulate with fetch row by number
  74       *   + 'alter'   = alter the query
  75       *   + false     = skip rows
  76       *
  77       * @var array
  78       */
  79      var $features = array(
  80          'limit'         => 'alter',
  81          'new_link'      => false,
  82          'numrows'       => true,
  83          'pconnect'      => false,
  84          'prepare'       => false,
  85          'ssl'           => true,
  86          'transactions'  => true,
  87      );
  88  
  89      /**
  90       * A mapping of native error codes to DB error codes
  91       * @var array
  92       */
  93      var $errorcode_map = array(
  94          1004 => DB_ERROR_CANNOT_CREATE,
  95          1005 => DB_ERROR_CANNOT_CREATE,
  96          1006 => DB_ERROR_CANNOT_CREATE,
  97          1007 => DB_ERROR_ALREADY_EXISTS,
  98          1008 => DB_ERROR_CANNOT_DROP,
  99          1022 => DB_ERROR_ALREADY_EXISTS,
 100          1044 => DB_ERROR_ACCESS_VIOLATION,
 101          1046 => DB_ERROR_NODBSELECTED,
 102          1048 => DB_ERROR_CONSTRAINT,
 103          1049 => DB_ERROR_NOSUCHDB,
 104          1050 => DB_ERROR_ALREADY_EXISTS,
 105          1051 => DB_ERROR_NOSUCHTABLE,
 106          1054 => DB_ERROR_NOSUCHFIELD,
 107          1061 => DB_ERROR_ALREADY_EXISTS,
 108          1062 => DB_ERROR_ALREADY_EXISTS,
 109          1064 => DB_ERROR_SYNTAX,
 110          1091 => DB_ERROR_NOT_FOUND,
 111          1100 => DB_ERROR_NOT_LOCKED,
 112          1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
 113          1142 => DB_ERROR_ACCESS_VIOLATION,
 114          1146 => DB_ERROR_NOSUCHTABLE,
 115          1216 => DB_ERROR_CONSTRAINT,
 116          1217 => DB_ERROR_CONSTRAINT,
 117          1356 => DB_ERROR_DIVZERO,
 118          1451 => DB_ERROR_CONSTRAINT,
 119          1452 => DB_ERROR_CONSTRAINT,
 120      );
 121  
 122      /**
 123       * The raw database connection created by PHP
 124       * @var resource
 125       */
 126      var $connection;
 127  
 128      /**
 129       * The DSN information for connecting to a database
 130       * @var array
 131       */
 132      var $dsn = array();
 133  
 134  
 135      /**
 136       * Should data manipulation queries be committed automatically?
 137       * @var bool
 138       * @access private
 139       */
 140      var $autocommit = true;
 141  
 142      /**
 143       * The quantity of transactions begun
 144       *
 145       * {@internal  While this is private, it can't actually be designated
 146       * private in PHP 5 because it is directly accessed in the test suite.}}
 147       *
 148       * @var integer
 149       * @access private
 150       */
 151      var $transaction_opcount = 0;
 152  
 153      /**
 154       * The database specified in the DSN
 155       *
 156       * It's a fix to allow calls to different databases in the same script.
 157       *
 158       * @var string
 159       * @access private
 160       */
 161      var $_db = '';
 162  
 163      /**
 164       * Array for converting MYSQLI_*_FLAG constants to text values
 165       * @var    array
 166       * @access public
 167       * @since  Property available since Release 1.6.5
 168       */
 169      var $mysqli_flags = array(
 170          MYSQLI_NOT_NULL_FLAG        => 'not_null',
 171          MYSQLI_PRI_KEY_FLAG         => 'primary_key',
 172          MYSQLI_UNIQUE_KEY_FLAG      => 'unique_key',
 173          MYSQLI_MULTIPLE_KEY_FLAG    => 'multiple_key',
 174          MYSQLI_BLOB_FLAG            => 'blob',
 175          MYSQLI_UNSIGNED_FLAG        => 'unsigned',
 176          MYSQLI_ZEROFILL_FLAG        => 'zerofill',
 177          MYSQLI_AUTO_INCREMENT_FLAG  => 'auto_increment',
 178          MYSQLI_TIMESTAMP_FLAG       => 'timestamp',
 179          MYSQLI_SET_FLAG             => 'set',
 180          // MYSQLI_NUM_FLAG             => 'numeric',  // unnecessary
 181          // MYSQLI_PART_KEY_FLAG        => 'multiple_key',  // duplicatvie
 182          MYSQLI_GROUP_FLAG           => 'group_by'
 183      );
 184  
 185      /**
 186       * Array for converting MYSQLI_TYPE_* constants to text values
 187       * @var    array
 188       * @access public
 189       * @since  Property available since Release 1.6.5
 190       */
 191      var $mysqli_types = array(
 192          MYSQLI_TYPE_DECIMAL     => 'decimal',
 193          246                     => 'decimal',
 194          MYSQLI_TYPE_TINY        => 'tinyint',
 195          MYSQLI_TYPE_SHORT       => 'int',
 196          MYSQLI_TYPE_LONG        => 'int',
 197          MYSQLI_TYPE_FLOAT       => 'float',
 198          MYSQLI_TYPE_DOUBLE      => 'double',
 199          // MYSQLI_TYPE_NULL        => 'DEFAULT NULL',  // let flags handle it
 200          MYSQLI_TYPE_TIMESTAMP   => 'timestamp',
 201          MYSQLI_TYPE_LONGLONG    => 'bigint',
 202          MYSQLI_TYPE_INT24       => 'mediumint',
 203          MYSQLI_TYPE_DATE        => 'date',
 204          MYSQLI_TYPE_TIME        => 'time',
 205          MYSQLI_TYPE_DATETIME    => 'datetime',
 206          MYSQLI_TYPE_YEAR        => 'year',
 207          MYSQLI_TYPE_NEWDATE     => 'date',
 208          MYSQLI_TYPE_ENUM        => 'enum',
 209          MYSQLI_TYPE_SET         => 'set',
 210          MYSQLI_TYPE_TINY_BLOB   => 'tinyblob',
 211          MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
 212          MYSQLI_TYPE_LONG_BLOB   => 'longblob',
 213          MYSQLI_TYPE_BLOB        => 'blob',
 214          MYSQLI_TYPE_VAR_STRING  => 'varchar',
 215          MYSQLI_TYPE_STRING      => 'char',
 216          MYSQLI_TYPE_GEOMETRY    => 'geometry',
 217      );
 218  
 219  
 220      // }}}
 221      // {{{ constructor
 222  
 223      /**
 224       * This constructor calls <kbd>$this->DB_common()</kbd>
 225       *
 226       * @return void
 227       */
 228      function DB_mysqli()
 229      {
 230          $this->DB_common();
 231      }
 232  
 233      // }}}
 234      // {{{ connect()
 235  
 236      /**
 237       * Connect to the database server, log in and open the database
 238       *
 239       * Don't call this method directly.  Use DB::connect() instead.
 240       *
 241       * PEAR DB's mysqli driver supports the following extra DSN options:
 242       *   + When the 'ssl' $option passed to DB::connect() is true:
 243       *     + key      The path to the key file.
 244       *     + cert     The path to the certificate file.
 245       *     + ca       The path to the certificate authority file.
 246       *     + capath   The path to a directory that contains trusted SSL
 247       *                 CA certificates in pem format.
 248       *     + cipher   The list of allowable ciphers for SSL encryption.
 249       *
 250       * Example of how to connect using SSL:
 251       * <code>
 252       * require_once 'DB.php';
 253       * 
 254       * $dsn = array(
 255       *     'phptype'  => 'mysqli',
 256       *     'username' => 'someuser',
 257       *     'password' => 'apasswd',
 258       *     'hostspec' => 'localhost',
 259       *     'database' => 'thedb',
 260       *     'key'      => 'client-key.pem',
 261       *     'cert'     => 'client-cert.pem',
 262       *     'ca'       => 'cacert.pem',
 263       *     'capath'   => '/path/to/ca/dir',
 264       *     'cipher'   => 'AES',
 265       * );
 266       * 
 267       * $options = array(
 268       *     'ssl' => true,
 269       * );
 270       * 
 271       * $db =& DB::connect($dsn, $options);
 272       * if (PEAR::isError($db)) {
 273       *     die($db->getMessage());
 274       * }
 275       * </code>
 276       *
 277       * @param array $dsn         the data source name
 278       * @param bool  $persistent  should the connection be persistent?
 279       *
 280       * @return int  DB_OK on success. A DB_Error object on failure.
 281       */
 282      function connect($dsn, $persistent = false)
 283      {
 284          if (!PEAR::loadExtension('mysqli')) {
 285              return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
 286          }
 287  
 288          $this->dsn = $dsn;
 289          if ($dsn['dbsyntax']) {
 290              $this->dbsyntax = $dsn['dbsyntax'];
 291          }
 292  
 293          $ini = ini_get('track_errors');
 294          @ini_set('track_errors', 1);
 295          $php_errormsg = '';
 296  
 297          if (((int) $this->getOption('ssl')) === 1) {
 298              $init = mysqli_init();
 299              mysqli_ssl_set(
 300                  $init,
 301                  empty($dsn['key'])    ? null : $dsn['key'],
 302                  empty($dsn['cert'])   ? null : $dsn['cert'],
 303                  empty($dsn['ca'])     ? null : $dsn['ca'],
 304                  empty($dsn['capath']) ? null : $dsn['capath'],
 305                  empty($dsn['cipher']) ? null : $dsn['cipher']
 306              );
 307              if ($this->connection = @mysqli_real_connect(
 308                      $init,
 309                      $dsn['hostspec'],
 310                      $dsn['username'],
 311                      $dsn['password'],
 312                      $dsn['database'],
 313                      $dsn['port'],
 314                      $dsn['socket']))
 315              {
 316                  $this->connection = $init;
 317              }
 318          } else {
 319              $this->connection = @mysqli_connect(
 320                  $dsn['hostspec'],
 321                  $dsn['username'],
 322                  $dsn['password'],
 323                  $dsn['database'],
 324                  $dsn['port'],
 325                  $dsn['socket']
 326              );
 327          }
 328  
 329          @ini_set('track_errors', $ini);
 330  
 331          if (!$this->connection) {
 332              if (($err = @mysqli_connect_error()) != '') {
 333                  return $this->raiseError(DB_ERROR_CONNECT_FAILED,
 334                                           null, null, null,
 335                                           $err);
 336              } else {
 337                  return $this->raiseError(DB_ERROR_CONNECT_FAILED,
 338                                           null, null, null,
 339                                           $php_errormsg);
 340              }
 341          }
 342  
 343          if ($dsn['database']) {
 344              $this->_db = $dsn['database'];
 345          }
 346  
 347          return DB_OK;
 348      }
 349  
 350      // }}}
 351      // {{{ disconnect()
 352  
 353      /**
 354       * Disconnects from the database server
 355       *
 356       * @return bool  TRUE on success, FALSE on failure
 357       */
 358      function disconnect()
 359      {
 360          $ret = @mysqli_close($this->connection);
 361          $this->connection = null;
 362          return $ret;
 363      }
 364  
 365      // }}}
 366      // {{{ simpleQuery()
 367  
 368      /**
 369       * Sends a query to the database server
 370       *
 371       * @param string  the SQL query string
 372       *
 373       * @return mixed  + a PHP result resrouce for successful SELECT queries
 374       *                + the DB_OK constant for other successful queries
 375       *                + a DB_Error object on failure
 376       */
 377      function simpleQuery($query)
 378      {
 379          $ismanip = $this->_checkManip($query);
 380          $this->last_query = $query;
 381          $query = $this->modifyQuery($query);
 382          if ($this->_db) {
 383              if (!@mysqli_select_db($this->connection, $this->_db)) {
 384                  return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
 385              }
 386          }
 387          if (!$this->autocommit && $ismanip) {
 388              if ($this->transaction_opcount == 0) {
 389                  $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0');
 390                  $result = @mysqli_query($this->connection, 'BEGIN');
 391                  if (!$result) {
 392                      return $this->mysqliRaiseError();
 393                  }
 394              }
 395              $this->transaction_opcount++;
 396          }
 397          $result = @mysqli_query($this->connection, $query);
 398          if (!$result) {
 399              return $this->mysqliRaiseError();
 400          }
 401          if (is_object($result)) {
 402              return $result;
 403          }
 404          return DB_OK;
 405      }
 406  
 407      // }}}
 408      // {{{ nextResult()
 409  
 410      /**
 411       * Move the internal mysql result pointer to the next available result.
 412       *
 413       * This method has not been implemented yet.
 414       *
 415       * @param resource $result a valid sql result resource
 416       * @return false
 417       * @access public
 418       */
 419      function nextResult($result)
 420      {
 421          return false;
 422      }
 423  
 424      // }}}
 425      // {{{ fetchInto()
 426  
 427      /**
 428       * Places a row from the result set into the given array
 429       *
 430       * Formating of the array and the data therein are configurable.
 431       * See DB_result::fetchInto() for more information.
 432       *
 433       * This method is not meant to be called directly.  Use
 434       * DB_result::fetchInto() instead.  It can't be declared "protected"
 435       * because DB_result is a separate object.
 436       *
 437       * @param resource $result    the query result resource
 438       * @param array    $arr       the referenced array to put the data in
 439       * @param int      $fetchmode how the resulting array should be indexed
 440       * @param int      $rownum    the row number to fetch (0 = first row)
 441       *
 442       * @return mixed  DB_OK on success, NULL when the end of a result set is
 443       *                 reached or on failure
 444       *
 445       * @see DB_result::fetchInto()
 446       */
 447      function fetchInto($result, &$arr, $fetchmode, $rownum = null)
 448      {
 449          if ($rownum !== null) {
 450              if (!@mysqli_data_seek($result, $rownum)) {
 451                  return null;
 452              }
 453          }
 454          if ($fetchmode & DB_FETCHMODE_ASSOC) {
 455              $arr = @mysqli_fetch_array($result, MYSQLI_ASSOC);
 456              if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
 457                  $arr = array_change_key_case($arr, CASE_LOWER);
 458              }
 459          } else {
 460              $arr = @mysqli_fetch_row($result);
 461          }
 462          if (!$arr) {
 463              return null;
 464          }
 465          if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
 466              /*
 467               * Even though this DBMS already trims output, we do this because
 468               * a field might have intentional whitespace at the end that
 469               * gets removed by DB_PORTABILITY_RTRIM under another driver.
 470               */
 471              $this->_rtrimArrayValues($arr);
 472          }
 473          if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
 474              $this->_convertNullArrayValuesToEmpty($arr);
 475          }
 476          return DB_OK;
 477      }
 478  
 479      // }}}
 480      // {{{ freeResult()
 481  
 482      /**
 483       * Deletes the result set and frees the memory occupied by the result set
 484       *
 485       * This method is not meant to be called directly.  Use
 486       * DB_result::free() instead.  It can't be declared "protected"
 487       * because DB_result is a separate object.
 488       *
 489       * @param resource $result  PHP's query result resource
 490       *
 491       * @return bool  TRUE on success, FALSE if $result is invalid
 492       *
 493       * @see DB_result::free()
 494       */
 495      function freeResult($result)
 496      {
 497          return is_resource($result) ? mysqli_free_result($result) : false;
 498      }
 499  
 500      // }}}
 501      // {{{ numCols()
 502  
 503      /**
 504       * Gets the number of columns in a result set
 505       *
 506       * This method is not meant to be called directly.  Use
 507       * DB_result::numCols() instead.  It can't be declared "protected"
 508       * because DB_result is a separate object.
 509       *
 510       * @param resource $result  PHP's query result resource
 511       *
 512       * @return int  the number of columns.  A DB_Error object on failure.
 513       *
 514       * @see DB_result::numCols()
 515       */
 516      function numCols($result)
 517      {
 518          $cols = @mysqli_num_fields($result);
 519          if (!$cols) {
 520              return $this->mysqliRaiseError();
 521          }
 522          return $cols;
 523      }
 524  
 525      // }}}
 526      // {{{ numRows()
 527  
 528      /**
 529       * Gets the number of rows in a result set
 530       *
 531       * This method is not meant to be called directly.  Use
 532       * DB_result::numRows() instead.  It can't be declared "protected"
 533       * because DB_result is a separate object.
 534       *
 535       * @param resource $result  PHP's query result resource
 536       *
 537       * @return int  the number of rows.  A DB_Error object on failure.
 538       *
 539       * @see DB_result::numRows()
 540       */
 541      function numRows($result)
 542      {
 543          $rows = @mysqli_num_rows($result);
 544          if ($rows === null) {
 545              return $this->mysqliRaiseError();
 546          }
 547          return $rows;
 548      }
 549  
 550      // }}}
 551      // {{{ autoCommit()
 552  
 553      /**
 554       * Enables or disables automatic commits
 555       *
 556       * @param bool $onoff  true turns it on, false turns it off
 557       *
 558       * @return int  DB_OK on success.  A DB_Error object if the driver
 559       *               doesn't support auto-committing transactions.
 560       */
 561      function autoCommit($onoff = false)
 562      {
 563          // XXX if $this->transaction_opcount > 0, we should probably
 564          // issue a warning here.
 565          $this->autocommit = $onoff ? true : false;
 566          return DB_OK;
 567      }
 568  
 569      // }}}
 570      // {{{ commit()
 571  
 572      /**
 573       * Commits the current transaction
 574       *
 575       * @return int  DB_OK on success.  A DB_Error object on failure.
 576       */
 577      function commit()
 578      {
 579          if ($this->transaction_opcount > 0) {
 580              if ($this->_db) {
 581                  if (!@mysqli_select_db($this->connection, $this->_db)) {
 582                      return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
 583                  }
 584              }
 585              $result = @mysqli_query($this->connection, 'COMMIT');
 586              $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
 587              $this->transaction_opcount = 0;
 588              if (!$result) {
 589                  return $this->mysqliRaiseError();
 590              }
 591          }
 592          return DB_OK;
 593      }
 594  
 595      // }}}
 596      // {{{ rollback()
 597  
 598      /**
 599       * Reverts the current transaction
 600       *
 601       * @return int  DB_OK on success.  A DB_Error object on failure.
 602       */
 603      function rollback()
 604      {
 605          if ($this->transaction_opcount > 0) {
 606              if ($this->_db) {
 607                  if (!@mysqli_select_db($this->connection, $this->_db)) {
 608                      return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED);
 609                  }
 610              }
 611              $result = @mysqli_query($this->connection, 'ROLLBACK');
 612              $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
 613              $this->transaction_opcount = 0;
 614              if (!$result) {
 615                  return $this->mysqliRaiseError();
 616              }
 617          }
 618          return DB_OK;
 619      }
 620  
 621      // }}}
 622      // {{{ affectedRows()
 623  
 624      /**
 625       * Determines the number of rows affected by a data maniuplation query
 626       *
 627       * 0 is returned for queries that don't manipulate data.
 628       *
 629       * @return int  the number of rows.  A DB_Error object on failure.
 630       */
 631      function affectedRows()
 632      {
 633          if ($this->_last_query_manip) {
 634              return @mysqli_affected_rows($this->connection);
 635          } else {
 636              return 0;
 637          }
 638       }
 639  
 640      // }}}
 641      // {{{ nextId()
 642  
 643      /**
 644       * Returns the next free id in a sequence
 645       *
 646       * @param string  $seq_name  name of the sequence
 647       * @param boolean $ondemand  when true, the seqence is automatically
 648       *                            created if it does not exist
 649       *
 650       * @return int  the next id number in the sequence.
 651       *               A DB_Error object on failure.
 652       *
 653       * @see DB_common::nextID(), DB_common::getSequenceName(),
 654       *      DB_mysqli::createSequence(), DB_mysqli::dropSequence()
 655       */
 656      function nextId($seq_name, $ondemand = true)
 657      {
 658          $seqname = $this->getSequenceName($seq_name);
 659          do {
 660              $repeat = 0;
 661              $this->pushErrorHandling(PEAR_ERROR_RETURN);
 662              $result = $this->query('UPDATE ' . $seqname
 663                                     . ' SET id = LAST_INSERT_ID(id + 1)');
 664              $this->popErrorHandling();
 665              if ($result === DB_OK) {
 666                  // COMMON CASE
 667                  $id = @mysqli_insert_id($this->connection);
 668                  if ($id != 0) {
 669                      return $id;
 670                  }
 671  
 672                  // EMPTY SEQ TABLE
 673                  // Sequence table must be empty for some reason,
 674                  // so fill it and return 1
 675                  // Obtain a user-level lock
 676                  $result = $this->getOne('SELECT GET_LOCK('
 677                                          . "'$seqname}_lock', 10)");
 678                  if (DB::isError($result)) {
 679                      return $this->raiseError($result);
 680                  }
 681                  if ($result == 0) {
 682                      return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
 683                  }
 684  
 685                  // add the default value
 686                  $result = $this->query('REPLACE INTO ' . $seqname
 687                                         . ' (id) VALUES (0)');
 688                  if (DB::isError($result)) {
 689                      return $this->raiseError($result);
 690                  }
 691  
 692                  // Release the lock
 693                  $result = $this->getOne('SELECT RELEASE_LOCK('
 694                                          . "'$seqname}_lock')");
 695                  if (DB::isError($result)) {
 696                      return $this->raiseError($result);
 697                  }
 698                  // We know what the result will be, so no need to try again
 699                  return 1;
 700  
 701              } elseif ($ondemand && DB::isError($result) &&
 702                  $result->getCode() == DB_ERROR_NOSUCHTABLE)
 703              {
 704                  // ONDEMAND TABLE CREATION
 705                  $result = $this->createSequence($seq_name);
 706  
 707                  // Since createSequence initializes the ID to be 1,
 708                  // we do not need to retrieve the ID again (or we will get 2)
 709                  if (DB::isError($result)) {
 710                      return $this->raiseError($result);
 711                  } else {
 712                      // First ID of a newly created sequence is 1
 713                      return 1;
 714                  }
 715  
 716              } elseif (DB::isError($result) &&
 717                        $result->getCode() == DB_ERROR_ALREADY_EXISTS)
 718              {
 719                  // BACKWARDS COMPAT
 720                  // see _BCsequence() comment
 721                  $result = $this->_BCsequence($seqname);
 722                  if (DB::isError($result)) {
 723                      return $this->raiseError($result);
 724                  }
 725                  $repeat = 1;
 726              }
 727          } while ($repeat);
 728  
 729          return $this->raiseError($result);
 730      }
 731  
 732      /**
 733       * Creates a new sequence
 734       *
 735       * @param string $seq_name  name of the new sequence
 736       *
 737       * @return int  DB_OK on success.  A DB_Error object on failure.
 738       *
 739       * @see DB_common::createSequence(), DB_common::getSequenceName(),
 740       *      DB_mysqli::nextID(), DB_mysqli::dropSequence()
 741       */
 742      function createSequence($seq_name)
 743      {
 744          $seqname = $this->getSequenceName($seq_name);
 745          $res = $this->query('CREATE TABLE ' . $seqname
 746                              . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'
 747                              . ' PRIMARY KEY(id))');
 748          if (DB::isError($res)) {
 749              return $res;
 750          }
 751          // insert yields value 1, nextId call will generate ID 2
 752          return $this->query("INSERT INTO $seqname} (id) VALUES (0)");
 753      }
 754  
 755      // }}}
 756      // {{{ dropSequence()
 757  
 758      /**
 759       * Deletes a sequence
 760       *
 761       * @param string $seq_name  name of the sequence to be deleted
 762       *
 763       * @return int  DB_OK on success.  A DB_Error object on failure.
 764       *
 765       * @see DB_common::dropSequence(), DB_common::getSequenceName(),
 766       *      DB_mysql::nextID(), DB_mysql::createSequence()
 767       */
 768      function dropSequence($seq_name)
 769      {
 770          return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
 771      }
 772  
 773      // }}}
 774      // {{{ _BCsequence()
 775  
 776      /**
 777       * Backwards compatibility with old sequence emulation implementation
 778       * (clean up the dupes)
 779       *
 780       * @param string $seqname  the sequence name to clean up
 781       *
 782       * @return bool  true on success.  A DB_Error object on failure.
 783       *
 784       * @access private
 785       */
 786      function _BCsequence($seqname)
 787      {
 788          // Obtain a user-level lock... this will release any previous
 789          // application locks, but unlike LOCK TABLES, it does not abort
 790          // the current transaction and is much less frequently used.
 791          $result = $this->getOne("SELECT GET_LOCK('$seqname}_lock',10)");
 792          if (DB::isError($result)) {
 793              return $result;
 794          }
 795          if ($result == 0) {
 796              // Failed to get the lock, can't do the conversion, bail
 797              // with a DB_ERROR_NOT_LOCKED error
 798              return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED);
 799          }
 800  
 801          $highest_id = $this->getOne("SELECT MAX(id) FROM $seqname}");
 802          if (DB::isError($highest_id)) {
 803              return $highest_id;
 804          }
 805  
 806          // This should kill all rows except the highest
 807          // We should probably do something if $highest_id isn't
 808          // numeric, but I'm at a loss as how to handle that...
 809          $result = $this->query('DELETE FROM ' . $seqname
 810                                 . " WHERE id <> $highest_id");
 811          if (DB::isError($result)) {
 812              return $result;
 813          }
 814  
 815          // If another thread has been waiting for this lock,
 816          // it will go thru the above procedure, but will have no
 817          // real effect
 818          $result = $this->getOne("SELECT RELEASE_LOCK('$seqname}_lock')");
 819          if (DB::isError($result)) {
 820              return $result;
 821          }
 822          return true;
 823      }
 824  
 825      // }}}
 826      // {{{ quoteIdentifier()
 827  
 828      /**
 829       * Quotes a string so it can be safely used as a table or column name
 830       * (WARNING: using names that require this is a REALLY BAD IDEA)
 831       *
 832       * WARNING:  Older versions of MySQL can't handle the backtick
 833       * character (<kbd>`</kbd>) in table or column names.
 834       *
 835       * @param string $str  identifier name to be quoted
 836       *
 837       * @return string  quoted identifier string
 838       *
 839       * @see DB_common::quoteIdentifier()
 840       * @since Method available since Release 1.6.0
 841       */
 842      function quoteIdentifier($str)
 843      {
 844          return '`' . str_replace('`', '``', $str) . '`';
 845      }
 846  
 847      // }}}
 848      // {{{ escapeSimple()
 849  
 850      /**
 851       * Escapes a string according to the current DBMS's standards
 852       *
 853       * @param string $str  the string to be escaped
 854       *
 855       * @return string  the escaped string
 856       *
 857       * @see DB_common::quoteSmart()
 858       * @since Method available since Release 1.6.0
 859       */
 860      function escapeSimple($str)
 861      {
 862          return @mysqli_real_escape_string($this->connection, $str);
 863      }
 864  
 865      // }}}
 866      // {{{ modifyLimitQuery()
 867  
 868      /**
 869       * Adds LIMIT clauses to a query string according to current DBMS standards
 870       *
 871       * @param string $query   the query to modify
 872       * @param int    $from    the row to start to fetching (0 = the first row)
 873       * @param int    $count   the numbers of rows to fetch
 874       * @param mixed  $params  array, string or numeric data to be used in
 875       *                         execution of the statement.  Quantity of items
 876       *                         passed must match quantity of placeholders in
 877       *                         query:  meaning 1 placeholder for non-array
 878       *                         parameters or 1 placeholder per array element.
 879       *
 880       * @return string  the query string with LIMIT clauses added
 881       *
 882       * @access protected
 883       */
 884      function modifyLimitQuery($query, $from, $count, $params = array())
 885      {
 886          if (DB::isManip($query) || $this->_next_query_manip) {
 887              return $query . " LIMIT $count";
 888          } else {
 889              return $query . " LIMIT $from, $count";
 890          }
 891      }
 892  
 893      // }}}
 894      // {{{ mysqliRaiseError()
 895  
 896      /**
 897       * Produces a DB_Error object regarding the current problem
 898       *
 899       * @param int $errno  if the error is being manually raised pass a
 900       *                     DB_ERROR* constant here.  If this isn't passed
 901       *                     the error information gathered from the DBMS.
 902       *
 903       * @return object  the DB_Error object
 904       *
 905       * @see DB_common::raiseError(),
 906       *      DB_mysqli::errorNative(), DB_common::errorCode()
 907       */
 908      function mysqliRaiseError($errno = null)
 909      {
 910          if ($errno === null) {
 911              if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
 912                  $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
 913                  $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
 914                  $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
 915              } else {
 916                  // Doing this in case mode changes during runtime.
 917                  $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
 918                  $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
 919                  $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
 920              }
 921              $errno = $this->errorCode(mysqli_errno($this->connection));
 922          }
 923          return $this->raiseError($errno, null, null, null,
 924                                   @mysqli_errno($this->connection) . ' ** ' .
 925                                   @mysqli_error($this->connection));
 926      }
 927  
 928      // }}}
 929      // {{{ errorNative()
 930  
 931      /**
 932       * Gets the DBMS' native error code produced by the last query
 933       *
 934       * @return int  the DBMS' error code
 935       */
 936      function errorNative()
 937      {
 938          return @mysqli_errno($this->connection);
 939      }
 940  
 941      // }}}
 942      // {{{ tableInfo()
 943  
 944      /**
 945       * Returns information about a table or a result set
 946       *
 947       * @param object|string  $result  DB_result object from a query or a
 948       *                                 string containing the name of a table.
 949       *                                 While this also accepts a query result
 950       *                                 resource identifier, this behavior is
 951       *                                 deprecated.
 952       * @param int            $mode    a valid tableInfo mode
 953       *
 954       * @return array  an associative array with the information requested.
 955       *                 A DB_Error object on failure.
 956       *
 957       * @see DB_common::setOption()
 958       */
 959      function tableInfo($result, $mode = null)
 960      {
 961          if (is_string($result)) {
 962              /*
 963               * Probably received a table name.
 964               * Create a result resource identifier.
 965               */
 966              $id = @mysqli_query($this->connection,
 967                                  "SELECT * FROM $result LIMIT 0");
 968              $got_string = true;
 969          } elseif (isset($result->result)) {
 970              /*
 971               * Probably received a result object.
 972               * Extract the result resource identifier.
 973               */
 974              $id = $result->result;
 975              $got_string = false;
 976          } else {
 977              /*
 978               * Probably received a result resource identifier.
 979               * Copy it.
 980               * Deprecated.  Here for compatibility only.
 981               */
 982              $id = $result;
 983              $got_string = false;
 984          }
 985  
 986          if (!is_a($id, 'mysqli_result')) {
 987              return $this->mysqliRaiseError(DB_ERROR_NEED_MORE_DATA);
 988          }
 989  
 990          if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
 991              $case_func = 'strtolower';
 992          } else {
 993              $case_func = 'strval';
 994          }
 995  
 996          $count = @mysqli_num_fields($id);
 997          $res   = array();
 998  
 999          if ($mode) {
1000              $res['num_fields'] = $count;
1001          }
1002  
1003          for ($i = 0; $i < $count; $i++) {
1004              $tmp = @mysqli_fetch_field($id);
1005  
1006              $flags = '';
1007              foreach ($this->mysqli_flags as $const => $means) {
1008                  if ($tmp->flags & $const) {
1009                      $flags .= $means . ' ';
1010                  }
1011              }
1012              if ($tmp->def) {
1013                  $flags .= 'default_' . rawurlencode($tmp->def);
1014              }
1015              $flags = trim($flags);
1016  
1017              $res[$i] = array(
1018                  'table' => $case_func($tmp->table),
1019                  'name'  => $case_func($tmp->name),
1020                  'type'  => isset($this->mysqli_types[$tmp->type])
1021                                      ? $this->mysqli_types[$tmp->type]
1022                                      : 'unknown',
1023                  // http://bugs.php.net/?id=36579
1024                  'len'   => $tmp->length,
1025                  'flags' => $flags,
1026              );
1027  
1028              if ($mode & DB_TABLEINFO_ORDER) {
1029                  $res['order'][$res[$i]['name']] = $i;
1030              }
1031              if ($mode & DB_TABLEINFO_ORDERTABLE) {
1032                  $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
1033              }
1034          }
1035  
1036          // free the result only if we were called on a table
1037          if ($got_string) {
1038              @mysqli_free_result($id);
1039          }
1040          return $res;
1041      }
1042  
1043      // }}}
1044      // {{{ getSpecialQuery()
1045  
1046      /**
1047       * Obtains the query string needed for listing a given type of objects
1048       *
1049       * @param string $type  the kind of objects you want to retrieve
1050       *
1051       * @return string  the SQL query string or null if the driver doesn't
1052       *                  support the object type requested
1053       *
1054       * @access protected
1055       * @see DB_common::getListOf()
1056       */
1057      function getSpecialQuery($type)
1058      {
1059          switch ($type) {
1060              case 'tables':
1061                  return 'SHOW TABLES';
1062              case 'users':
1063                  return 'SELECT DISTINCT User FROM mysql.user';
1064              case 'databases':
1065                  return 'SHOW DATABASES';
1066              default:
1067                  return null;
1068          }
1069      }
1070  
1071      // }}}
1072  
1073  }
1074  
1075  /*
1076   * Local variables:
1077   * tab-width: 4
1078   * c-basic-offset: 4
1079   * End:
1080   */
1081  
1082  ?>


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