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