source: branches/feature-module-update/data/module/DB/mysqli.php @ 15532

Revision 15532, 33.0 KB checked in by nanasess, 14 years ago (diff)

svn:mime-type 修正

  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
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$
23 * @link       http://pear.php.net/package/DB
24 */
25
26/**
27 * Obtain the DB_common class so it can be extended from
28 */
29require_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: @package_version@
47 * @link       http://pear.php.net/package/DB
48 * @since      Class functional since Release 1.6.3
49 */
50class 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?>
Note: See TracBrowser for help on using the repository browser.