ここの情報は古いです。ご理解頂いた上でお取り扱いください。

source: OpenPNE/branches/ebihara/prj_pnebiz/lib/include/DB/common.php @ 557

Last change on this file since 557 was 557, checked in by ebihara, 14 years ago

create prj_pnebiz

File size: 67.9 KB
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5/**
6 * Contains the DB_common base class
7 *
8 * PHP versions 4 and 5
9 *
10 * LICENSE: This source file is subject to version 3.0 of the PHP license
11 * that is available through the world-wide-web at the following URI:
12 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
13 * the PHP License and are unable to obtain it through the web, please
14 * send a note to license@php.net so we can mail you a copy immediately.
15 *
16 * @category   Database
17 * @package    DB
18 * @author     Stig Bakken <ssb@php.net>
19 * @author     Tomas V.V. Cox <cox@idecnet.com>
20 * @author     Daniel Convissor <danielc@php.net>
21 * @copyright  1997-2005 The PHP Group
22 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
23 * @version    CVS: $Id: common.php,v 1.137 2005/04/07 14:27:35 danielc Exp $
24 * @link       http://pear.php.net/package/DB
25 */
26
27/**
28 * Obtain the PEAR class so it can be extended from
29 */
30require_once 'PEAR.php';
31
32/**
33 * DB_common is the base class from which each database driver class extends
34 *
35 * All common methods are declared here.  If a given DBMS driver contains
36 * a particular method, that method will overload the one here.
37 *
38 * @category   Database
39 * @package    DB
40 * @author     Stig Bakken <ssb@php.net>
41 * @author     Tomas V.V. Cox <cox@idecnet.com>
42 * @author     Daniel Convissor <danielc@php.net>
43 * @copyright  1997-2005 The PHP Group
44 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
45 * @version    Release: 1.7.6
46 * @link       http://pear.php.net/package/DB
47 */
48class DB_common extends PEAR
49{
50    // {{{ properties
51
52    /**
53     * The current default fetch mode
54     * @var integer
55     */
56    var $fetchmode = DB_FETCHMODE_ORDERED;
57
58    /**
59     * The name of the class into which results should be fetched when
60     * DB_FETCHMODE_OBJECT is in effect
61     *
62     * @var string
63     */
64    var $fetchmode_object_class = 'stdClass';
65
66    /**
67     * Was a connection present when the object was serialized()?
68     * @var bool
69     * @see DB_common::__sleep(), DB_common::__wake()
70     */
71    var $was_connected = null;
72
73    /**
74     * The most recently executed query
75     * @var string
76     */
77    var $last_query = '';
78
79    /**
80     * Run-time configuration options
81     *
82     * The 'optimize' option has been deprecated.  Use the 'portability'
83     * option instead.
84     *
85     * @var array
86     * @see DB_common::setOption()
87     */
88    var $options = array(
89        'result_buffering' => 500,
90        'persistent' => false,
91        'ssl' => false,
92        'debug' => 0,
93        'seqname_format' => '%s_seq',
94        'autofree' => false,
95        'portability' => DB_PORTABILITY_NONE,
96        'optimize' => 'performance',  // Deprecated.  Use 'portability'.
97    );
98
99    /**
100     * The parameters from the most recently executed query
101     * @var array
102     * @since Property available since Release 1.7.0
103     */
104    var $last_parameters = array();
105
106    /**
107     * The elements from each prepared statement
108     * @var array
109     */
110    var $prepare_tokens = array();
111
112    /**
113     * The data types of the various elements in each prepared statement
114     * @var array
115     */
116    var $prepare_types = array();
117
118    /**
119     * The prepared queries
120     * @var array
121     */
122    var $prepared_queries = array();
123
124
125    // }}}
126    // {{{ DB_common
127
128    /**
129     * This constructor calls <kbd>$this->PEAR('DB_Error')</kbd>
130     *
131     * @return void
132     */
133    function DB_common()
134    {
135        $this->PEAR('DB_Error');
136    }
137
138    // }}}
139    // {{{ __sleep()
140
141    /**
142     * Automatically indicates which properties should be saved
143     * when PHP's serialize() function is called
144     *
145     * @return array  the array of properties names that should be saved
146     */
147    function __sleep()
148    {
149        if ($this->connection) {
150            // Don't disconnect(), people use serialize() for many reasons
151            $this->was_connected = true;
152        } else {
153            $this->was_connected = false;
154        }
155        if (isset($this->autocommit)) {
156            return array('autocommit',
157                         'dbsyntax',
158                         'dsn',
159                         'features',
160                         'fetchmode',
161                         'fetchmode_object_class',
162                         'options',
163                         'was_connected',
164                   );
165        } else {
166            return array('dbsyntax',
167                         'dsn',
168                         'features',
169                         'fetchmode',
170                         'fetchmode_object_class',
171                         'options',
172                         'was_connected',
173                   );
174        }
175    }
176
177    // }}}
178    // {{{ __wakeup()
179
180    /**
181     * Automatically reconnects to the database when PHP's unserialize()
182     * function is called
183     *
184     * The reconnection attempt is only performed if the object was connected
185     * at the time PHP's serialize() function was run.
186     *
187     * @return void
188     */
189    function __wakeup()
190    {
191        if ($this->was_connected) {
192            $this->connect($this->dsn, $this->options);
193        }
194    }
195
196    // }}}
197    // {{{ __toString()
198
199    /**
200     * Automatic string conversion for PHP 5
201     *
202     * @return string  a string describing the current PEAR DB object
203     *
204     * @since Method available since Release 1.7.0
205     */
206    function __toString()
207    {
208        $info = strtolower(get_class($this));
209        $info .=  ': (phptype=' . $this->phptype .
210                  ', dbsyntax=' . $this->dbsyntax .
211                  ')';
212        if ($this->connection) {
213            $info .= ' [connected]';
214        }
215        return $info;
216    }
217
218    // }}}
219    // {{{ toString()
220
221    /**
222     * DEPRECATED:  String conversion method
223     *
224     * @return string  a string describing the current PEAR DB object
225     *
226     * @deprecated Method deprecated in Release 1.7.0
227     */
228    function toString()
229    {
230        return $this->__toString();
231    }
232
233    // }}}
234    // {{{ quoteString()
235
236    /**
237     * DEPRECATED: Quotes a string so it can be safely used within string
238     * delimiters in a query
239     *
240     * @param string $string  the string to be quoted
241     *
242     * @return string  the quoted string
243     *
244     * @see DB_common::quoteSmart(), DB_common::escapeSimple()
245     * @deprecated Method deprecated some time before Release 1.2
246     */
247    function quoteString($string)
248    {
249        $string = $this->quote($string);
250        if ($string{0} == "'") {
251            return substr($string, 1, -1);
252        }
253        return $string;
254    }
255
256    // }}}
257    // {{{ quote()
258
259    /**
260     * DEPRECATED: Quotes a string so it can be safely used in a query
261     *
262     * @param string $string  the string to quote
263     *
264     * @return string  the quoted string or the string <samp>NULL</samp>
265     *                  if the value submitted is <kbd>null</kbd>.
266     *
267     * @see DB_common::quoteSmart(), DB_common::escapeSimple()
268     * @deprecated Deprecated in release 1.6.0
269     */
270    function quote($string = null)
271    {
272        return ($string === null) ? 'NULL'
273                                  : "'" . str_replace("'", "''", $string) . "'";
274    }
275
276    // }}}
277    // {{{ quoteIdentifier()
278
279    /**
280     * Quotes a string so it can be safely used as a table or column name
281     *
282     * Delimiting style depends on which database driver is being used.
283     *
284     * NOTE: just because you CAN use delimited identifiers doesn't mean
285     * you SHOULD use them.  In general, they end up causing way more
286     * problems than they solve.
287     *
288     * Portability is broken by using the following characters inside
289     * delimited identifiers:
290     *   + backtick (<kbd>`</kbd>) -- due to MySQL
291     *   + double quote (<kbd>"</kbd>) -- due to Oracle
292     *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
293     *
294     * Delimited identifiers are known to generally work correctly under
295     * the following drivers:
296     *   + mssql
297     *   + mysql
298     *   + mysqli
299     *   + oci8
300     *   + odbc(access)
301     *   + odbc(db2)
302     *   + pgsql
303     *   + sqlite
304     *   + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime
305     *     prior to use)
306     *
307     * InterBase doesn't seem to be able to use delimited identifiers
308     * via PHP 4.  They work fine under PHP 5.
309     *
310     * @param string $str  the identifier name to be quoted
311     *
312     * @return string  the quoted identifier
313     *
314     * @since Method available since Release 1.6.0
315     */
316    function quoteIdentifier($str)
317    {
318        return '"' . str_replace('"', '""', $str) . '"';
319    }
320
321    // }}}
322    // {{{ quoteSmart()
323
324    /**
325     * Formats input so it can be safely used in a query
326     *
327     * The output depends on the PHP data type of input and the database
328     * type being used.
329     *
330     * @param mixed $in  the data to be formatted
331     *
332     * @return mixed  the formatted data.  The format depends on the input's
333     *                 PHP type:
334     * <ul>
335     *  <li>
336     *    <kbd>input</kbd> -> <samp>returns</samp>
337     *  </li>
338     *  <li>
339     *    <kbd>null</kbd> -> the string <samp>NULL</samp>
340     *  </li>
341     *  <li>
342     *    <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number
343     *  </li>
344     *  <li>
345     *    <kbd>bool</kbd> -> output depends on the driver in use
346     *    Most drivers return integers: <samp>1</samp> if
347     *    <kbd>true</kbd> or <samp>0</samp> if
348     *    <kbd>false</kbd>.
349     *    Some return strings: <samp>TRUE</samp> if
350     *    <kbd>true</kbd> or <samp>FALSE</samp> if
351     *    <kbd>false</kbd>.
352     *    Finally one returns strings: <samp>T</samp> if
353     *    <kbd>true</kbd> or <samp>F</samp> if
354     *    <kbd>false</kbd>. Here is a list of each DBMS,
355     *    the values returned and the suggested column type:
356     *    <ul>
357     *      <li>
358     *        <kbd>dbase</kbd> -> <samp>T/F</samp>
359     *        (<kbd>Logical</kbd>)
360     *      </li>
361     *      <li>
362     *        <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp>
363     *        (<kbd>BOOLEAN</kbd>)
364     *      </li>
365     *      <li>
366     *        <kbd>ibase</kbd> -> <samp>1/0</samp>
367     *        (<kbd>SMALLINT</kbd>) [1]
368     *      </li>
369     *      <li>
370     *        <kbd>ifx</kbd> -> <samp>1/0</samp>
371     *        (<kbd>SMALLINT</kbd>) [1]
372     *      </li>
373     *      <li>
374     *        <kbd>msql</kbd> -> <samp>1/0</samp>
375     *        (<kbd>INTEGER</kbd>)
376     *      </li>
377     *      <li>
378     *        <kbd>mssql</kbd> -> <samp>1/0</samp>
379     *        (<kbd>BIT</kbd>)
380     *      </li>
381     *      <li>
382     *        <kbd>mysql</kbd> -> <samp>1/0</samp>
383     *        (<kbd>TINYINT(1)</kbd>)
384     *      </li>
385     *      <li>
386     *        <kbd>mysqli</kbd> -> <samp>1/0</samp>
387     *        (<kbd>TINYINT(1)</kbd>)
388     *      </li>
389     *      <li>
390     *        <kbd>oci8</kbd> -> <samp>1/0</samp>
391     *        (<kbd>NUMBER(1)</kbd>)
392     *      </li>
393     *      <li>
394     *        <kbd>odbc</kbd> -> <samp>1/0</samp>
395     *        (<kbd>SMALLINT</kbd>) [1]
396     *      </li>
397     *      <li>
398     *        <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp>
399     *        (<kbd>BOOLEAN</kbd>)
400     *      </li>
401     *      <li>
402     *        <kbd>sqlite</kbd> -> <samp>1/0</samp>
403     *        (<kbd>INTEGER</kbd>)
404     *      </li>
405     *      <li>
406     *        <kbd>sybase</kbd> -> <samp>1/0</samp>
407     *        (<kbd>TINYINT(1)</kbd>)
408     *      </li>
409     *    </ul>
410     *    [1] Accommodate the lowest common denominator because not all
411     *    versions of have <kbd>BOOLEAN</kbd>.
412     *  </li>
413     *  <li>
414     *    other (including strings and numeric strings) ->
415     *    the data with single quotes escaped by preceeding
416     *    single quotes, backslashes are escaped by preceeding
417     *    backslashes, then the whole string is encapsulated
418     *    between single quotes
419     *  </li>
420     * </ul>
421     *
422     * @see DB_common::escapeSimple()
423     * @since Method available since Release 1.6.0
424     */
425    function quoteSmart($in)
426    {
427        if (is_int($in) || is_double($in)) {
428            return $in;
429        } elseif (is_bool($in)) {
430            return $in ? 1 : 0;
431        } elseif (is_null($in)) {
432            return 'NULL';
433        } else {
434            return "'" . $this->escapeSimple($in) . "'";
435        }
436    }
437
438    // }}}
439    // {{{ escapeSimple()
440
441    /**
442     * Escapes a string according to the current DBMS's standards
443     *
444     * In SQLite, this makes things safe for inserts/updates, but may
445     * cause problems when performing text comparisons against columns
446     * containing binary data. See the
447     * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
448     *
449     * @param string $str  the string to be escaped
450     *
451     * @return string  the escaped string
452     *
453     * @see DB_common::quoteSmart()
454     * @since Method available since Release 1.6.0
455     */
456    function escapeSimple($str)
457    {
458        return str_replace("'", "''", $str);
459    }
460
461    // }}}
462    // {{{ provides()
463
464    /**
465     * Tells whether the present driver supports a given feature
466     *
467     * @param string $feature  the feature you're curious about
468     *
469     * @return bool  whether this driver supports $feature
470     */
471    function provides($feature)
472    {
473        return $this->features[$feature];
474    }
475
476    // }}}
477    // {{{ setFetchMode()
478
479    /**
480     * Sets the fetch mode that should be used by default for query results
481     *
482     * @param integer $fetchmode    DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC
483     *                               or DB_FETCHMODE_OBJECT
484     * @param string $object_class  the class name of the object to be returned
485     *                               by the fetch methods when the
486     *                               DB_FETCHMODE_OBJECT mode is selected.
487     *                               If no class is specified by default a cast
488     *                               to object from the assoc array row will be
489     *                               done.  There is also the posibility to use
490     *                               and extend the 'DB_row' class.
491     *
492     * @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT
493     */
494    function setFetchMode($fetchmode, $object_class = 'stdClass')
495    {
496        switch ($fetchmode) {
497            case DB_FETCHMODE_OBJECT:
498                $this->fetchmode_object_class = $object_class;
499            case DB_FETCHMODE_ORDERED:
500            case DB_FETCHMODE_ASSOC:
501                $this->fetchmode = $fetchmode;
502                break;
503            default:
504                return $this->raiseError('invalid fetchmode mode');
505        }
506    }
507
508    // }}}
509    // {{{ setOption()
510
511    /**
512     * Sets run-time configuration options for PEAR DB
513     *
514     * Options, their data types, default values and description:
515     * <ul>
516     * <li>
517     * <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp>
518     *      <br />should results be freed automatically when there are no
519     *            more rows?
520     * </li><li>
521     * <var>result_buffering</var> <kbd>integer</kbd> = <samp>500</samp>
522     *      <br />how many rows of the result set should be buffered?
523     *      <br />In mysql: mysql_unbuffered_query() is used instead of
524     *            mysql_query() if this value is 0.  (Release 1.7.0)
525     *      <br />In oci8: this value is passed to ocisetprefetch().
526     *            (Release 1.7.0)
527     * </li><li>
528     * <var>debug</var> <kbd>integer</kbd> = <samp>0</samp>
529     *      <br />debug level
530     * </li><li>
531     * <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp>
532     *      <br />should the connection be persistent?
533     * </li><li>
534     * <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp>
535     *      <br />portability mode constant (see below)
536     * </li><li>
537     * <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp>
538     *      <br />the sprintf() format string used on sequence names.  This
539     *            format is applied to sequence names passed to
540     *            createSequence(), nextID() and dropSequence().
541     * </li><li>
542     * <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp>
543     *      <br />use ssl to connect?
544     * </li>
545     * </ul>
546     *
547     * -----------------------------------------
548     *
549     * PORTABILITY MODES
550     *
551     * These modes are bitwised, so they can be combined using <kbd>|</kbd>
552     * and removed using <kbd>^</kbd>.  See the examples section below on how
553     * to do this.
554     *
555     * <samp>DB_PORTABILITY_NONE</samp>
556     * turn off all portability features
557     *
558     * This mode gets automatically turned on if the deprecated
559     * <var>optimize</var> option gets set to <samp>performance</samp>.
560     *
561     *
562     * <samp>DB_PORTABILITY_LOWERCASE</samp>
563     * convert names of tables and fields to lower case when using
564     * <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd>
565     *
566     * This mode gets automatically turned on in the following databases
567     * if the deprecated option <var>optimize</var> gets set to
568     * <samp>portability</samp>:
569     * + oci8
570     *
571     *
572     * <samp>DB_PORTABILITY_RTRIM</samp>
573     * right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd>
574     *
575     *
576     * <samp>DB_PORTABILITY_DELETE_COUNT</samp>
577     * force reporting the number of rows deleted
578     *
579     * Some DBMS's don't count the number of rows deleted when performing
580     * simple <kbd>DELETE FROM tablename</kbd> queries.  This portability
581     * mode tricks such DBMS's into telling the count by adding
582     * <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries.
583     *
584     * This mode gets automatically turned on in the following databases
585     * if the deprecated option <var>optimize</var> gets set to
586     * <samp>portability</samp>:
587     * + fbsql
588     * + mysql
589     * + mysqli
590     * + sqlite
591     *
592     *
593     * <samp>DB_PORTABILITY_NUMROWS</samp>
594     * enable hack that makes <kbd>numRows()</kbd> work in Oracle
595     *
596     * This mode gets automatically turned on in the following databases
597     * if the deprecated option <var>optimize</var> gets set to
598     * <samp>portability</samp>:
599     * + oci8
600     *
601     *
602     * <samp>DB_PORTABILITY_ERRORS</samp>
603     * makes certain error messages in certain drivers compatible
604     * with those from other DBMS's
605     *
606     * + mysql, mysqli:  change unique/primary key constraints
607     *   DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT
608     *
609     * + odbc(access):  MS's ODBC driver reports 'no such field' as code
610     *   07001, which means 'too few parameters.'  When this option is on
611     *   that code gets mapped to DB_ERROR_NOSUCHFIELD.
612     *   DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD
613     *
614     * <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp>
615     * convert null values to empty strings in data output by get*() and
616     * fetch*().  Needed because Oracle considers empty strings to be null,
617     * while most other DBMS's know the difference between empty and null.
618     *
619     *
620     * <samp>DB_PORTABILITY_ALL</samp>
621     * turn on all portability features
622     *
623     * -----------------------------------------
624     *
625     * Example 1. Simple setOption() example
626     * <code>
627     * $db->setOption('autofree', true);
628     * </code>
629     *
630     * Example 2. Portability for lowercasing and trimming
631     * <code>
632     * $db->setOption('portability',
633     *                 DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM);
634     * </code>
635     *
636     * Example 3. All portability options except trimming
637     * <code>
638     * $db->setOption('portability',
639     *                 DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM);
640     * </code>
641     *
642     * @param string $option option name
643     * @param mixed  $value value for the option
644     *
645     * @return int  DB_OK on success.  A DB_Error object on failure.
646     *
647     * @see DB_common::$options
648     */
649    function setOption($option, $value)
650    {
651        if (isset($this->options[$option])) {
652            $this->options[$option] = $value;
653
654            /*
655             * Backwards compatibility check for the deprecated 'optimize'
656             * option.  Done here in case settings change after connecting.
657             */
658            if ($option == 'optimize') {
659                if ($value == 'portability') {
660                    switch ($this->phptype) {
661                        case 'oci8':
662                            $this->options['portability'] =
663                                    DB_PORTABILITY_LOWERCASE |
664                                    DB_PORTABILITY_NUMROWS;
665                            break;
666                        case 'fbsql':
667                        case 'mysql':
668                        case 'mysqli':
669                        case 'sqlite':
670                            $this->options['portability'] =
671                                    DB_PORTABILITY_DELETE_COUNT;
672                            break;
673                    }
674                } else {
675                    $this->options['portability'] = DB_PORTABILITY_NONE;
676                }
677            }
678
679            return DB_OK;
680        }
681        return $this->raiseError("unknown option $option");
682    }
683
684    // }}}
685    // {{{ getOption()
686
687    /**
688     * Returns the value of an option
689     *
690     * @param string $option  the option name you're curious about
691     *
692     * @return mixed  the option's value
693     */
694    function getOption($option)
695    {
696        if (isset($this->options[$option])) {
697            return $this->options[$option];
698        }
699        return $this->raiseError("unknown option $option");
700    }
701
702    // }}}
703    // {{{ prepare()
704
705    /**
706     * Prepares a query for multiple execution with execute()
707     *
708     * Creates a query that can be run multiple times.  Each time it is run,
709     * the placeholders, if any, will be replaced by the contents of
710     * execute()'s $data argument.
711     *
712     * Three types of placeholders can be used:
713     *   + <kbd>?</kbd>  scalar value (i.e. strings, integers).  The system
714     *                   will automatically quote and escape the data.
715     *   + <kbd>!</kbd>  value is inserted 'as is'
716     *   + <kbd>&</kbd>  requires a file name.  The file's contents get
717     *                   inserted into the query (i.e. saving binary
718     *                   data in a db)
719     *
720     * Example 1.
721     * <code>
722     * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
723     * $data = array(
724     *     "John's text",
725     *     "'it''s good'",
726     *     'filename.txt'
727     * );
728     * $res = $db->execute($sth, $data);
729     * </code>
730     *
731     * Use backslashes to escape placeholder characters if you don't want
732     * them to be interpreted as placeholders:
733     * <pre>
734     *    "UPDATE foo SET col=? WHERE col='over \& under'"
735     * </pre>
736     *
737     * With some database backends, this is emulated.
738     *
739     * {@internal ibase and oci8 have their own prepare() methods.}}
740     *
741     * @param string $query  the query to be prepared
742     *
743     * @return mixed  DB statement resource on success. A DB_Error object
744     *                 on failure.
745     *
746     * @see DB_common::execute()
747     */
748    function prepare($query)
749    {
750        $tokens   = preg_split('/((?<!\\\)[&?!])/', $query, -1,
751                               PREG_SPLIT_DELIM_CAPTURE);
752        $token     = 0;
753        $types     = array();
754        $newtokens = array();
755
756        foreach ($tokens as $val) {
757            switch ($val) {
758                case '?':
759                    $types[$token++] = DB_PARAM_SCALAR;
760                    break;
761                case '&':
762                    $types[$token++] = DB_PARAM_OPAQUE;
763                    break;
764                case '!':
765                    $types[$token++] = DB_PARAM_MISC;
766                    break;
767                default:
768                    $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val);
769            }
770        }
771
772        $this->prepare_tokens[] = &$newtokens;
773        end($this->prepare_tokens);
774
775        $k = key($this->prepare_tokens);
776        $this->prepare_types[$k] = $types;
777        $this->prepared_queries[$k] = implode(' ', $newtokens);
778
779        return $k;
780    }
781
782    // }}}
783    // {{{ autoPrepare()
784
785    /**
786     * Automaticaly generates an insert or update query and pass it to prepare()
787     *
788     * @param string $table         the table name
789     * @param array  $table_fields  the array of field names
790     * @param int    $mode          a type of query to make:
791     *                               DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
792     * @param string $where         for update queries: the WHERE clause to
793     *                               append to the SQL statement.  Don't
794     *                               include the "WHERE" keyword.
795     *
796     * @return resource  the query handle
797     *
798     * @uses DB_common::prepare(), DB_common::buildManipSQL()
799     */
800    function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT,
801                         $where = false)
802    {
803        $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
804        if (DB::isError($query)) {
805            return $query;
806        }
807        return $this->prepare($query);
808    }
809
810    // }}}
811    // {{{ autoExecute()
812
813    /**
814     * Automaticaly generates an insert or update query and call prepare()
815     * and execute() with it
816     *
817     * @param string $table         the table name
818     * @param array  $fields_values the associative array where $key is a
819     *                               field name and $value its value
820     * @param int    $mode          a type of query to make:
821     *                               DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
822     * @param string $where         for update queries: the WHERE clause to
823     *                               append to the SQL statement.  Don't
824     *                               include the "WHERE" keyword.
825     *
826     * @return mixed  a new DB_result object for successful SELECT queries
827     *                 or DB_OK for successul data manipulation queries.
828     *                 A DB_Error object on failure.
829     *
830     * @uses DB_common::autoPrepare(), DB_common::execute()
831     */
832    function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT,
833                         $where = false)
834    {
835        $sth = $this->autoPrepare($table, array_keys($fields_values), $mode,
836                                  $where);
837        if (DB::isError($sth)) {
838            return $sth;
839        }
840        $ret =& $this->execute($sth, array_values($fields_values));
841        $this->freePrepared($sth);
842        return $ret;
843
844    }
845
846    // }}}
847    // {{{ buildManipSQL()
848
849    /**
850     * Produces an SQL query string for autoPrepare()
851     *
852     * Example:
853     * <pre>
854     * buildManipSQL('table_sql', array('field1', 'field2', 'field3'),
855     *               DB_AUTOQUERY_INSERT);
856     * </pre>
857     *
858     * That returns
859     * <samp>
860     * INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?)
861     * </samp>
862     *
863     * NOTES:
864     *   - This belongs more to a SQL Builder class, but this is a simple
865     *     facility.
866     *   - Be carefull! If you don't give a $where param with an UPDATE
867     *     query, all the records of the table will be updated!
868     *
869     * @param string $table         the table name
870     * @param array  $table_fields  the array of field names
871     * @param int    $mode          a type of query to make:
872     *                               DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
873     * @param string $where         for update queries: the WHERE clause to
874     *                               append to the SQL statement.  Don't
875     *                               include the "WHERE" keyword.
876     *
877     * @return string  the sql query for autoPrepare()
878     */
879    function buildManipSQL($table, $table_fields, $mode, $where = false)
880    {
881        if (count($table_fields) == 0) {
882            return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
883        }
884        $first = true;
885        switch ($mode) {
886            case DB_AUTOQUERY_INSERT:
887                $values = '';
888                $names = '';
889                foreach ($table_fields as $value) {
890                    if ($first) {
891                        $first = false;
892                    } else {
893                        $names .= ',';
894                        $values .= ',';
895                    }
896                    $names .= $value;
897                    $values .= '?';
898                }
899                return "INSERT INTO $table ($names) VALUES ($values)";
900            case DB_AUTOQUERY_UPDATE:
901                $set = '';
902                foreach ($table_fields as $value) {
903                    if ($first) {
904                        $first = false;
905                    } else {
906                        $set .= ',';
907                    }
908                    $set .= "$value = ?";
909                }
910                $sql = "UPDATE $table SET $set";
911                if ($where) {
912                    $sql .= " WHERE $where";
913                }
914                return $sql;
915            default:
916                return $this->raiseError(DB_ERROR_SYNTAX);
917        }
918    }
919
920    // }}}
921    // {{{ execute()
922
923    /**
924     * Executes a DB statement prepared with prepare()
925     *
926     * Example 1.
927     * <code>
928     * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
929     * $data = array(
930     *     "John's text",
931     *     "'it''s good'",
932     *     'filename.txt'
933     * );
934     * $res =& $db->execute($sth, $data);
935     * </code>
936     *
937     * @param resource $stmt  a DB statement resource returned from prepare()
938     * @param mixed    $data  array, string or numeric data to be used in
939     *                         execution of the statement.  Quantity of items
940     *                         passed must match quantity of placeholders in
941     *                         query:  meaning 1 placeholder for non-array
942     *                         parameters or 1 placeholder per array element.
943     *
944     * @return mixed  a new DB_result object for successful SELECT queries
945     *                 or DB_OK for successul data manipulation queries.
946     *                 A DB_Error object on failure.
947     *
948     * {@internal ibase and oci8 have their own execute() methods.}}
949     *
950     * @see DB_common::prepare()
951     */
952    function &execute($stmt, $data = array())
953    {
954        $realquery = $this->executeEmulateQuery($stmt, $data);
955        if (DB::isError($realquery)) {
956            return $realquery;
957        }
958        $result = $this->simpleQuery($realquery);
959
960        if ($result === DB_OK || DB::isError($result)) {
961            return $result;
962        } else {
963            $tmp =& new DB_result($this, $result);
964            return $tmp;
965        }
966    }
967
968    // }}}
969    // {{{ executeEmulateQuery()
970
971    /**
972     * Emulates executing prepared statements if the DBMS not support them
973     *
974     * @param resource $stmt  a DB statement resource returned from execute()
975     * @param mixed    $data  array, string or numeric data to be used in
976     *                         execution of the statement.  Quantity of items
977     *                         passed must match quantity of placeholders in
978     *                         query:  meaning 1 placeholder for non-array
979     *                         parameters or 1 placeholder per array element.
980     *
981     * @return mixed  a string containing the real query run when emulating
982     *                 prepare/execute.  A DB_Error object on failure.
983     *
984     * @access protected
985     * @see DB_common::execute()
986     */
987    function executeEmulateQuery($stmt, $data = array())
988    {
989        $stmt = (int)$stmt;
990        $data = (array)$data;
991        $this->last_parameters = $data;
992
993        if (count($this->prepare_types[$stmt]) != count($data)) {
994            $this->last_query = $this->prepared_queries[$stmt];
995            return $this->raiseError(DB_ERROR_MISMATCH);
996        }
997
998        $realquery = $this->prepare_tokens[$stmt][0];
999
1000        $i = 0;
1001        foreach ($data as $value) {
1002            if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) {
1003                $realquery .= $this->quoteSmart($value);
1004            } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) {
1005                $fp = @fopen($value, 'rb');
1006                if (!$fp) {
1007                    return $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
1008                }
1009                $realquery .= $this->quoteSmart(fread($fp, filesize($value)));
1010                fclose($fp);
1011            } else {
1012                $realquery .= $value;
1013            }
1014
1015            $realquery .= $this->prepare_tokens[$stmt][++$i];
1016        }
1017
1018        return $realquery;
1019    }
1020
1021    // }}}
1022    // {{{ executeMultiple()
1023
1024    /**
1025     * Performs several execute() calls on the same statement handle
1026     *
1027     * $data must be an array indexed numerically
1028     * from 0, one execute call is done for every "row" in the array.
1029     *
1030     * If an error occurs during execute(), executeMultiple() does not
1031     * execute the unfinished rows, but rather returns that error.
1032     *
1033     * @param resource $stmt  query handle from prepare()
1034     * @param array    $data  numeric array containing the
1035     *                         data to insert into the query
1036     *
1037     * @return int  DB_OK on success.  A DB_Error object on failure.
1038     *
1039     * @see DB_common::prepare(), DB_common::execute()
1040     */
1041    function executeMultiple($stmt, $data)
1042    {
1043        foreach ($data as $value) {
1044            $res =& $this->execute($stmt, $value);
1045            if (DB::isError($res)) {
1046                return $res;
1047            }
1048        }
1049        return DB_OK;
1050    }
1051
1052    // }}}
1053    // {{{ freePrepared()
1054
1055    /**
1056     * Frees the internal resources associated with a prepared query
1057     *
1058     * @param resource $stmt           the prepared statement's PHP resource
1059     * @param bool     $free_resource  should the PHP resource be freed too?
1060     *                                  Use false if you need to get data
1061     *                                  from the result set later.
1062     *
1063     * @return bool  TRUE on success, FALSE if $result is invalid
1064     *
1065     * @see DB_common::prepare()
1066     */
1067    function freePrepared($stmt, $free_resource = true)
1068    {
1069        $stmt = (int)$stmt;
1070        if (isset($this->prepare_tokens[$stmt])) {
1071            unset($this->prepare_tokens[$stmt]);
1072            unset($this->prepare_types[$stmt]);
1073            unset($this->prepared_queries[$stmt]);
1074            return true;
1075        }
1076        return false;
1077    }
1078
1079    // }}}
1080    // {{{ modifyQuery()
1081
1082    /**
1083     * Changes a query string for various DBMS specific reasons
1084     *
1085     * It is defined here to ensure all drivers have this method available.
1086     *
1087     * @param string $query  the query string to modify
1088     *
1089     * @return string  the modified query string
1090     *
1091     * @access protected
1092     * @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(),
1093     *      DB_sqlite::modifyQuery()
1094     */
1095    function modifyQuery($query)
1096    {
1097        return $query;
1098    }
1099
1100    // }}}
1101    // {{{ modifyLimitQuery()
1102
1103    /**
1104     * Adds LIMIT clauses to a query string according to current DBMS standards
1105     *
1106     * It is defined here to assure that all implementations
1107     * have this method defined.
1108     *
1109     * @param string $query   the query to modify
1110     * @param int    $from    the row to start to fetching (0 = the first row)
1111     * @param int    $count   the numbers of rows to fetch
1112     * @param mixed  $params  array, string or numeric data to be used in
1113     *                         execution of the statement.  Quantity of items
1114     *                         passed must match quantity of placeholders in
1115     *                         query:  meaning 1 placeholder for non-array
1116     *                         parameters or 1 placeholder per array element.
1117     *
1118     * @return string  the query string with LIMIT clauses added
1119     *
1120     * @access protected
1121     */
1122    function modifyLimitQuery($query, $from, $count, $params = array())
1123    {
1124        return $query;
1125    }
1126
1127    // }}}
1128    // {{{ query()
1129
1130    /**
1131     * Sends a query to the database server
1132     *
1133     * The query string can be either a normal statement to be sent directly
1134     * to the server OR if <var>$params</var> are passed the query can have
1135     * placeholders and it will be passed through prepare() and execute().
1136     *
1137     * @param string $query   the SQL query or the statement to prepare
1138     * @param mixed  $params  array, string or numeric data to be used in
1139     *                         execution of the statement.  Quantity of items
1140     *                         passed must match quantity of placeholders in
1141     *                         query:  meaning 1 placeholder for non-array
1142     *                         parameters or 1 placeholder per array element.
1143     *
1144     * @return mixed  a new DB_result object for successful SELECT queries
1145     *                 or DB_OK for successul data manipulation queries.
1146     *                 A DB_Error object on failure.
1147     *
1148     * @see DB_result, DB_common::prepare(), DB_common::execute()
1149     */
1150    function &query($query, $params = array())
1151    {
1152        if (sizeof($params) > 0) {
1153            $sth = $this->prepare($query);
1154            if (DB::isError($sth)) {
1155                return $sth;
1156            }
1157            $ret =& $this->execute($sth, $params);
1158            $this->freePrepared($sth, false);
1159            return $ret;
1160        } else {
1161            $this->last_parameters = array();
1162            $result = $this->simpleQuery($query);
1163            if ($result === DB_OK || DB::isError($result)) {
1164                return $result;
1165            } else {
1166                $tmp =& new DB_result($this, $result);
1167                return $tmp;
1168            }
1169        }
1170    }
1171
1172    // }}}
1173    // {{{ limitQuery()
1174
1175    /**
1176     * Generates and executes a LIMIT query
1177     *
1178     * @param string $query   the query
1179     * @param intr   $from    the row to start to fetching (0 = the first row)
1180     * @param int    $count   the numbers of rows to fetch
1181     * @param mixed  $params  array, string or numeric data to be used in
1182     *                         execution of the statement.  Quantity of items
1183     *                         passed must match quantity of placeholders in
1184     *                         query:  meaning 1 placeholder for non-array
1185     *                         parameters or 1 placeholder per array element.
1186     *
1187     * @return mixed  a new DB_result object for successful SELECT queries
1188     *                 or DB_OK for successul data manipulation queries.
1189     *                 A DB_Error object on failure.
1190     */
1191    function &limitQuery($query, $from, $count, $params = array())
1192    {
1193        $query = $this->modifyLimitQuery($query, $from, $count, $params);
1194        if (DB::isError($query)){
1195            return $query;
1196        }
1197        $result =& $this->query($query, $params);
1198        if (is_a($result, 'DB_result')) {
1199            $result->setOption('limit_from', $from);
1200            $result->setOption('limit_count', $count);
1201        }
1202        return $result;
1203    }
1204
1205    // }}}
1206    // {{{ getOne()
1207
1208    /**
1209     * Fetches the first column of the first row from a query result
1210     *
1211     * Takes care of doing the query and freeing the results when finished.
1212     *
1213     * @param string $query   the SQL query
1214     * @param mixed  $params  array, string or numeric data to be used in
1215     *                         execution of the statement.  Quantity of items
1216     *                         passed must match quantity of placeholders in
1217     *                         query:  meaning 1 placeholder for non-array
1218     *                         parameters or 1 placeholder per array element.
1219     *
1220     * @return mixed  the returned value of the query.
1221     *                 A DB_Error object on failure.
1222     */
1223    function &getOne($query, $params = array())
1224    {
1225        $params = (array)$params;
1226        // modifyLimitQuery() would be nice here, but it causes BC issues
1227        if (sizeof($params) > 0) {
1228            $sth = $this->prepare($query);
1229            if (DB::isError($sth)) {
1230                return $sth;
1231            }
1232            $res =& $this->execute($sth, $params);
1233            $this->freePrepared($sth);
1234        } else {
1235            $res =& $this->query($query);
1236        }
1237
1238        if (DB::isError($res)) {
1239            return $res;
1240        }
1241
1242        $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED);
1243        $res->free();
1244
1245        if ($err !== DB_OK) {
1246            return $err;
1247        }
1248
1249        return $row[0];
1250    }
1251
1252    // }}}
1253    // {{{ getRow()
1254
1255    /**
1256     * Fetches the first row of data returned from a query result
1257     *
1258     * Takes care of doing the query and freeing the results when finished.
1259     *
1260     * @param string $query   the SQL query
1261     * @param mixed  $params  array, string or numeric data to be used in
1262     *                         execution of the statement.  Quantity of items
1263     *                         passed must match quantity of placeholders in
1264     *                         query:  meaning 1 placeholder for non-array
1265     *                         parameters or 1 placeholder per array element.
1266     * @param int $fetchmode  the fetch mode to use
1267     *
1268     * @return array  the first row of results as an array.
1269     *                 A DB_Error object on failure.
1270     */
1271    function &getRow($query, $params = array(),
1272                     $fetchmode = DB_FETCHMODE_DEFAULT)
1273    {
1274        // compat check, the params and fetchmode parameters used to
1275        // have the opposite order
1276        if (!is_array($params)) {
1277            if (is_array($fetchmode)) {
1278                if ($params === null) {
1279                    $tmp = DB_FETCHMODE_DEFAULT;
1280                } else {
1281                    $tmp = $params;
1282                }
1283                $params = $fetchmode;
1284                $fetchmode = $tmp;
1285            } elseif ($params !== null) {
1286                $fetchmode = $params;
1287                $params = array();
1288            }
1289        }
1290        // modifyLimitQuery() would be nice here, but it causes BC issues
1291        if (sizeof($params) > 0) {
1292            $sth = $this->prepare($query);
1293            if (DB::isError($sth)) {
1294                return $sth;
1295            }
1296            $res =& $this->execute($sth, $params);
1297            $this->freePrepared($sth);
1298        } else {
1299            $res =& $this->query($query);
1300        }
1301
1302        if (DB::isError($res)) {
1303            return $res;
1304        }
1305
1306        $err = $res->fetchInto($row, $fetchmode);
1307
1308        $res->free();
1309
1310        if ($err !== DB_OK) {
1311            return $err;
1312        }
1313
1314        return $row;
1315    }
1316
1317    // }}}
1318    // {{{ getCol()
1319
1320    /**
1321     * Fetches a single column from a query result and returns it as an
1322     * indexed array
1323     *
1324     * @param string $query   the SQL query
1325     * @param mixed  $col     which column to return (integer [column number,
1326     *                         starting at 0] or string [column name])
1327     * @param mixed  $params  array, string or numeric data to be used in
1328     *                         execution of the statement.  Quantity of items
1329     *                         passed must match quantity of placeholders in
1330     *                         query:  meaning 1 placeholder for non-array
1331     *                         parameters or 1 placeholder per array element.
1332     *
1333     * @return array  the results as an array.  A DB_Error object on failure.
1334     *
1335     * @see DB_common::query()
1336     */
1337    function &getCol($query, $col = 0, $params = array())
1338    {
1339        $params = (array)$params;
1340        if (sizeof($params) > 0) {
1341            $sth = $this->prepare($query);
1342
1343            if (DB::isError($sth)) {
1344                return $sth;
1345            }
1346
1347            $res =& $this->execute($sth, $params);
1348            $this->freePrepared($sth);
1349        } else {
1350            $res =& $this->query($query);
1351        }
1352
1353        if (DB::isError($res)) {
1354            return $res;
1355        }
1356
1357        $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
1358
1359        if (!is_array($row = $res->fetchRow($fetchmode))) {
1360            $ret = array();
1361        } else {
1362            if (!array_key_exists($col, $row)) {
1363                $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD);
1364            } else {
1365                $ret = array($row[$col]);
1366                while (is_array($row = $res->fetchRow($fetchmode))) {
1367                    $ret[] = $row[$col];
1368                }
1369            }
1370        }
1371
1372        $res->free();
1373
1374        if (DB::isError($row)) {
1375            $ret = $row;
1376        }
1377
1378        return $ret;
1379    }
1380
1381    // }}}
1382    // {{{ getAssoc()
1383
1384    /**
1385     * Fetches an entire query result and returns it as an
1386     * associative array using the first column as the key
1387     *
1388     * If the result set contains more than two columns, the value
1389     * will be an array of the values from column 2-n.  If the result
1390     * set contains only two columns, the returned value will be a
1391     * scalar with the value of the second column (unless forced to an
1392     * array with the $force_array parameter).  A DB error code is
1393     * returned on errors.  If the result set contains fewer than two
1394     * columns, a DB_ERROR_TRUNCATED error is returned.
1395     *
1396     * For example, if the table "mytable" contains:
1397     *
1398     * <pre>
1399     *  ID      TEXT       DATE
1400     * --------------------------------
1401     *  1       'one'      944679408
1402     *  2       'two'      944679408
1403     *  3       'three'    944679408
1404     * </pre>
1405     *
1406     * Then the call getAssoc('SELECT id,text FROM mytable') returns:
1407     * <pre>
1408     *   array(
1409     *     '1' => 'one',
1410     *     '2' => 'two',
1411     *     '3' => 'three',
1412     *   )
1413     * </pre>
1414     *
1415     * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
1416     * <pre>
1417     *   array(
1418     *     '1' => array('one', '944679408'),
1419     *     '2' => array('two', '944679408'),
1420     *     '3' => array('three', '944679408')
1421     *   )
1422     * </pre>
1423     *
1424     * If the more than one row occurs with the same value in the
1425     * first column, the last row overwrites all previous ones by
1426     * default.  Use the $group parameter if you don't want to
1427     * overwrite like this.  Example:
1428     *
1429     * <pre>
1430     * getAssoc('SELECT category,id,name FROM mytable', false, null,
1431     *          DB_FETCHMODE_ASSOC, true) returns:
1432     *
1433     *   array(
1434     *     '1' => array(array('id' => '4', 'name' => 'number four'),
1435     *                  array('id' => '6', 'name' => 'number six')
1436     *            ),
1437     *     '9' => array(array('id' => '4', 'name' => 'number four'),
1438     *                  array('id' => '6', 'name' => 'number six')
1439     *            )
1440     *   )
1441     * </pre>
1442     *
1443     * Keep in mind that database functions in PHP usually return string
1444     * values for results regardless of the database's internal type.
1445     *
1446     * @param string $query        the SQL query
1447     * @param bool   $force_array  used only when the query returns
1448     *                              exactly two columns.  If true, the values
1449     *                              of the returned array will be one-element
1450     *                              arrays instead of scalars.
1451     * @param mixed  $params       array, string or numeric data to be used in
1452     *                              execution of the statement.  Quantity of
1453     *                              items passed must match quantity of
1454     *                              placeholders in query:  meaning 1
1455     *                              placeholder for non-array parameters or
1456     *                              1 placeholder per array element.
1457     * @param int   $fetchmode     the fetch mode to use
1458     * @param bool  $group         if true, the values of the returned array
1459     *                              is wrapped in another array.  If the same
1460     *                              key value (in the first column) repeats
1461     *                              itself, the values will be appended to
1462     *                              this array instead of overwriting the
1463     *                              existing values.
1464     *
1465     * @return array  the associative array containing the query results.
1466     *                A DB_Error object on failure.
1467     */
1468    function &getAssoc($query, $force_array = false, $params = array(),
1469                       $fetchmode = DB_FETCHMODE_DEFAULT, $group = false)
1470    {
1471        $params = (array)$params;
1472        if (sizeof($params) > 0) {
1473            $sth = $this->prepare($query);
1474
1475            if (DB::isError($sth)) {
1476                return $sth;
1477            }
1478
1479            $res =& $this->execute($sth, $params);
1480            $this->freePrepared($sth);
1481        } else {
1482            $res =& $this->query($query);
1483        }
1484
1485        if (DB::isError($res)) {
1486            return $res;
1487        }
1488        if ($fetchmode == DB_FETCHMODE_DEFAULT) {
1489            $fetchmode = $this->fetchmode;
1490        }
1491        $cols = $res->numCols();
1492
1493        if ($cols < 2) {
1494            $tmp =& $this->raiseError(DB_ERROR_TRUNCATED);
1495            return $tmp;
1496        }
1497
1498        $results = array();
1499
1500        if ($cols > 2 || $force_array) {
1501            // return array values
1502            // XXX this part can be optimized
1503            if ($fetchmode == DB_FETCHMODE_ASSOC) {
1504                while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) {
1505                    reset($row);
1506                    $key = current($row);
1507                    unset($row[key($row)]);
1508                    if ($group) {
1509                        $results[$key][] = $row;
1510                    } else {
1511                        $results[$key] = $row;
1512                    }
1513                }
1514            } elseif ($fetchmode == DB_FETCHMODE_OBJECT) {
1515                while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) {
1516                    $arr = get_object_vars($row);
1517                    $key = current($arr);
1518                    if ($group) {
1519                        $results[$key][] = $row;
1520                    } else {
1521                        $results[$key] = $row;
1522                    }
1523                }
1524            } else {
1525                while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
1526                    // we shift away the first element to get
1527                    // indices running from 0 again
1528                    $key = array_shift($row);
1529                    if ($group) {
1530                        $results[$key][] = $row;
1531                    } else {
1532                        $results[$key] = $row;
1533                    }
1534                }
1535            }
1536            if (DB::isError($row)) {
1537                $results = $row;
1538            }
1539        } else {
1540            // return scalar values
1541            while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) {
1542                if ($group) {
1543                    $results[$row[0]][] = $row[1];
1544                } else {
1545                    $results[$row[0]] = $row[1];
1546                }
1547            }
1548            if (DB::isError($row)) {
1549                $results = $row;
1550            }
1551        }
1552
1553        $res->free();
1554
1555        return $results;
1556    }
1557
1558    // }}}
1559    // {{{ getAll()
1560
1561    /**
1562     * Fetches all of the rows from a query result
1563     *
1564     * @param string $query      the SQL query
1565     * @param mixed  $params     array, string or numeric data to be used in
1566     *                            execution of the statement.  Quantity of
1567     *                            items passed must match quantity of
1568     *                            placeholders in query:  meaning 1
1569     *                            placeholder for non-array parameters or
1570     *                            1 placeholder per array element.
1571     * @param int    $fetchmode  the fetch mode to use:
1572     *                            + DB_FETCHMODE_ORDERED
1573     *                            + DB_FETCHMODE_ASSOC
1574     *                            + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED
1575     *                            + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED
1576     *
1577     * @return array  the nested array.  A DB_Error object on failure.
1578     */
1579    function &getAll($query, $params = array(),
1580                     $fetchmode = DB_FETCHMODE_DEFAULT)
1581    {
1582        // compat check, the params and fetchmode parameters used to
1583        // have the opposite order
1584        if (!is_array($params)) {
1585            if (is_array($fetchmode)) {
1586                if ($params === null) {
1587                    $tmp = DB_FETCHMODE_DEFAULT;
1588                } else {
1589                    $tmp = $params;
1590                }
1591                $params = $fetchmode;
1592                $fetchmode = $tmp;
1593            } elseif ($params !== null) {
1594                $fetchmode = $params;
1595                $params = array();
1596            }
1597        }
1598
1599        if (sizeof($params) > 0) {
1600            $sth = $this->prepare($query);
1601
1602            if (DB::isError($sth)) {
1603                return $sth;
1604            }
1605
1606            $res =& $this->execute($sth, $params);
1607            $this->freePrepared($sth);
1608        } else {
1609            $res =& $this->query($query);
1610        }
1611
1612        if ($res === DB_OK || DB::isError($res)) {
1613            return $res;
1614        }
1615
1616        $results = array();
1617        while (DB_OK === $res->fetchInto($row, $fetchmode)) {
1618            if ($fetchmode & DB_FETCHMODE_FLIPPED) {
1619                foreach ($row as $key => $val) {
1620                    $results[$key][] = $val;
1621                }
1622            } else {
1623                $results[] = $row;
1624            }
1625        }
1626
1627        $res->free();
1628
1629        if (DB::isError($row)) {
1630            $tmp =& $this->raiseError($row);
1631            return $tmp;
1632        }
1633        return $results;
1634    }
1635
1636    // }}}
1637    // {{{ autoCommit()
1638
1639    /**
1640     * Enables or disables automatic commits
1641     *
1642     * @param bool $onoff  true turns it on, false turns it off
1643     *
1644     * @return int  DB_OK on success.  A DB_Error object if the driver
1645     *               doesn't support auto-committing transactions.
1646     */
1647    function autoCommit($onoff = false)
1648    {
1649        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1650    }
1651
1652    // }}}
1653    // {{{ commit()
1654
1655    /**
1656     * Commits the current transaction
1657     *
1658     * @return int  DB_OK on success.  A DB_Error object on failure.
1659     */
1660    function commit()
1661    {
1662        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1663    }
1664
1665    // }}}
1666    // {{{ rollback()
1667
1668    /**
1669     * Reverts the current transaction
1670     *
1671     * @return int  DB_OK on success.  A DB_Error object on failure.
1672     */
1673    function rollback()
1674    {
1675        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1676    }
1677
1678    // }}}
1679    // {{{ numRows()
1680
1681    /**
1682     * Determines the number of rows in a query result
1683     *
1684     * @param resource $result  the query result idenifier produced by PHP
1685     *
1686     * @return int  the number of rows.  A DB_Error object on failure.
1687     */
1688    function numRows($result)
1689    {
1690        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1691    }
1692
1693    // }}}
1694    // {{{ affectedRows()
1695
1696    /**
1697     * Determines the number of rows affected by a data maniuplation query
1698     *
1699     * 0 is returned for queries that don't manipulate data.
1700     *
1701     * @return int  the number of rows.  A DB_Error object on failure.
1702     */
1703    function affectedRows()
1704    {
1705        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1706    }
1707
1708    // }}}
1709    // {{{ getSequenceName()
1710
1711    /**
1712     * Generates the name used inside the database for a sequence
1713     *
1714     * The createSequence() docblock contains notes about storing sequence
1715     * names.
1716     *
1717     * @param string $sqn  the sequence's public name
1718     *
1719     * @return string  the sequence's name in the backend
1720     *
1721     * @access protected
1722     * @see DB_common::createSequence(), DB_common::dropSequence(),
1723     *      DB_common::nextID(), DB_common::setOption()
1724     */
1725    function getSequenceName($sqn)
1726    {
1727        return sprintf($this->getOption('seqname_format'),
1728                       preg_replace('/[^a-z0-9_.]/i', '_', $sqn));
1729    }
1730
1731    // }}}
1732    // {{{ nextId()
1733
1734    /**
1735     * Returns the next free id in a sequence
1736     *
1737     * @param string  $seq_name  name of the sequence
1738     * @param boolean $ondemand  when true, the seqence is automatically
1739     *                            created if it does not exist
1740     *
1741     * @return int  the next id number in the sequence.
1742     *               A DB_Error object on failure.
1743     *
1744     * @see DB_common::createSequence(), DB_common::dropSequence(),
1745     *      DB_common::getSequenceName()
1746     */
1747    function nextId($seq_name, $ondemand = true)
1748    {
1749        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1750    }
1751
1752    // }}}
1753    // {{{ createSequence()
1754
1755    /**
1756     * Creates a new sequence
1757     *
1758     * The name of a given sequence is determined by passing the string
1759     * provided in the <var>$seq_name</var> argument through PHP's sprintf()
1760     * function using the value from the <var>seqname_format</var> option as
1761     * the sprintf()'s format argument.
1762     *
1763     * <var>seqname_format</var> is set via setOption().
1764     *
1765     * @param string $seq_name  name of the new sequence
1766     *
1767     * @return int  DB_OK on success.  A DB_Error object on failure.
1768     *
1769     * @see DB_common::dropSequence(), DB_common::getSequenceName(),
1770     *      DB_common::nextID()
1771     */
1772    function createSequence($seq_name)
1773    {
1774        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1775    }
1776
1777    // }}}
1778    // {{{ dropSequence()
1779
1780    /**
1781     * Deletes a sequence
1782     *
1783     * @param string $seq_name  name of the sequence to be deleted
1784     *
1785     * @return int  DB_OK on success.  A DB_Error object on failure.
1786     *
1787     * @see DB_common::createSequence(), DB_common::getSequenceName(),
1788     *      DB_common::nextID()
1789     */
1790    function dropSequence($seq_name)
1791    {
1792        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1793    }
1794
1795    // }}}
1796    // {{{ raiseError()
1797
1798    /**
1799     * Communicates an error and invoke error callbacks, etc
1800     *
1801     * Basically a wrapper for PEAR::raiseError without the message string.
1802     *
1803     * @param mixed   integer error code, or a PEAR error object (all
1804     *                 other parameters are ignored if this parameter is
1805     *                 an object
1806     * @param int     error mode, see PEAR_Error docs
1807     * @param mixed   if error mode is PEAR_ERROR_TRIGGER, this is the
1808     *                 error level (E_USER_NOTICE etc).  If error mode is
1809     *                 PEAR_ERROR_CALLBACK, this is the callback function,
1810     *                 either as a function name, or as an array of an
1811     *                 object and method name.  For other error modes this
1812     *                 parameter is ignored.
1813     * @param string  extra debug information.  Defaults to the last
1814     *                 query and native error code.
1815     * @param mixed   native error code, integer or string depending the
1816     *                 backend
1817     *
1818     * @return object  the PEAR_Error object
1819     *
1820     * @see PEAR_Error
1821     */
1822    function &raiseError($code = DB_ERROR, $mode = null, $options = null,
1823                         $userinfo = null, $nativecode = null)
1824    {
1825        // The error is yet a DB error object
1826        if (is_object($code)) {
1827            // because we the static PEAR::raiseError, our global
1828            // handler should be used if it is set
1829            if ($mode === null && !empty($this->_default_error_mode)) {
1830                $mode    = $this->_default_error_mode;
1831                $options = $this->_default_error_options;
1832            }
1833            $tmp = PEAR::raiseError($code, null, $mode, $options,
1834                                    null, null, true);
1835            return $tmp;
1836        }
1837
1838        if ($userinfo === null) {
1839            $userinfo = $this->last_query;
1840        }
1841
1842        if ($nativecode) {
1843            $userinfo .= ' [nativecode=' . trim($nativecode) . ']';
1844        } else {
1845            $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']';
1846        }
1847
1848        $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo,
1849                                'DB_Error', true);
1850        return $tmp;
1851    }
1852
1853    // }}}
1854    // {{{ errorNative()
1855
1856    /**
1857     * Gets the DBMS' native error code produced by the last query
1858     *
1859     * @return mixed  the DBMS' error code.  A DB_Error object on failure.
1860     */
1861    function errorNative()
1862    {
1863        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
1864    }
1865
1866    // }}}
1867    // {{{ errorCode()
1868
1869    /**
1870     * Maps native error codes to DB's portable ones
1871     *
1872     * Uses the <var>$errorcode_map</var> property defined in each driver.
1873     *
1874     * @param string|int $nativecode  the error code returned by the DBMS
1875     *
1876     * @return int  the portable DB error code.  Return DB_ERROR if the
1877     *               current driver doesn't have a mapping for the
1878     *               $nativecode submitted.
1879     */
1880    function errorCode($nativecode)
1881    {
1882        if (isset($this->errorcode_map[$nativecode])) {
1883            return $this->errorcode_map[$nativecode];
1884        }
1885        // Fall back to DB_ERROR if there was no mapping.
1886        return DB_ERROR;
1887    }
1888
1889    // }}}
1890    // {{{ errorMessage()
1891
1892    /**
1893     * Maps a DB error code to a textual message
1894     *
1895     * @param integer $dbcode  the DB error code
1896     *
1897     * @return string  the error message corresponding to the error code
1898     *                  submitted.  FALSE if the error code is unknown.
1899     *
1900     * @see DB::errorMessage()
1901     */
1902    function errorMessage($dbcode)
1903    {
1904        return DB::errorMessage($this->errorcode_map[$dbcode]);
1905    }
1906
1907    // }}}
1908    // {{{ tableInfo()
1909
1910    /**
1911     * Returns information about a table or a result set
1912     *
1913     * The format of the resulting array depends on which <var>$mode</var>
1914     * you select.  The sample output below is based on this query:
1915     * <pre>
1916     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
1917     *    FROM tblFoo
1918     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
1919     * </pre>
1920     *
1921     * <ul>
1922     * <li>
1923     *
1924     * <kbd>null</kbd> (default)
1925     *   <pre>
1926     *   [0] => Array (
1927     *       [table] => tblFoo
1928     *       [name] => fldId
1929     *       [type] => int
1930     *       [len] => 11
1931     *       [flags] => primary_key not_null
1932     *   )
1933     *   [1] => Array (
1934     *       [table] => tblFoo
1935     *       [name] => fldPhone
1936     *       [type] => string
1937     *       [len] => 20
1938     *       [flags] =>
1939     *   )
1940     *   [2] => Array (
1941     *       [table] => tblBar
1942     *       [name] => fldId
1943     *       [type] => int
1944     *       [len] => 11
1945     *       [flags] => primary_key not_null
1946     *   )
1947     *   </pre>
1948     *
1949     * </li><li>
1950     *
1951     * <kbd>DB_TABLEINFO_ORDER</kbd>
1952     *
1953     *   <p>In addition to the information found in the default output,
1954     *   a notation of the number of columns is provided by the
1955     *   <samp>num_fields</samp> element while the <samp>order</samp>
1956     *   element provides an array with the column names as the keys and
1957     *   their location index number (corresponding to the keys in the
1958     *   the default output) as the values.</p>
1959     *
1960     *   <p>If a result set has identical field names, the last one is
1961     *   used.</p>
1962     *
1963     *   <pre>
1964     *   [num_fields] => 3
1965     *   [order] => Array (
1966     *       [fldId] => 2
1967     *       [fldTrans] => 1
1968     *   )
1969     *   </pre>
1970     *
1971     * </li><li>
1972     *
1973     * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>
1974     *
1975     *   <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more
1976     *   dimensions to the array in which the table names are keys and
1977     *   the field names are sub-keys.  This is helpful for queries that
1978     *   join tables which have identical field names.</p>
1979     *
1980     *   <pre>
1981     *   [num_fields] => 3
1982     *   [ordertable] => Array (
1983     *       [tblFoo] => Array (
1984     *           [fldId] => 0
1985     *           [fldPhone] => 1
1986     *       )
1987     *       [tblBar] => Array (
1988     *           [fldId] => 2
1989     *       )
1990     *   )
1991     *   </pre>
1992     *
1993     * </li>
1994     * </ul>
1995     *
1996     * The <samp>flags</samp> element contains a space separated list
1997     * of extra information about the field.  This data is inconsistent
1998     * between DBMS's due to the way each DBMS works.
1999     *   + <samp>primary_key</samp>
2000     *   + <samp>unique_key</samp>
2001     *   + <samp>multiple_key</samp>
2002     *   + <samp>not_null</samp>
2003     *
2004     * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
2005     * elements if <var>$result</var> is a table name.  The following DBMS's
2006     * provide full information from queries:
2007     *   + fbsql
2008     *   + mysql
2009     *
2010     * If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp>
2011     * turned on, the names of tables and fields will be lowercased.
2012     *
2013     * @param object|string  $result  DB_result object from a query or a
2014     *                                string containing the name of a table.
2015     *                                While this also accepts a query result
2016     *                                resource identifier, this behavior is
2017     *                                deprecated.
2018     * @param int  $mode   either unused or one of the tableInfo modes:
2019     *                     <kbd>DB_TABLEINFO_ORDERTABLE</kbd>,
2020     *                     <kbd>DB_TABLEINFO_ORDER</kbd> or
2021     *                     <kbd>DB_TABLEINFO_FULL</kbd> (which does both).
2022     *                     These are bitwise, so the first two can be
2023     *                     combined using <kbd>|</kbd>.
2024     *
2025     * @return array  an associative array with the information requested.
2026     *                 A DB_Error object on failure.
2027     *
2028     * @see DB_common::setOption()
2029     */
2030    function tableInfo($result, $mode = null)
2031    {
2032        /*
2033         * If the DB_<driver> class has a tableInfo() method, that one
2034         * overrides this one.  But, if the driver doesn't have one,
2035         * this method runs and tells users about that fact.
2036         */
2037        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
2038    }
2039
2040    // }}}
2041    // {{{ getTables()
2042
2043    /**
2044     * Lists the tables in the current database
2045     *
2046     * @return array  the list of tables.  A DB_Error object on failure.
2047     *
2048     * @deprecated Method deprecated some time before Release 1.2
2049     */
2050    function getTables()
2051    {
2052        return $this->getListOf('tables');
2053    }
2054
2055    // }}}
2056    // {{{ getListOf()
2057
2058    /**
2059     * Lists internal database information
2060     *
2061     * @param string $type  type of information being sought.
2062     *                       Common items being sought are:
2063     *                       tables, databases, users, views, functions
2064     *                       Each DBMS's has its own capabilities.
2065     *
2066     * @return array  an array listing the items sought.
2067     *                 A DB DB_Error object on failure.
2068     */
2069    function getListOf($type)
2070    {
2071        $sql = $this->getSpecialQuery($type);
2072        if ($sql === null) {
2073            $this->last_query = '';
2074            return $this->raiseError(DB_ERROR_UNSUPPORTED);
2075        } elseif (is_int($sql) || DB::isError($sql)) {
2076            // Previous error
2077            return $this->raiseError($sql);
2078        } elseif (is_array($sql)) {
2079            // Already the result
2080            return $sql;
2081        }
2082        // Launch this query
2083        return $this->getCol($sql);
2084    }
2085
2086    // }}}
2087    // {{{ getSpecialQuery()
2088
2089    /**
2090     * Obtains the query string needed for listing a given type of objects
2091     *
2092     * @param string $type  the kind of objects you want to retrieve
2093     *
2094     * @return string  the SQL query string or null if the driver doesn't
2095     *                  support the object type requested
2096     *
2097     * @access protected
2098     * @see DB_common::getListOf()
2099     */
2100    function getSpecialQuery($type)
2101    {
2102        return $this->raiseError(DB_ERROR_UNSUPPORTED);
2103    }
2104
2105    // }}}
2106    // {{{ _rtrimArrayValues()
2107
2108    /**
2109     * Right-trims all strings in an array
2110     *
2111     * @param array $array  the array to be trimmed (passed by reference)
2112     *
2113     * @return void
2114     *
2115     * @access protected
2116     */
2117    function _rtrimArrayValues(&$array)
2118    {
2119        foreach ($array as $key => $value) {
2120            if (is_string($value)) {
2121                $array[$key] = rtrim($value);
2122            }
2123        }
2124    }
2125
2126    // }}}
2127    // {{{ _convertNullArrayValuesToEmpty()
2128
2129    /**
2130     * Converts all null values in an array to empty strings
2131     *
2132     * @param array  $array  the array to be de-nullified (passed by reference)
2133     *
2134     * @return void
2135     *
2136     * @access protected
2137     */
2138    function _convertNullArrayValuesToEmpty(&$array)
2139    {
2140        foreach ($array as $key => $value) {
2141            if (is_null($value)) {
2142                $array[$key] = '';
2143            }
2144        }
2145    }
2146
2147    // }}}
2148}
2149
2150/*
2151 * Local variables:
2152 * tab-width: 4
2153 * c-basic-offset: 4
2154 * End:
2155 */
2156
2157?>
Note: See TracBrowser for help on using the repository browser.