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