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