1<?php
2// +----------------------------------------------------------------------+
3// | PHP Version 4                                                        |
4// +----------------------------------------------------------------------+
5// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
6// | Stig. S. Bakken, Lukas Smith                                         |
7// | All rights reserved.                                                 |
8// +----------------------------------------------------------------------+
9// | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
10// | API as well as database abstraction for PHP applications.            |
11// | This LICENSE is in the BSD license style.                            |
12// |                                                                      |
13// | Redistribution and use in source and binary forms, with or without   |
14// | modification, are permitted provided that the following conditions   |
15// | are met:                                                             |
16// |                                                                      |
17// | Redistributions of source code must retain the above copyright       |
18// | notice, this list of conditions and the following disclaimer.        |
19// |                                                                      |
20// | Redistributions in binary form must reproduce the above copyright    |
21// | notice, this list of conditions and the following disclaimer in the  |
22// | documentation and/or other materials provided with the distribution. |
23// |                                                                      |
24// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
25// | Lukas Smith nor the names of his contributors may be used to endorse |
26// | or promote products derived from this software without specific prior|
27// | written permission.                                                  |
28// |                                                                      |
29// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
30// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
31// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
32// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
33// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
34// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
37// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
38// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
40// | POSSIBILITY OF SUCH DAMAGE.                                          |
41// +----------------------------------------------------------------------+
42// | Author: Lukas Smith <smith@backendmedia.com>                         |
43// +----------------------------------------------------------------------+
44//
45// $Id: Common.php,v 1.114.4.22 2004/04/08 19:11:58 lsmith Exp $
46
47/**
48 * @package MDB
49 * @author Lukas Smith <smith@backendmedia.com>
50 */
51
52// }}}
53// {{{ MDB_defaultDebugOutput()
54
55/**
56 * default debug output handler
57 *
58 * @param object $db reference to an MDB database object
59 * @param string $message message that should be appended to the debug
60 *       variable
61 * @return string the corresponding error message, of FALSE
62 * if the error code was unknown
63 * @access public
64 */
65function MDB_defaultDebugOutput(&$db, $message)
66{
67    $db->debug_output .= $db->database . " $message" . $db->getOption('log_line_break');
68}
69
70/**
71 * MDB_Common: Base class that is extended by each MDB driver
72 *
73 * @package MDB
74 * @category Database
75 * @author Lukas Smith <smith@backendmedia.com>
76 */
77class MDB_Common extends PEAR
78{
79    // {{{ properties
80    /**
81    * index of the MDB object withing the global $_MDB_databases array
82    * @var integer
83    * @access private
84    */
85    var $database = 0;
86
87    /**
88    * @var string
89    * @access private
90    */
91    var $host = '';
92
93    /**
94    * @var string
95    * @access private
96    */
97    var $port = '';
98
99    /**
100    * @var string
101    * @access private
102    */
103    var $user = '';
104
105    /**
106    * @var string
107    * @access private
108    */
109    var $password = '';
110
111    /**
112    * @var string
113    * @access private
114    */
115    var $database_name = '';
116
117    /**
118    * @var array
119    * @access private
120    */
121    var $supported = array();
122
123    /**
124    * $options["persistent"] -> boolean persistent connection true|false?
125    * $options["debug"] -> integer numeric debug level
126    * $options["autofree"] -> boolean
127    * $options["lob_buffer_length"] -> integer LOB buffer length
128    * $options["log_line_break"] -> string line-break format
129    * $options["seqname_format"] -> string pattern for sequence name
130    * $options["includelob"] -> boolean
131    * $options["includemanager"] -> boolean
132    * $options["UseTransactions"] -> boolean
133    * $options["optimize"] -> string 'performance' or 'portability'
134    * @var array
135    * @access private
136    */
137    var $options = array(
138            'persistent' => FALSE,
139            'debug' => FALSE,
140            'autofree' => FALSE,
141            'lob_buffer_length' => 8192,
142            'log_line_break' => "\n",
143            'seqname_format' => '%s_seq',
144            'sequence_col_name' => 'sequence',
145            'includelob' => FALSE,
146            'includemanager' => FALSE,
147            'UseTransactions' => FALSE,
148            'optimize' => 'performance',
149        );
150
151    /**
152    * @var string
153    * @access private
154    */
155    var $escape_quotes = '';
156
157    /**
158    * @var integer
159    * @access private
160    */
161    var $decimal_places = 2;
162
163    /**
164    * @var string
165    * @access private
166    */
167    var $manager_included_constant = '';
168
169    /**
170    * @var string
171    * @access private
172    */
173    var $manager_include = '';
174
175    /**
176    * @var string
177    * @access private
178    */
179    var $manager_class_name = '';
180
181    /**
182    * @var object
183    * @access private
184    */
185    var $manager;
186
187    /**
188    * @var array
189    * @access private
190    */
191    var $warnings = array();
192
193    /**
194    * @var string
195    * @access private
196    */
197    var $debug = '';
198
199    /**
200    * @var string
201    * @access private
202    */
203    var $debug_output = '';
204
205    /**
206    * @var boolean
207    * @access private
208    */
209    var $pass_debug_handle = FALSE;
210
211    /**
212    * @var boolean
213    * @access private
214    */
215    var $auto_commit = TRUE;
216
217    /**
218    * @var boolean
219    * @access private
220    */
221    var $in_transaction = FALSE;
222
223    /**
224    * @var integer
225    * @access private
226    */
227    var $first_selected_row = 0;
228
229    /**
230    * @var integer
231    * @access private
232    */
233    var $selected_row_limit = 0;
234
235    /**
236    * DB type (mysql, oci8, odbc etc.)
237    * @var string
238    * @access private
239    */
240    var $type;
241
242    /**
243    * @var array
244    * @access private
245    */
246    var $prepared_queries = array();
247
248    /**
249    * @var array
250    * @access private
251    */
252    var $result_types;
253
254    /**
255    * @var string
256    * @access private
257    */
258    var $last_query = '';
259
260    /**
261    * @var integer
262    * @access private
263    */
264    var $fetchmode = MDB_FETCHMODE_ORDERED;
265
266    /**
267    * @var integer
268    * @access private
269    */
270    var $affected_rows = -1;
271
272    /**
273    * @var array
274    * @access private
275    */
276    var $lobs = array();
277
278    /**
279    * @var array
280    * @access private
281    */
282    var $clobs = array();
283
284    /**
285    * @var array
286    * @access private
287    */
288    var $blobs = array();
289
290    // }}}
291    // {{{ constructor
292
293    /**
294     * Constructor
295     */
296    function MDB_Common()
297    {
298        $database = count($GLOBALS['_MDB_databases']) + 1;
299        $GLOBALS['_MDB_databases'][$database] = &$this;
300        $this->database = $database;
301
302        $this->PEAR('MDB_Error');
303        $this->supported = array();
304        $this->errorcode_map = array();
305        $this->fetchmode = MDB_FETCHMODE_ORDERED;
306    }
307
308    // }}}
309    // {{{ __toString()
310
311    /**
312     * String conversation
313     *
314     * @return string
315     * @access public
316     */
317    function __toString()
318    {
319        $info = get_class($this);
320        $info .= ': (phptype = ' . $this->phptype . ', dbsyntax = ' . $this->dbsyntax . ')';
321        if ($this->connection) {
322            $info .= ' [connected]';
323        }
324        return($info);
325    }
326
327    // }}}
328    // {{{ errorCode()
329
330    /**
331     * Map native error codes to MDB's portable ones.  Requires that
332     * the DB implementation's constructor fills in the $errorcode_map
333     * property.
334     *
335     * @param mixed $nativecode the native error code, as returned by the
336     *      backend database extension (string or integer)
337     * @return int a portable MDB error code, or FALSE if this MDB
338     *      implementation has no mapping for the given error code.
339     * @access public
340     */
341    function errorCode($nativecode)
342    {
343        if (isset($this->errorcode_map[$nativecode])) {
344            return($this->errorcode_map[$nativecode]);
345        }
346        // Fall back to MDB_ERROR if there was no mapping.
347        return(MDB_ERROR);
348    }
349
350    // }}}
351    // {{{ errorMessage()
352
353    /**
354     * Map a MDB error code to a textual message.  This is actually
355     * just a wrapper for MDB::errorMessage().
356     *
357     * @param integer $dbcode the MDB error code
358     * @return string the corresponding error message, of FALSE
359     *      if the error code was unknown
360     * @access public
361     */
362    function errorMessage($dbcode)
363    {
364        return(MDB::errorMessage($this->errorcode_map[$dbcode]));
365    }
366
367    // }}}
368    // {{{ raiseError()
369
370    /**
371     * This method is used to communicate an error and invoke error
372     * callbacks etc.  Basically a wrapper for PEAR::raiseError
373     * without the message string.
374     *
375     * @param mixed $code integer error code, or a PEAR error object (all
376     *      other parameters are ignored if this parameter is an object
377     * @param int $mode error mode, see PEAR_Error docs
378     * @param mixed $options If error mode is PEAR_ERROR_TRIGGER, this is the
379     *      error level (E_USER_NOTICE etc).  If error mode is
380     *      PEAR_ERROR_CALLBACK, this is the callback function, either as a
381     *      function name, or as an array of an object and method name. For
382     *      other error modes this parameter is ignored.
383     * @param string $userinfo Extra debug information.  Defaults to the last
384     *      query and native error code.
385     * @param mixed $nativecode Native error code, integer or string depending
386     *      the backend.
387     * @return object a PEAR error object
388     * @access public
389     * @see PEAR_Error
390     */
391    function &raiseError($code = MDB_ERROR, $mode = NULL, $options = NULL,
392        $userinfo = NULL, $nativecode = NULL)
393    {
394        // The error is yet a MDB error object
395        if (is_object($code)) {
396            // because we the static PEAR::raiseError, our global
397            // handler should be used if it is set
398            if ($mode === null && !empty($this->_default_error_mode)) {
399                $mode    = $this->_default_error_mode;
400                $options = $this->_default_error_options;
401            }
402            $err = PEAR::raiseError($code, NULL, $mode, $options, NULL, NULL, TRUE);
403            return($err);
404        }
405
406        if ($userinfo === NULL) {
407            $userinfo = $this->last_query;
408        }
409
410        if ($nativecode) {
411            $userinfo .= ' [nativecode=' . trim($nativecode) . ']';
412        }
413
414        $err = PEAR::raiseError(NULL, $code, $mode, $options, $userinfo, 'MDB_Error', TRUE);
415        return($err);
416    }
417
418    // }}}
419    // {{{ errorNative()
420
421    /**
422     * returns an errormessage, provides by the database
423     *
424     * @return mixed MDB_Error or message
425     * @access public
426     */
427    function errorNative()
428    {
429        return($this->raiseError(MDB_ERROR_NOT_CAPABLE));
430    }
431
432    // }}}
433    // {{{ resetWarnings()
434
435    /**
436     * reset the warning array
437     *
438     * @access public
439     */
440    function resetWarnings()
441    {
442        $this->warnings = array();
443    }
444
445    // }}}
446    // {{{ getWarnings()
447
448    /**
449     * get all warnings in reverse order.
450     * This means that the last warning is the first element in the array
451     *
452     * @return array with warnings
453     * @access public
454     * @see resetWarnings()
455     */
456    function getWarnings()
457    {
458        return array_reverse($this->warnings);
459    }
460
461    // }}}
462    // {{{ setOption()
463
464    /**
465     * set the option for the db class
466     *
467     * @param string $option option name
468     * @param mixed $value value for the option
469     * @return mixed MDB_OK or MDB_Error
470     * @access public
471     */
472    function setOption($option, $value)
473    {
474        if (isset($this->options[$option])) {
475            $this->options[$option] = $value;
476            return MDB_OK;
477        }
478        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, "unknown option $option"));
479    }
480
481    // }}}
482    // {{{ getOption()
483
484    /**
485     * returns the value of an option
486     *
487     * @param string $option option name
488     * @return mixed the option value or error object
489     * @access public
490     */
491    function getOption($option)
492    {
493        if (isset($this->options[$option])) {
494            return($this->options[$option]);
495        }
496        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, "unknown option $option"));
497    }
498
499    // }}}
500    // {{{ captureDebugOutput()
501
502    /**
503     * set a debug handler
504     *
505     * @param string $capture name of the function that should be used in
506     *      debug()
507     * @access public
508     * @see debug()
509     */
510    function captureDebugOutput($capture)
511    {
512        $this->pass_debug_handle = $capture;
513        $this->debug = ($capture ? 'MDB_defaultDebugOutput' : '');
514    }
515
516    // }}}
517    // {{{ debug()
518
519    /**
520     * set a debug message
521     *
522     * @param string $message Message with information for the user.
523     * @access public
524     */
525    function debug($message)
526    {
527        if (strcmp($function = $this->debug, '')) {
528            if ($this->pass_debug_handle) {
529                $function($this, $message);
530            } else {
531                $function($message);
532            }
533        }
534    }
535
536    // }}}
537    // {{{ debugOutput()
538
539    /**
540     * output debug info
541     *
542     * @return string content of the debug_output class variable
543     * @access public
544     */
545    function debugOutput()
546    {
547        return($this->debug_output);
548    }
549
550    // }}}
551    // {{{ setError() (deprecated)
552
553    /**
554     * set an error (deprecated)
555     *
556     * @param string $scope Scope of the error message
557     *     (usually the method tht caused the error)
558     * @param string $message Message with information for the user.
559     * @return boolean FALSE
560     * @access private
561     */
562    function setError($scope, $message)
563    {
564        $this->last_error = $message;
565        $this->debug($scope . ': ' . $message);
566        if (($function = $this->error_handler) != '') {
567            $error = array(
568                'Scope' => $scope,
569                'Message' => $message
570            );
571            $function($this, $error);
572        }
573        return(0);
574    }
575
576    // }}}
577    // {{{ setErrorHandler() (deprecated)
578
579    /**
580     * Specify a function that is called when an error occurs.
581     *
582     * @param string $function Name of the function that will be called on
583     *      error. If an empty string is specified, no handler function is
584     *      called on error. The error handler function receives two arguments.
585     *      The first argument a reference to the driver class object that
586     *      triggered the error.
587     *
588     *      The second argument is a reference to an associative array that
589     *      provides details about the error that occured. These details provide
590     *      more information than it is returned by the MetabaseError function.
591     *
592     *      These are the currently supported error detail entries:
593     *
594     *      Scope
595     *       String that indicates the scope of the driver object class
596     *       within which the error occured.
597     *
598     *      Message
599     *       Error message as is returned by the MetabaseError function.
600     * @return string name of last function
601     * @access public
602     */
603    function setErrorHandler($function)
604    {
605        $last_function = $this->error_handler;
606        $this->error_handler = $function;
607        return($last_function);
608    }
609
610    // }}}
611    // {{{ error() (deprecated)
612
613    /**
614     * Retrieve the error message text associated with the last operation that
615     * failed. Some functions may fail but they do not return the reason that
616     * makes them to fail. This function is meant to retrieve a textual
617     * description of the failure cause.
618     *
619     * @return string the error message text associated with the last failure.
620     * @access public
621     */
622    function error()
623    {
624        return($this->last_error);
625    }
626
627    // }}}
628    // {{{ _quote()
629
630    /**
631     * Quotes a string so it can be safely used in a query. It will quote
632     * the text so it can safely be used within a query.
633     *
634     * @param string $text the input string to quote
635     * @return string quoted string
636     * @access private
637     */
638    function _quote($text)
639    {
640        if (strcmp($this->escape_quotes, "'")) {
641            $text = str_replace($this->escape_quotes, $this->escape_quotes . $this->escape_quotes, $text);
642        }
643        return str_replace("'", $this->escape_quotes . "'", $text);
644    }
645
646    // }}}
647    // {{{ quoteIdentifier()
648
649    /**
650     * Quote a string so it can be safely used as a table or column name
651     *
652     * Delimiting style depends on which database driver is being used.
653     *
654     * NOTE: just because you CAN use delimited identifiers doesn't mean
655     * you SHOULD use them.  In general, they end up causing way more
656     * problems than they solve.
657     *
658     * Portability is broken by using the following characters inside
659     * delimited identifiers:
660     *   + backtick (<kbd>`</kbd>) -- due to MySQL
661     *   + double quote (<kbd>"</kbd>) -- due to Oracle
662     *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
663     *
664     * Delimited identifiers are known to generally work correctly under
665     * the following drivers:
666     *   + mssql
667     *   + mysql
668     *   + mysqli
669     *   + oci8
670     *   + odbc(access)
671     *   + odbc(db2)
672     *   + pgsql
673     *   + sqlite
674     *   + sybase
675     *
676     * InterBase doesn't seem to be able to use delimited identifiers
677     * via PHP 4.  They work fine under PHP 5.
678     *
679     * @param string $str  identifier name to be quoted
680     *
681     * @return string  quoted identifier string
682     *
683     * @access public
684     */
685    function quoteIdentifier($str)
686    {
687        return '"' . str_replace('"', '""', $str) . '"';
688    }
689
690    // }}}
691    // {{{ _loadModule()
692
693    /**
694     * loads an module
695     *
696     * @param string $scope information about what method is being loaded,
697     *      that is used for error messages
698     * @param string $module name of the module that should be loaded
699     *      (only used for error messages)
700     * @param string $included_constant name of the constant that should be
701     *      defined when the module has been loaded
702     * @param string $include name of the script that includes the module
703     * @access private
704     */
705    function _loadModule($scope, $module, $included_constant, $include)
706    {
707        if (strlen($included_constant) == 0 || !defined($included_constant)) {
708            if($include) {
709                $include = 'MDB/Modules/'.$include;
710                if(MDB::isError($debug = $this->getOption('debug')) || $debug > 2) {
711                    include_once($include);
712                } else {
713                    @include_once($include);
714                }
715            } else {
716                return($this->raiseError(MDB_ERROR_LOADMODULE, NULL, NULL,
717                    $scope . ': it was not specified an existing ' . $module . ' file (' . $include . ')'));
718            }
719        }
720        return(MDB_OK);
721    }
722
723    // }}}
724    // {{{ loadLob()
725
726    /**
727     * loads the LOB module
728     *
729     * @param string $scope information about what method is being loaded,
730     *                       that is used for error messages
731     * @access public
732     */
733    function loadLob($scope = '')
734    {
735        if (defined('MDB_LOB_INCLUDED')) {
736            return(MDB_OK);
737        }
738        $result = $this->_loadModule($scope, 'LOB',
739            'MDB_LOB_INCLUDED', 'LOB.php');
740        if (MDB::isError($result)) {
741            return($result);
742        }
743        return(MDB_OK);
744    }
745
746    // }}}
747    // {{{ loadManager()
748
749    /**
750     * loads the Manager module
751     *
752     * @param string $scope information about what method is being loaded,
753     *                       that is used for error messages
754     * @access public
755     */
756    function loadManager($scope = '')
757    {
758        if (isset($this->manager) && is_object($this->manager)) {
759            return(MDB_OK);
760        }
761        $result = $this->_loadModule($scope, 'Manager',
762            'MDB_MANAGER_'.strtoupper($this->phptype).'_INCLUDED',
763            'Manager/'.$this->phptype.'.php');
764        if (MDB::isError($result)) {
765            return($result);
766        }
767        $class_name = 'MDB_Manager_'.$this->dbsyntax;
768        if (!class_exists($class_name)) {
769            return($this->raiseError(MDB_ERROR_LOADMODULE, NULL, NULL,
770                'Unable to load extension'));
771        }
772        @$this->manager = new $class_name;
773        return(MDB_OK);
774    }
775
776    // }}}
777    // {{{ autoCommit()
778
779    /**
780     * Define whether database changes done on the database be automatically
781     * committed. This function may also implicitly start or end a transaction.
782     *
783     * @param boolean $auto_commit flag that indicates whether the database
784     *      changes should be committed right after executing every query
785     *      statement. If this argument is 0 a transaction implicitly started.
786     *      Otherwise, if a transaction is in progress it is ended by committing
787     *      any database changes that were pending.
788     * @return mixed MDB_OK on success, a MDB error on failure
789     * @access public
790     */
791    function autoCommit($auto_commit)
792    {
793        $this->debug('AutoCommit: ' . ($auto_commit ? 'On' : 'Off'));
794        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
795            'Auto-commit transactions: transactions are not supported'));
796    }
797
798    // }}}
799    // {{{ commit()
800
801    /**
802     * Commit the database changes done during a transaction that is in
803     * progress. This function may only be called when auto-committing is
804     * disabled, otherwise it will fail. Therefore, a new transaction is
805     * implicitly started after committing the pending changes.
806     *
807     * @return mixed MDB_OK on success, a MDB error on failure
808     * @access public
809     */
810    function commit()
811    {
812        $this->debug('Commit Transaction');
813        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
814            'Commit transaction: commiting transactions are not supported'));
815    }
816
817    // }}}
818    // {{{ rollback()
819
820    /**
821     * Cancel any database changes done during a transaction that is in
822     * progress. This function may only be called when auto-committing is
823     * disabled, otherwise it will fail. Therefore, a new transaction is
824     * implicitly started after canceling the pending changes.
825     *
826     * @return mixed MDB_OK on success, a MDB error on failure
827     * @access public
828     */
829    function rollback()
830    {
831        $this->debug('Rollback Transaction');
832        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
833            'Rollback transaction: rolling back transactions are not supported'));
834    }
835
836    // }}}
837    // {{{ disconnect()
838
839    /**
840     * Log out and disconnect from the database.
841     *
842     * @return mixed TRUE on success, FALSE if not connected and error
843     *                object on error
844     * @access public
845     */
846    function disconnect()
847    {
848        if ($this->in_transaction && !MDB::isError($this->rollback()) && !MDB::isError($this->autoCommit(TRUE))) {
849            $this->in_transaction = FALSE;
850        }
851        return($this->_close());
852    }
853
854    // }}}
855    // {{{ _close()
856
857    /**
858     * all the RDBMS specific things needed to close a DB connection
859     *
860     * @access private
861     */
862    function _close()
863    {
864        unset($GLOBALS['_MDB_databases'][$this->database]);
865    }
866
867    // }}}
868    // {{{ setDatabase()
869
870    /**
871     * Select a different database
872     *
873     * @param string $name name of the database that should be selected
874     * @return string name of the database previously connected to
875     * @access public
876     */
877    function setDatabase($name)
878    {
879        $previous_database_name = $this->database_name;
880        $this->database_name = $name;
881        return($previous_database_name);
882    }
883
884    // }}}
885    // {{{ setDSN()
886
887    /**
888     * set the DSN
889     *
890     * @param mixed     $dsninfo    DSN string or array
891     * @return MDB_OK
892     * @access public
893     */
894    function setDSN($dsn)
895    {
896        $dsninfo = MDB::parseDSN($dsn);
897        if(isset($dsninfo['hostspec'])) {
898            $this->host = $dsninfo['hostspec'];
899        }
900        if(isset($dsninfo['port'])) {
901            $this->port = $dsninfo['port'];
902        }
903        if(isset($dsninfo['username'])) {
904            $this->user = $dsninfo['username'];
905        }
906        if(isset($dsninfo['password'])) {
907            $this->password = $dsninfo['password'];
908        }
909        if(isset($dsninfo['database'])) {
910            $this->database_name = $dsninfo['database'];
911        }
912        return(MDB_OK);
913    }
914
915    // }}}
916    // {{{ getDSN()
917
918    /**
919     * return the DSN as a string
920     *
921     * @param string     $type    type to return
922     * @return mixed DSN in the chosen type
923     * @access public
924     */
925    function getDSN($type = 'string')
926    {
927        switch($type) {
928            case 'array':
929                $dsn = array(
930                    'phptype' => $this->phptype,
931                    'username' => $this->user,
932                    'password' => $this->password,
933                    'hostspec' => $this->host,
934                    'database' => $this->database_name
935                );
936                break;
937            default:
938                $dsn = $this->phptype.'://'.$this->user.':'
939                    .$this->password.'@'.$this->host
940                    .($this->port ? (':'.$this->port) : '')
941                    .'/'.$this->database_name;
942                break;
943        }
944        return($dsn);
945    }
946
947    // }}}
948    // {{{ createDatabase()
949
950    /**
951     * create a new database
952     *
953     * @param string $name name of the database that should be created
954     * @return mixed MDB_OK on success, a MDB error on failure
955     * @access public
956     */
957    function createDatabase($name)
958    {
959        $result = $this->loadManager('Create database');
960        if (MDB::isError($result)) {
961            return($result);
962        }
963        return($this->manager->createDatabase($this, $name));
964    }
965
966    // }}}
967    // {{{ dropDatabase()
968
969    /**
970     * drop an existing database
971     *
972     * @param string $name name of the database that should be dropped
973     * @return mixed MDB_OK on success, a MDB error on failure
974     * @access public
975     */
976    function dropDatabase($name)
977    {
978        $result = $this->loadManager('Drop database');
979        if (MDB::isError($result)) {
980            return($result);
981        }
982        return($this->manager->dropDatabase($this, $name));
983    }
984
985    // }}}
986    // {{{ createTable()
987
988    /**
989     * create a new table
990     *
991     * @param string $name Name of the database that should be created
992     * @param array $fields Associative array that contains the definition of
993     *      each field of the new table. The indexes of the array entries are
994     *      the names of the fields of the table an the array entry values are
995     *      associative arrays like those that are meant to be passed with the
996     *      field definitions to get[Type]Declaration() functions.
997     *
998     *      Example
999     *        array(
1000     *            'id' => array(
1001     *                'type' => 'integer',
1002     *                'unsigned' => 1
1003     *                'notnull' => 1
1004     *                'default' => 0
1005     *            ),
1006     *            'name' => array(
1007     *                'type' => 'text',
1008     *                'length' => 12
1009     *            ),
1010     *            'password' => array(
1011     *                'type' => 'text',
1012     *                'length' => 12
1013     *            )
1014     *        );
1015     * @return mixed MDB_OK on success, a MDB error on failure
1016     * @access public
1017     */
1018    function createTable($name, $fields)
1019    {
1020        $result = $this->loadManager('Create table');
1021        if (MDB::isError($result)) {
1022            return($result);
1023        }
1024        return($this->manager->createTable($this, $name, $fields));
1025    }
1026
1027    // }}}
1028    // {{{ dropTable()
1029
1030    /**
1031     * drop an existing table
1032     *
1033     * @param string $name name of the table that should be dropped
1034     * @return mixed MDB_OK on success, a MDB error on failure
1035     * @access public
1036     */
1037    function dropTable($name)
1038    {
1039        $result = $this->loadManager('Drop table');
1040        if (MDB::isError($result)) {
1041            return($result);
1042        }
1043        return($this->manager->dropTable($this, $name));
1044    }
1045
1046    // }}}
1047    // {{{ alterTable()
1048
1049    /**
1050     * alter an existing table
1051     *
1052     * @param string $name name of the table that is intended to be changed.
1053     * @param array  $changes associative array that contains the details of
1054     *       each type of change that is intended to be performed. The types of
1055     *       changes that are currently supported are defined as follows:
1056     *
1057     *  name
1058     *      New name for the table.
1059     *
1060     *  AddedFields
1061     *      Associative array with the names of fields to be added as indexes of
1062     *      the array. The value of each entry of the array should be set to
1063     *      another associative array with the properties of the fields to be
1064     *      added. The properties of the fields should be the same as defined by
1065     *      the Metabase parser.
1066     *
1067     *      Additionally, there should be an entry named Declaration that is
1068     *      expected to contain the portion of the field declaration already in
1069     *       DBMS specific SQL code as it is used in the CREATE TABLE statement.
1070     *
1071     *  RemovedFields
1072     *      Associative array with the names of fields to be removed as indexes of
1073     *      the array. Currently the values assigned to each entry are ignored. An
1074     *      empty array should be used for future compatibility.
1075     *
1076     *  RenamedFields
1077     *      Associative array with the names of fields to be renamed as indexes of
1078     *      the array. The value of each entry of the array should be set to another
1079     *      associative array with the entry named name with the new field name and
1080     *      the entry named Declaration that is expected to contain the portion of
1081     *      the field declaration already in DBMS specific SQL code as it is used
1082     *      in the CREATE TABLE statement.
1083     *
1084     *  ChangedFields
1085     *      Associative array with the names of the fields to be changed as indexes
1086     *      of the array. Keep in mind that if it is intended to change either the
1087     *      name of a field and any other properties, the ChangedFields array
1088     *      entries should have the new names of the fields as array indexes.
1089     *
1090     *      The value of each entry of the array should be set to another
1091     *      associative array with the properties of the fields to that are meant
1092     *      to be changed as array entries. These entries should be assigned to the
1093     *      new values of the respective properties. The properties of the fields
1094     *      should be the* same as defined by the Metabase parser.
1095     *
1096     *      If the default property is meant to be added, removed or changed, there
1097     *      should also be an entry with index ChangedDefault assigned to 1.
1098     *      Similarly, if the notnull constraint is to be added or removed, there
1099     *      should also be an entry with index ChangedNotNull assigned to 1.
1100     *
1101     *      Additionally, there should be an entry named Declaration that is
1102     *      expected to contain the portion of the field changed declaration
1103     *      already in DBMS specific SQL code as it is used in the CREATE TABLE
1104     *      statement.
1105     *
1106     *  Example
1107     *      array(
1108     *          'name' => 'userlist',
1109     *          'AddedFields' => array(
1110     *              'quota' => array(
1111     *                  'type' => 'integer',
1112     *                  'unsigned' => 1,
1113     *                  'Declaration' => 'quota INT'
1114     *              )
1115     *          ),
1116     *          'RemovedFields' => array(
1117     *              'file_limit' => array(),
1118     *              'time_limit' => array()
1119     *          ),
1120     *          'ChangedFields' => array(
1121     *              'gender' => array(
1122     *                  'default' => 'M',
1123     *                  'ChangeDefault' => 1,
1124     *                  'Declaration' => "gender CHAR(1) DEFAULT 'M'"
1125     *              )
1126     *          ),
1127     *          'RenamedFields' => array(
1128     *              'sex' => array(
1129     *                  'name' => 'gender',
1130     *                  'Declaration' => "gender CHAR(1) DEFAULT 'M'"
1131     *              )
1132     *          )
1133     *      )
1134     *
1135     * @param boolean $check indicates whether the function should just check
1136     *       if the DBMS driver can perform the requested table alterations if
1137     *       the value is TRUE or actually perform them otherwise.
1138     * @return mixed MDB_OK on success, a MDB error on failure
1139     * @access public
1140     */
1141    function alterTable($name, $changes, $check)
1142    {
1143        $result = $this->loadManager('Alter table');
1144        if (MDB::isError($result)) {
1145            return($result);
1146        }
1147        return($this->manager->alterTable($this, $name, $changes, $check));
1148    }
1149
1150    // }}}
1151    // {{{ listDatabases()
1152
1153    /**
1154     * list all databases
1155     *
1156     * @return mixed data array on success, a MDB error on failure
1157     * @access public
1158     */
1159    function listDatabases()
1160    {
1161        $result = $this->loadManager('List databases');
1162        if (MDB::isError($result)) {
1163            return($result);
1164        }
1165        return($this->manager->listDatabases($this));
1166    }
1167
1168    // }}}
1169    // {{{ listUsers()
1170
1171    /**
1172     * list all users
1173     *
1174     * @return mixed data array on success, a MDB error on failure
1175     * @access public
1176     */
1177    function listUsers()
1178    {
1179        $result = $this->loadManager('List users');
1180        if (MDB::isError($result)) {
1181            return($result);
1182        }
1183        return($this->manager->listUsers($this));
1184    }
1185
1186    // }}}
1187    // {{{ listViews()
1188
1189    /**
1190     * list all viewes in the current database
1191     *
1192     * @return mixed data array on success, a MDB error on failure
1193     * @access public
1194     */
1195    function listViews()
1196    {
1197        $result = $this->loadManager('List views');
1198        if (MDB::isError($result)) {
1199            return($result);
1200        }
1201        return($this->manager->listViews($this));
1202    }
1203
1204    // }}}
1205    // {{{ listFunctions()
1206
1207    /**
1208     * list all functions in the current database
1209     *
1210     * @return mixed data array on success, a MDB error on failure
1211     * @access public
1212     */
1213    function listFunctions()
1214    {
1215        $result = $this->loadManager('List functions');
1216        if (MDB::isError($result)) {
1217            return($result);
1218        }
1219        return($this->manager->listFunctions($this));
1220    }
1221
1222    // }}}
1223    // {{{ listTables()
1224
1225    /**
1226     * list all tables in the current database
1227     *
1228     * @return mixed data array on success, a MDB error on failure
1229     * @access public
1230     */
1231    function listTables()
1232    {
1233        $result = $this->loadManager('List tables');
1234        if (MDB::isError($result)) {
1235            return($result);
1236        }
1237        return($this->manager->listTables($this));
1238    }
1239
1240    // }}}
1241    // {{{ listTableFields()
1242
1243    /**
1244     * list all fields in a tables in the current database
1245     *
1246     * @param string $table name of table that should be used in method
1247     * @return mixed data array on success, a MDB error on failure
1248     * @access public
1249     */
1250    function listTableFields($table)
1251    {
1252        $result = $this->loadManager('List table fields');
1253        if (MDB::isError($result)) {
1254            return($result);
1255        }
1256        return($this->manager->listTableFields($this, $table));
1257    }
1258
1259    // }}}
1260    // {{{ getTableFieldDefinition()
1261
1262    /**
1263     * get the stucture of a field into an array
1264     *
1265     * @param string $table name of table that should be used in method
1266     * @param string $fields name of field that should be used in method
1267     * @return mixed data array on success, a MDB error on failure
1268     * @access public
1269     */
1270    function getTableFieldDefinition($table, $field)
1271    {
1272        $result = $this->loadManager('Get table field definition');
1273        if (MDB::isError($result)) {
1274            return($result);
1275        }
1276        return($this->manager->getTableFieldDefinition($this, $table, $field));
1277    }
1278
1279    // }}}
1280    // {{{ getFieldDeclaration()
1281
1282    /**
1283     * get declaration of a field
1284     *
1285     * @param string $field_name name of the field to be created
1286     * @param string $field associative array with the name of the properties
1287     *       of the field being declared as array indexes. Currently, the types
1288     *       of supported field properties are as follows:
1289     *
1290     *       default
1291     *           Boolean value to be used as default for this field.
1292     *
1293     *       notnull
1294     *           Boolean flag that indicates whether this field is constrained
1295     *           to not be set to NULL.
1296     * @return mixed string on success, a MDB error on failure
1297     * @access public
1298     */
1299    function getFieldDeclaration($field_name, $field)
1300    {
1301        $result = $this->loadManager('Get table field definition');
1302        if (MDB::isError($result)) {
1303            return($result);
1304        }
1305        return($this->manager->getFieldDeclaration($this, $field_name, $field));
1306    }
1307
1308    // }}}
1309    // {{{ getFieldDeclarationList()
1310
1311    /**
1312     * get declaration of a number of field in bulk
1313     *
1314     * @param string $fields a multidimensional associative array.
1315     * The first dimension determines the field name, while the second
1316     * dimension is keyed with the name of the properties
1317     *       of the field being declared as array indexes. Currently, the types
1318     *       of supported field properties are as follows:
1319     *
1320     *       default
1321     *           Boolean value to be used as default for this field.
1322     *
1323     *       notnull
1324     *           Boolean flag that indicates whether this field is constrained
1325     *           to not be set to NULL.
1326     *
1327     *       default
1328     *           Boolean value to be used as default for this field.
1329     *
1330     *       notnull
1331     *           Boolean flag that indicates whether this field is constrained
1332     *           to not be set to NULL.
1333     * @return mixed string on success, a MDB error on failure
1334     * @access public
1335     */
1336    function getFieldDeclarationList($fields)
1337    {
1338        $result = $this->loadManager('Get table field list');
1339        if (MDB::isError($result)) {
1340            return($result);
1341        }
1342        return($this->manager->getFieldDeclarationList($this, $fields));
1343    }
1344
1345    // }}}
1346    // {{{ _isSequenceName()
1347
1348    /**
1349     * list all tables in the current database
1350     *
1351     * @param string $sqn string that containts name of a potential sequence
1352     * @return mixed name of the sequence if $sqn is a name of a sequence, else FALSE
1353     * @access private
1354     */
1355    function _isSequenceName($sqn)
1356    {
1357        $result = $this->loadManager('is sequence name');
1358        if (MDB::isError($result)) {
1359            return($result);
1360        }
1361        return($this->manager->_isSequenceName($this, $sqn));
1362    }
1363
1364    // }}}
1365    // {{{ createIndex()
1366
1367    /**
1368     * get the stucture of a field into an array
1369     *
1370     * @param string $table name of the table on which the index is to be
1371     *       created
1372     * @param string $name name of the index to be created
1373     * @param array $definition associative array that defines properties of
1374     *       the index to be created. Currently, only one property named FIELDS
1375     *       is supported. This property is also an associative with the names
1376     *       of the index fields as array indexes. Each entry of this array is
1377     *       set to another type of associative array that specifies properties
1378     *       of the index that are specific to each field.
1379     *
1380     *       Currently, only the sorting property is supported. It should be
1381     *       used to define the sorting direction of the index. It may be set
1382     *       to either ascending or descending. Not all DBMS support index
1383     *       sorting direction configuration. The DBMS drivers of those that do
1384     *       not support it ignore this property. Use the function support() to
1385     *       determine whether the DBMS driver can manage indexes.
1386     *
1387     *       Example
1388     *          array(
1389     *              'FIELDS' => array(
1390     *                  'user_name' => array(
1391     *                      'sorting' => 'ascending'
1392     *                  ),
1393     *                  'last_login' => array()
1394     *              )
1395     *          )
1396     * @return mixed MDB_OK on success, a MDB error on failure
1397     * @access public
1398     */
1399    function createIndex($table, $name, $definition)
1400    {
1401        $result = $this->loadManager('Create index');
1402        if (MDB::isError($result)) {
1403            return($result);
1404        }
1405        return($this->manager->createIndex($this, $table, $name, $definition));
1406    }
1407
1408    // }}}
1409    // {{{ dropIndex()
1410
1411    /**
1412     * drop existing index
1413     *
1414     * @param string $table name of table that should be used in method
1415     * @param string $name name of the index to be dropped
1416     * @return mixed MDB_OK on success, a MDB error on failure
1417     * @access public
1418     */
1419    function dropIndex($table, $name)
1420    {
1421        $result = $this->loadManager('Drop index');
1422        if (MDB::isError($result)) {
1423            return($result);
1424        }
1425        return($this->manager->dropIndex($this, $table , $name));
1426    }
1427
1428    // }}}
1429    // {{{ listTableIndexes()
1430
1431    /**
1432     * list all indexes in a table
1433     *
1434     * @param string $table name of table that should be used in method
1435     * @return mixed data array on success, a MDB error on failure
1436     * @access public
1437     */
1438    function listTableIndexes($table)
1439    {
1440        $result = $this->loadManager('List table index');
1441        if (MDB::isError($result)) {
1442            return($result);
1443        }
1444        return($this->manager->listTableIndexes($this, $table));
1445    }
1446
1447    // }}}
1448    // {{{ getTableIndexDefinition()
1449
1450    /**
1451     * get the stucture of an index into an array
1452     *
1453     * @param string $table name of table that should be used in method
1454     * @param string $index name of index that should be used in method
1455     * @return mixed data array on success, a MDB error on failure
1456     * @access public
1457     */
1458    function getTableIndexDefinition($table, $index)
1459    {
1460        $result = $this->loadManager('Get table index definition');
1461        if (MDB::isError($result)) {
1462            return($result);
1463        }
1464        return($this->manager->getTableIndexDefinition($this, $table, $index));
1465    }
1466
1467    // }}}
1468    // {{{ createSequence()
1469
1470    /**
1471     * create sequence
1472     *
1473     * @param string $name name of the sequence to be created
1474     * @param string $start start value of the sequence; default is 1
1475     * @return mixed MDB_OK on success, a MDB error on failure
1476     * @access public
1477     */
1478    function createSequence($name, $start = 1)
1479    {
1480        $result = $this->loadManager('Create sequence');
1481        if (MDB::isError($result)) {
1482            return($result);
1483        }
1484        return($this->manager->createSequence($this, $name, $start));
1485    }
1486
1487    // }}}
1488    // {{{ dropSequence()
1489
1490    /**
1491     * drop existing sequence
1492     *
1493     * @param string $name name of the sequence to be dropped
1494     * @return mixed MDB_OK on success, a MDB error on failure
1495     * @access public
1496     */
1497    function dropSequence($name)
1498    {
1499        $result = $this->loadManager('Drop sequence');
1500        if (MDB::isError($result)) {
1501            return($result);
1502        }
1503        return($this->manager->dropSequence($this, $name));
1504    }
1505
1506    // }}}
1507    // {{{ listSequences()
1508
1509    /**
1510     * list all tables in the current database
1511     *
1512     * @return mixed data array on success, a MDB error on failure
1513     * @access public
1514     */
1515    function listSequences()
1516    {
1517        $result = $this->loadManager('List sequences');
1518        if (MDB::isError($result)) {
1519            return($result);
1520        }
1521        return($this->manager->listSequences($this));
1522    }
1523
1524    // }}}
1525    // {{{ getSequenceDefinition()
1526
1527    /**
1528     * get the stucture of a sequence into an array
1529     *
1530     * @param string $sequence name of sequence that should be used in method
1531     * @return mixed data array on success, a MDB error on failure
1532     * @access public
1533     */
1534    function getSequenceDefinition($sequence)
1535    {
1536        $result = $this->loadManager('Get sequence definition');
1537        if (MDB::isError($result)) {
1538            return($result);
1539        }
1540        return($this->manager->getSequenceDefinition($this, $sequence));
1541    }
1542
1543    // }}}
1544    // {{{ query()
1545
1546    /**
1547     * Send a query to the database and return any results
1548     *
1549     * @param string $query the SQL query
1550     * @param mixed   $types  array that contains the types of the columns in
1551     *                        the result set
1552     * @return mixed a result handle or MDB_OK on success, a MDB error on failure
1553     * @access public
1554     */
1555    function query($query, $types = NULL)
1556    {
1557        $this->debug("Query: $query");
1558        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'Query: database queries are not implemented'));
1559    }
1560
1561    // }}}
1562    // {{{ setSelectedRowRange()
1563
1564    /**
1565     * set the range of the next query
1566     *
1567     * @param string $first first row to select
1568     * @param string $limit number of rows to select
1569     * @return mixed MDB_OK on success, a MDB error on failure
1570     * @access public
1571     */
1572    function setSelectedRowRange($first, $limit)
1573    {
1574        if (!isset($this->supported['SelectRowRanges'])) {
1575            return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
1576                'Set selected row range: selecting row ranges is not supported by this driver'));
1577        }
1578        $first = (int)$first;
1579        if ($first < 0) {
1580            return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
1581                'Set selected row range: it was not specified a valid first selected range row'));
1582        }
1583        $limit = (int)$limit;
1584        if ($limit < 1) {
1585            return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
1586                'Set selected row range: it was not specified a valid selected range row limit'));
1587        }
1588        $this->first_selected_row = $first;
1589        $this->selected_row_limit = $limit;
1590        return(MDB_OK);
1591    }
1592
1593    // }}}
1594    // {{{ limitQuery()
1595
1596    /**
1597     * Generates a limited query
1598     *
1599     * @param string $query query
1600     * @param mixed   $types  array that contains the types of the columns in
1601     *                        the result set
1602     * @param integer $from the row to start to fetching
1603     * @param integer $count the numbers of rows to fetch
1604     * @return mixed a valid ressource pointer or a MDB_Error
1605     * @access public
1606     */
1607    function limitQuery($query, $types = NULL, $from, $count)
1608    {
1609        $result = $this->setSelectedRowRange($from, $count);
1610        if (MDB::isError($result)) {
1611            return($result);
1612        }
1613        return($this->query($query, $types));
1614    }
1615
1616    // }}}
1617    // {{{ subSelect()
1618
1619    /**
1620     * simple subselect emulation: leaves the query untouched for all RDBMS
1621     * that support subselects
1622     *
1623     * @access public
1624     *
1625     * @param string $query the SQL query for the subselect that may only
1626     *                      return a column
1627     * @param string $quote determines if the data needs to be quoted before
1628     *                      being returned
1629     *
1630     * @return string the query
1631     */
1632    function subSelect($query, $quote = FALSE)
1633    {
1634        if ($this->supported['SubSelects'] == 1) {
1635            return($query);
1636        }
1637        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'Subselect: subselect not implemented'));
1638    }
1639
1640    // }}}
1641    // {{{ replace()
1642
1643    /**
1644     * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
1645     * query, except that if there is already a row in the table with the same
1646     * key field values, the REPLACE query just updates its values instead of
1647     * inserting a new row.
1648     *
1649     * The REPLACE type of query does not make part of the SQL standards. Since
1650     * pratically only MySQL implements it natively, this type of query is
1651     * emulated through this method for other DBMS using standard types of
1652     * queries inside a transaction to assure the atomicity of the operation.
1653     *
1654     * @param string $table name of the table on which the REPLACE query will
1655     *       be executed.
1656     * @param array $fields associative array that describes the fields and the
1657     *       values that will be inserted or updated in the specified table. The
1658     *       indexes of the array are the names of all the fields of the table.
1659     *       The values of the array are also associative arrays that describe
1660     *       the values and other properties of the table fields.
1661     *
1662     *       Here follows a list of field properties that need to be specified:
1663     *
1664     *       Value
1665     *           Value to be assigned to the specified field. This value may be
1666     *           of specified in database independent type format as this
1667     *           function can perform the necessary datatype conversions.
1668     *
1669     *           Default: this property is required unless the Null property is
1670     *           set to 1.
1671     *
1672     *       Type
1673     *           Name of the type of the field. Currently, all types Metabase
1674     *           are supported except for clob and blob.
1675     *
1676     *           Default: no type conversion
1677     *
1678     *       Null
1679     *           Boolean property that indicates that the value for this field
1680     *           should be set to NULL.
1681     *
1682     *           The default value for fields missing in INSERT queries may be
1683     *           specified the definition of a table. Often, the default value
1684     *           is already NULL, but since the REPLACE may be emulated using
1685     *           an UPDATE query, make sure that all fields of the table are
1686     *           listed in this function argument array.
1687     *
1688     *           Default: 0
1689     *
1690     *       Key
1691     *           Boolean property that indicates that this field should be
1692     *           handled as a primary key or at least as part of the compound
1693     *           unique index of the table that will determine the row that will
1694     *           updated if it exists or inserted a new row otherwise.
1695     *
1696     *           This function will fail if no key field is specified or if the
1697     *           value of a key field is set to NULL because fields that are
1698     *           part of unique index they may not be NULL.
1699     *
1700     *           Default: 0
1701     * @return mixed MDB_OK on success, a MDB error on failure
1702     * @access public
1703     */
1704    function replace($table, $fields)
1705    {
1706        if (!$this->supported['Replace']) {
1707            return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'Replace: replace query is not supported'));
1708        }
1709        $count = count($fields);
1710        for($keys = 0, $condition = $insert = $values = '', reset($fields), $field = 0;
1711            $field < $count;
1712            next($fields), $field++)
1713        {
1714            $name = key($fields);
1715            if ($field > 0) {
1716                $insert .= ', ';
1717                $values .= ', ';
1718            }
1719            $insert .= $name;
1720            if (isset($fields[$name]['Null']) && $fields[$name]['Null']) {
1721                $value = 'NULL';
1722            } else {
1723                if(isset($fields[$name]['Type'])) {
1724                    switch ($fields[$name]['Type']) {
1725                        case 'text':
1726                            $value = $this->getTextValue($fields[$name]['Value']);
1727                            break;
1728                        case 'boolean':
1729                            $value = $this->getBooleanValue($fields[$name]['Value']);
1730                            break;
1731                        case 'integer':
1732                            $value = $this->getIntegerValue($fields[$name]['Value']);
1733                            break;
1734                        case 'decimal':
1735                            $value = $this->getDecimalValue($fields[$name]['Value']);
1736                            break;
1737                        case 'float':
1738                            $value = $this->getFloatValue($fields[$name]['Value']);
1739                            break;
1740                        case 'date':
1741                            $value = $this->getDateValue($fields[$name]['Value']);
1742                            break;
1743                        case 'time':
1744                            $value = $this->getTimeValue($fields[$name]['Value']);
1745                            break;
1746                        case 'timestamp':
1747                            $value = $this->getTimestampValue($fields[$name]['Value']);
1748                            break;
1749                        default:
1750                            return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
1751                                'no supported type for field "' . $name . '" specified'));
1752                    }
1753                } else {
1754                    $value = $fields[$name]['Value'];
1755                }
1756            }
1757            $values .= $value;
1758            if (isset($fields[$name]['Key']) && $fields[$name]['Key']) {
1759                if ($value === 'NULL') {
1760                    return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
1761                        'key values may not be NULL'));
1762                }
1763                $condition .= ($keys ? ' AND ' : ' WHERE ') . $name . '=' . $value;
1764                $keys++;
1765            }
1766        }
1767        if ($keys == 0) {
1768            return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
1769                'not specified which fields are keys'));
1770        }
1771        $in_transaction = $this->in_transaction;
1772        if (!$in_transaction && MDB::isError($result = $this->autoCommit(FALSE))) {
1773            return($result);
1774        }
1775        $success = $this->query("DELETE FROM $table$condition");
1776        if (!MDB::isError($success)) {
1777            $affected_rows = $this->affected_rows;
1778            $success = $this->query("INSERT INTO $table ($insert) VALUES ($values)");
1779            $affected_rows += $this->affected_rows;
1780        }
1781
1782        if (!$in_transaction) {
1783            if (!MDB::isError($success)) {
1784                if (!MDB::isError($success = $this->commit())
1785                    && !MDB::isError($success = $this->autoCommit(TRUE))
1786                    && isset($this->supported['AffectedRows'])
1787                ) {
1788                    $this->affected_rows = $affected_rows;
1789                }
1790            } else {
1791                $this->rollback();
1792                $this->autoCommit(TRUE);
1793            }
1794        }
1795        return($success);
1796    }
1797
1798    // }}}
1799    // {{{ prepareQuery()
1800
1801    /**
1802     * Prepares a query for multiple execution with execute().
1803     * With some database backends, this is emulated.
1804     * prepareQuery() requires a generic query as string like
1805     * 'INSERT INTO numbers VALUES(?,?,?)'. The ? are wildcards.
1806     * Types of wildcards:
1807     *    ? - a quoted scalar value, i.e. strings, integers
1808     *
1809     * @param string $ the query to prepare
1810     * @return mixed resource handle for the prepared query on success, a DB
1811     *        error on failure
1812     * @access public
1813     * @see execute
1814     */
1815    function prepareQuery($query)
1816    {
1817        $this->debug("PrepareQuery: $query");
1818        $positions = array();
1819        for($position = 0;
1820            $position < strlen($query) && is_integer($question = strpos($query, '?', $position));
1821        ) {
1822            if (is_integer($quote = strpos($query, "'", $position))
1823                && $quote < $question
1824            ) {
1825                if (!is_integer($end_quote = strpos($query, "'", $quote + 1))) {
1826                    return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
1827                        'Prepare query: query with an unterminated text string specified'));
1828                }
1829                switch ($this->escape_quotes) {
1830                    case '':
1831                    case "'":
1832                        $position = $end_quote + 1;
1833                        break;
1834                    default:
1835                        if ($end_quote == $quote + 1) {
1836                            $position = $end_quote + 1;
1837                        } else {
1838                            if ($query[$end_quote-1] == $this->escape_quotes) {
1839                                $position = $end_quote;
1840                            } else {
1841                                $position = $end_quote + 1;
1842                            }
1843                        }
1844                        break;
1845                }
1846            } else {
1847                $positions[] = $question;
1848                $position = $question + 1;
1849            }
1850        }
1851        $this->prepared_queries[] = array(
1852            'Query' => $query,
1853            'Positions' => $positions,
1854            'Values' => array(),
1855            'Types' => array()
1856            );
1857        $prepared_query = count($this->prepared_queries);
1858        if ($this->selected_row_limit > 0) {
1859            $this->prepared_queries[$prepared_query-1]['First'] = $this->first_selected_row;
1860            $this->prepared_queries[$prepared_query-1]['Limit'] = $this->selected_row_limit;
1861        }
1862        return($prepared_query);
1863    }
1864
1865    // }}}
1866    // {{{ _validatePreparedQuery()
1867
1868    /**
1869     * validate that a handle is infact a prepared query
1870     *
1871     * @param int $prepared_query argument is a handle that was returned by
1872     *       the function prepareQuery()
1873     * @access private
1874     */
1875    function _validatePreparedQuery($prepared_query)
1876    {
1877        if ($prepared_query < 1 || $prepared_query > count($this->prepared_queries)) {
1878            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
1879                'Validate prepared query: invalid prepared query'));
1880        }
1881        if (gettype($this->prepared_queries[$prepared_query-1]) != 'array') {
1882            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
1883                'Validate prepared query: prepared query was already freed'));
1884        }
1885        return(MDB_OK);
1886    }
1887
1888    // }}}
1889    // {{{ freePreparedQuery()
1890
1891    /**
1892     * Release resources allocated for the specified prepared query.
1893     *
1894     * @param int $prepared_query argument is a handle that was returned by
1895     *       the function prepareQuery()
1896     * @return mixed MDB_OK on success, a MDB error on failure
1897     * @access public
1898     */
1899    function freePreparedQuery($prepared_query)
1900    {
1901        $result = $this->_validatePreparedQuery($prepared_query);
1902        if (MDB::isError($result)) {
1903            return($result);
1904        }
1905        $this->prepared_queries[$prepared_query-1] = '';
1906        return(MDB_OK);
1907    }
1908
1909    // }}}
1910    // {{{ _executePreparedQuery()
1911
1912    /**
1913     * Execute a prepared query statement.
1914     *
1915     * @param int $prepared_query argument is a handle that was returned by
1916     *       the function prepareQuery()
1917     * @param string $query query to be executed
1918     * @param array $types array that contains the types of the columns in
1919     *       the result set
1920     * @return mixed a result handle or MDB_OK on success, a MDB error on failure
1921     * @access private
1922     */
1923    function _executePreparedQuery($prepared_query, $query, $types = NULL)
1924    {
1925        return($this->query($query, $types));
1926    }
1927
1928    // }}}
1929    // {{{ executeQuery()
1930
1931    /**
1932     * Execute a prepared query statement.
1933     *
1934     * @param int $prepared_query argument is a handle that was returned by
1935     *       the function prepareQuery()
1936     * @param array $types array that contains the types of the columns in the
1937     *       result set
1938     * @return mixed a result handle or MDB_OK on success, a MDB error on failure
1939     * @access public
1940     */
1941    function executeQuery($prepared_query, $types = NULL)
1942    {
1943        $result = $this->_validatePreparedQuery($prepared_query);
1944        if (MDB::isError($result)) {
1945            return($result);
1946        }
1947        $index = $prepared_query-1;
1948        $success = MDB_OK;
1949        $this->clobs[$prepared_query] = $this->blobs[$prepared_query] = array();
1950        $query = '';
1951        for($last_position = $position = 0;
1952            $position < count($this->prepared_queries[$index]['Positions']);
1953            $position++) {
1954            if (!isset($this->prepared_queries[$index]['Values'][$position])) {
1955                return($this->raiseError(MDB_ERROR_NEED_MORE_DATA, NULL, NULL,
1956                    'Execute query: it was not defined query argument '.($position + 1)));
1957            }
1958            $current_position = $this->prepared_queries[$index]['Positions'][$position];
1959            $query .= substr($this->prepared_queries[$index]['Query'], $last_position, $current_position - $last_position);
1960            $value = $this->prepared_queries[$index]['Values'][$position];
1961            if ($this->prepared_queries[$index]['IsNULL'][$position]) {
1962                $query .= $value;
1963            } else {
1964                switch ($this->prepared_queries[$index]['Types'][$position]) {
1965                    case 'clob':
1966                        if (!MDB::isError($success = $this->getClobValue($prepared_query, $position + 1, $value))) {
1967                            $this->clobs[$prepared_query][$position + 1] = $success;
1968                            $query .= $this->clobs[$prepared_query][$position + 1];
1969                        }
1970                        break;
1971                    case 'blob':
1972                        if (!MDB::isError($success = $this->getBlobValue($prepared_query, $position + 1, $value))) {
1973                            $this->blobs[$prepared_query][$position + 1] = $success;
1974                            $query .= $this->blobs[$prepared_query][$position + 1];
1975                        }
1976                        break;
1977                    default:
1978                        $query .= $value;
1979                        break;
1980                }
1981            }
1982            $last_position = $current_position + 1;
1983        }
1984        if (!MDB::isError($success)) {
1985            $query .= substr($this->prepared_queries[$index]['Query'], $last_position);
1986            if ($this->selected_row_limit > 0) {
1987                $this->prepared_queries[$index]['First'] = $this->first_selected_row;
1988                $this->prepared_queries[$index]['Limit'] = $this->selected_row_limit;
1989            }
1990            if (isset($this->prepared_queries[$index]['Limit'])
1991                && $this->prepared_queries[$index]['Limit'] > 0
1992            ) {
1993                $this->first_selected_row = $this->prepared_queries[$index]['First'];
1994                $this->selected_row_limit = $this->prepared_queries[$index]['Limit'];
1995            } else {
1996                $this->first_selected_row = $this->selected_row_limit = 0;
1997            }
1998            $success = $this->_executePreparedQuery($prepared_query, $query, $types);
1999        }
2000        for(reset($this->clobs[$prepared_query]), $clob = 0;
2001            $clob < count($this->clobs[$prepared_query]);
2002            $clob++, next($this->clobs[$prepared_query])) {
2003            $this->freeClobValue($prepared_query, key($this->clobs[$prepared_query]), $this->clobs[$prepared_query][key($this->clobs[$prepared_query])], $success);
2004        }
2005        unset($this->clobs[$prepared_query]);
2006        for(reset($this->blobs[$prepared_query]), $blob = 0;
2007            $blob < count($this->blobs[$prepared_query]);
2008            $blob++, next($this->blobs[$prepared_query])) {
2009            $this->freeBlobValue($prepared_query, key($this->blobs[$prepared_query]), $this->blobs[$prepared_query][key($this->blobs[$prepared_query])], $success);
2010        }
2011        unset($this->blobs[$prepared_query]);
2012        return($success);
2013    }
2014
2015    // }}}
2016    // {{{ execute()
2017
2018    /**
2019     * Executes a prepared SQL query
2020     * With execute() the generic query of prepare is assigned with the given
2021     * data array. The values of the array inserted into the query in the same
2022     * order like the array order
2023     *
2024     * @param resource $prepared_query query handle from prepare()
2025     * @param array $types array that contains the types of the columns in
2026     *        the result set
2027     * @param array $params numeric array containing the data to insert into
2028     *        the query
2029     * @param array $param_types array that contains the types of the values
2030     *        defined in $params
2031     * @return mixed a new result handle or a MDB_Error when fail
2032     * @access public
2033     * @see prepare()
2034     */
2035    function execute($prepared_query, $types = NULL, $params = FALSE, $param_types = NULL)
2036    {
2037        $this->setParamArray($prepared_query, $params, $param_types);
2038
2039        return($this->executeQuery($prepared_query, $types));
2040    }
2041
2042    // }}}
2043    // {{{ executeMultiple()
2044
2045    /**
2046     * This function does several execute() calls on the same statement handle.
2047     * $params must be an array indexed numerically from 0, one execute call is
2048     * done for every 'row' in the array.
2049     *
2050     * If an error occurs during execute(), executeMultiple() does not execute
2051     * the unfinished rows, but rather returns that error.
2052     *
2053     * @param resource $stmt query handle from prepare()
2054     * @param array $types array that contains the types of the columns in
2055     *        the result set
2056     * @param array $params numeric array containing the
2057     *        data to insert into the query
2058     * @param array $parAM_types array that contains the types of the values
2059     *        defined in $params
2060     * @return mixed a result handle or MDB_OK on success, a MDB error on failure
2061     * @access public
2062     * @see prepare(), execute()
2063     */
2064    function executeMultiple($prepared_query, $types = NULL, $params, $param_types = NULL)
2065    {
2066        for($i = 0, $j = count($params); $i < $j; $i++) {
2067            $result = $this->execute($prepared_query, $types, $params[$i], $param_types);
2068            if (MDB::isError($result)) {
2069                return($result);
2070            }
2071        }
2072        return(MDB_OK);
2073    }
2074
2075    // }}}
2076    // {{{ setParam()
2077
2078    /**
2079     * Set the value of a parameter of a prepared query.
2080     *
2081     * @param int $prepared_query argument is a handle that was returned
2082     *       by the function prepareQuery()
2083     * @param int $parameter the order number of the parameter in the query
2084     *       statement. The order number of the first parameter is 1.
2085     * @param string $type designation of the type of the parameter to be set.
2086     *       The designation of the currently supported types is as follows:
2087     *           text, boolean, integer, decimal, float, date, time, timestamp,
2088     *           clob, blob
2089     * @param mixed $value value that is meant to be assigned to specified
2090     *       parameter. The type of the value depends on the $type argument.
2091     * @param boolean $is_null flag that indicates whether whether the
2092     *       parameter is a NULL
2093     * @param string $field name of the field that is meant to be assigned
2094     *       with this parameter value when it is of type clob or blob
2095     * @return mixed MDB_OK on success, a MDB error on failure
2096     * @access public
2097     */
2098    function setParam($prepared_query, $parameter, $type, $value, $is_null = 0, $field = '')
2099    {
2100        $result = $this->_validatePreparedQuery($prepared_query);
2101        if (MDB::isError($result)) {
2102            return($result);
2103        }
2104        $index = $prepared_query - 1;
2105        if ($parameter < 1 || $parameter > count($this->prepared_queries[$index]['Positions'])) {
2106            return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
2107                'Query set: it was not specified a valid argument number'));
2108        }
2109        $this->prepared_queries[$index]['Values'][$parameter-1] = $value;
2110        $this->prepared_queries[$index]['Types'][$parameter-1] = $type;
2111        $this->prepared_queries[$index]['Fields'][$parameter-1] = $field;
2112        $this->prepared_queries[$index]['IsNULL'][$parameter-1] = $is_null;
2113        return(MDB_OK);
2114    }
2115
2116    // }}}
2117    // {{{ setParamArray()
2118
2119    /**
2120     * Set the values of multiple a parameter of a prepared query in bulk.
2121     *
2122     * @param int $prepared_query argument is a handle that was returned by
2123     *       the function prepareQuery()
2124     * @param array $params array thats specifies all necessary infromation
2125     *       for setParam() the array elements must use keys corresponding to
2126     *       the number of the position of the parameter.
2127     * @param array $types array thats specifies the types of the fields
2128     * @return mixed MDB_OK on success, a MDB error on failure
2129     * @access public
2130     * @see setParam()
2131     */
2132    function setParamArray($prepared_query, $params, $types = NULL)
2133    {
2134        if (is_array($types)) {
2135            if (count($params) != count($types)) {
2136                return $this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
2137                    'setParamArray: the number of given types ('.count($types).')'
2138                    .'is not corresponding to the number of given parameters ('.count($params).')');
2139            }
2140            for($i = 0, $j = count($params); $i < $j; ++$i) {
2141                switch ($types[$i]) {
2142                    case 'NULL':
2143                        $success = $this->setParam($prepared_query, $i + 1, $params[$i][0], 'NULL', 1, '');
2144                        break;
2145                    case 'text':
2146                        $success = $this->setParam($prepared_query, $i + 1, 'text', $this->getTextValue($params[$i]));
2147                        break;
2148                    case 'clob':
2149                        $success = $this->setParam($prepared_query, $i + 1, 'clob', $params[$i][0], 0, $params[$i][1]);
2150                        break;
2151                    case 'blob':
2152                        $success = $this->setParam($prepared_query, $i + 1, 'blob', $params[$i][0], 0, $params[$i][1]);
2153                        break;
2154                    case 'integer':
2155                        $success = $this->setParam($prepared_query, $i + 1, 'integer', $this->getIntegerValue($params[$i]));
2156                        break;
2157                    case 'boolean':
2158                        $success = $this->setParam($prepared_query, $i + 1, 'boolean', $this->getBooleanValue($params[$i]));
2159                        break;
2160                    case 'date':
2161                        $success = $this->setParam($prepared_query, $i + 1, 'date', $this->getDateValue($params[$i]));
2162                        break;
2163                    case 'timestamp':
2164                        $success = $this->setParam($prepared_query, $i + 1, 'timestamp', $this->getTimestampValue($params[$i]));
2165                        break;
2166                    case 'time':
2167                        $success = $this->setParam($prepared_query, $i + 1, 'time', $this->getTimeValue($params[$i]));
2168                        break;
2169                    case 'float':
2170                        $success = $this->setParam($prepared_query, $i + 1, 'float', $this->getFloatValue($params[$i]));
2171                        break;
2172                    case 'decimal':
2173                        $success = $this->setParam($prepared_query, $i + 1, 'decimal', $this->getDecimalValue($params[$i]));
2174                        break;
2175                    default:
2176                        $success = $this->setParam($prepared_query, $i + 1, 'text', $this->getTextValue($params[$i]));
2177                        break;
2178                }
2179                if (MDB::isError($success)) {
2180                    return($success);
2181                }
2182            }
2183        } else {
2184            for($i = 0, $j = count($params); $i < $j; ++$i) {
2185                $success = $this->setParam($prepared_query, $i + 1, 'text', $this->getTextValue($params[$i]));
2186                if (MDB::isError($success)) {
2187                    return($success);
2188                }
2189            }
2190        }
2191        return(MDB_OK);
2192    }
2193
2194    // }}}
2195    // {{{ setParamNull()
2196
2197    /**
2198     * Set the value of a parameter of a prepared query to NULL.
2199     *
2200     * @param int $prepared_query argument is a handle that was returned by
2201     *       the function prepareQuery()
2202     * @param int $parameter order number of the parameter in the query
2203     *       statement. The order number of the first parameter is 1.
2204     * @param string $type designation of the type of the parameter to be set.
2205     *       The designation of the currently supported types is list in the
2206     *       usage of the function  setParam()
2207     * @return mixed MDB_OK on success, a MDB error on failure
2208     * @access public
2209     * @see setParam()
2210     */
2211    function setParamNull($prepared_query, $parameter, $type)
2212    {
2213        return($this->setParam($prepared_query, $parameter, $type, 'NULL', 1, ''));
2214    }
2215
2216    // }}}
2217    // {{{ setParamText()
2218
2219    /**
2220     * Set a parameter of a prepared query with a text value.
2221     *
2222     * @param int $prepared_query argument is a handle that was returned by
2223     *       the function prepareQuery()
2224     * @param int $parameter order number of the parameter in the query
2225     *       statement. The order number of the first parameter is 1.
2226     * @param string $value text value that is meant to be assigned to
2227     *       specified parameter.
2228     * @return mixed MDB_OK on success, a MDB error on failure
2229     * @access public
2230     * @see setParam()
2231     */
2232    function setParamText($prepared_query, $parameter, $value)
2233    {
2234        return($this->setParam($prepared_query, $parameter, 'text', $this->getTextValue($value)));
2235    }
2236
2237    // }}}
2238    // {{{ setParamClob()
2239
2240    /**
2241     * Set a parameter of a prepared query with a character large object value.
2242     *
2243     * @param int $prepared_query argument is a handle that was returned by
2244     *       the function prepareQuery()
2245     * @param int $parameter order number of the parameter in the query
2246     *       statement. The order number of the first parameter is 1.
2247     * @param int $value handle of large object created with createLOB()
2248     *       function from which it will be read the data value that is meant
2249     *       to be assigned to specified parameter.
2250     * @param string $field name of the field of a INSERT or UPDATE query to
2251     *       which it will be assigned the value to specified parameter.
2252     * @return mixed MDB_OK on success, a MDB error on failure
2253     * @access public
2254     * @see setParam()
2255     */
2256    function setParamClob($prepared_query, $parameter, $value, $field)
2257    {
2258        return($this->setParam($prepared_query, $parameter, 'clob', $value, 0, $field));
2259    }
2260
2261    // }}}
2262    // {{{ setParamBlob()
2263
2264    /**
2265     * Set a parameter of a prepared query with a binary large object value.
2266     *
2267     * @param int $prepared_query argument is a handle that was returned by
2268     *       the function prepareQuery()
2269     * @param int $parameter order number of the parameter in the query
2270     *       statement. The order number of the first parameter is 1.
2271     * @param int $value handle of large object created with createLOB()
2272     *       function from which it will be read the data value that is meant
2273     *       to be assigned to specified parameter.
2274     * @param string $field name of the field of a INSERT or UPDATE query to
2275     *       which it will be assigned the value to specified parameter.
2276     * @return mixed MDB_OK on success, a MDB error on failure
2277     * @access public
2278     * @see setParam()
2279     */
2280    function setParamBlob($prepared_query, $parameter, $value, $field)
2281    {
2282        return($this->setParam($prepared_query, $parameter, 'blob', $value, 0, $field));
2283    }
2284
2285    // }}}
2286    // {{{ setParamInteger()
2287
2288    /**
2289     * Set a parameter of a prepared query with a text value.
2290     *
2291     * @param int $prepared_query argument is a handle that was returned by
2292     *       the function prepareQuery()
2293     * @param int $parameter order number of the parameter in the query
2294     *       statement. The order number of the first parameter is 1.
2295     * @param int $value an integer value that is meant to be assigned to
2296     *       specified parameter.
2297     * @return mixed MDB_OK on success, a MDB error on failure
2298     * @access public
2299     * @see setParam()
2300     */
2301    function setParamInteger($prepared_query, $parameter, $value)
2302    {
2303        return($this->setParam($prepared_query, $parameter, 'integer', $this->getIntegerValue($value)));
2304    }
2305
2306    // }}}
2307    // {{{ setParamBoolean()
2308
2309    /**
2310     * Set a parameter of a prepared query with a boolean value.
2311     *
2312     * @param int $prepared_query argument is a handle that was returned by
2313     *       the function prepareQuery()
2314     * @param int $parameter order number of the parameter in the query
2315     *       statement. The order number of the first parameter is 1.
2316     * @param boolean $value boolean value that is meant to be assigned to
2317     *       specified parameter.
2318     * @return mixed MDB_OK on success, a MDB error on failure
2319     * @access public
2320     * @see setParam()
2321     */
2322    function setParamBoolean($prepared_query, $parameter, $value)
2323    {
2324        return($this->setParam($prepared_query, $parameter, 'boolean', $this->getBooleanValue($value)));
2325    }
2326
2327    // }}}
2328    // {{{ setParamDate()
2329
2330    /**
2331     * Set a parameter of a prepared query with a date value.
2332     *
2333     * @param int $prepared_query argument is a handle that was returned by
2334     *       the function prepareQuery()
2335     * @param int $parameter order number of the parameter in the query
2336     *       statement. The order number of the first parameter is 1.
2337     * @param string $value date value that is meant to be assigned to
2338     *       specified parameter.
2339     * @return mixed MDB_OK on success, a MDB error on failure
2340     * @access public
2341     * @see setParam()
2342     */
2343    function setParamDate($prepared_query, $parameter, $value)
2344    {
2345        return($this->setParam($prepared_query, $parameter, 'date', $this->getDateValue($value)));
2346    }
2347
2348    // }}}
2349    // {{{ setParamTimestamp()
2350
2351    /**
2352     * Set a parameter of a prepared query with a time stamp value.
2353     *
2354     * @param int $prepared_query argument is a handle that was returned by
2355     *       the function prepareQuery()
2356     * @param int $parameter order number of the parameter in the query
2357     *       statement. The order number of the first parameter is 1.
2358     * @param string $value time stamp value that is meant to be assigned to
2359     *       specified parameter.
2360     * @return mixed MDB_OK on success, a MDB error on failure
2361     * @access public
2362     * @see setParam()
2363     */
2364    function setParamTimestamp($prepared_query, $parameter, $value)
2365    {
2366        return($this->setParam($prepared_query, $parameter, 'timestamp', $this->getTimestampValue($value)));
2367    }
2368
2369    // }}}
2370    // {{{ setParamTime()
2371
2372    /**
2373     * Set a parameter of a prepared query with a time value.
2374     *
2375     * @param int $prepared_query argument is a handle that was returned by
2376     *       the function prepareQuery()
2377     * @param int $parameter order number of the parameter in the query
2378     *       statement. The order number of the first parameter is 1.
2379     * @param string $value time value that is meant to be assigned to
2380     *       specified parameter.
2381     * @return mixed MDB_OK on success, a MDB error on failure
2382     * @access public
2383     * @see setParam()
2384     */
2385    function setParamTime($prepared_query, $parameter, $value)
2386    {
2387        return($this->setParam($prepared_query, $parameter, 'time', $this->getTimeValue($value)));
2388    }
2389
2390    // }}}
2391    // {{{ setParamFloat()
2392
2393    /**
2394     * Set a parameter of a prepared query with a float value.
2395     *
2396     * @param int $prepared_query argument is a handle that was returned by
2397     *       the function prepareQuery()
2398     * @param int $parameter order number of the parameter in the query
2399     *       statement. The order number of the first parameter is 1.
2400     * @param string $value float value that is meant to be assigned to
2401     *       specified parameter.
2402     * @return mixed MDB_OK on success, a MDB error on failure
2403     * @access public
2404     * @see setParam()
2405     */
2406    function setParamFloat($prepared_query, $parameter, $value)
2407    {
2408        return($this->setParam($prepared_query, $parameter, 'float', $this->getFloatValue($value)));
2409    }
2410
2411    // }}}
2412    // {{{ setParamDecimal()
2413
2414    /**
2415     * Set a parameter of a prepared query with a decimal value.
2416     *
2417     * @param int $prepared_query argument is a handle that was returned by
2418     *       the function prepareQuery()
2419     * @param int $parameter order number of the parameter in the query
2420     *       statement. The order number of the first parameter is 1.
2421     * @param string $value decimal value that is meant to be assigned to
2422     *       specified parameter.
2423     * @return mixed MDB_OK on success, a MDB error on failure
2424     * @access public
2425     * @see setParam()
2426     */
2427    function setParamDecimal($prepared_query, $parameter, $value)
2428    {
2429        return($this->setParam($prepared_query, $parameter, 'decimal', $this->getDecimalValue($value)));
2430    }
2431
2432    // }}}
2433    // {{{ setResultTypes()
2434
2435    /**
2436     * Define the list of types to be associated with the columns of a given
2437     * result set.
2438     *
2439     * This function may be called before invoking fetchInto(), fetchOne(),
2440     * fetchRow(), fetchCol() and fetchAll() so that the necessary data type
2441     * conversions are performed on the data to be retrieved by them. If this
2442     * function is not called, the type of all result set columns is assumed
2443     * to be text, thus leading to not perform any conversions.
2444     *
2445     * @param resource $result result identifier
2446     * @param string $types array variable that lists the
2447     *       data types to be expected in the result set columns. If this array
2448     *       contains less types than the number of columns that are returned
2449     *       in the result set, the remaining columns are assumed to be of the
2450     *       type text. Currently, the types clob and blob are not fully
2451     *       supported.
2452     * @return mixed MDB_OK on success, a MDB error on failure
2453     * @access public
2454     */
2455    function setResultTypes($result, $types)
2456    {
2457        $result_value = intval($result);
2458        if (isset($this->result_types[$result_value])) {
2459            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
2460                'Set result types: attempted to redefine the types of the columns of a result set'));
2461        }
2462        $columns = $this->numCols($result);
2463        if (MDB::isError($columns)) {
2464            return($columns);
2465        }
2466        if ($columns < count($types)) {
2467            return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
2468                'Set result types: it were specified more result types (' . count($types) . ') than result columns (' . $columns . ')'));
2469        }
2470        $valid_types = array(
2471            'text'      => MDB_TYPE_TEXT,
2472            'boolean'   => MDB_TYPE_BOOLEAN,
2473            'integer'   => MDB_TYPE_INTEGER,
2474            'decimal'   => MDB_TYPE_DECIMAL,
2475            'float'     => MDB_TYPE_FLOAT,
2476            'date'      => MDB_TYPE_DATE,
2477            'time'      => MDB_TYPE_TIME,
2478            'timestamp' => MDB_TYPE_TIMESTAMP,
2479            'clob'      => MDB_TYPE_CLOB,
2480            'blob'      => MDB_TYPE_BLOB
2481        );
2482        for($column = 0; $column < count($types); $column++) {
2483            if (!isset($valid_types[$types[$column]])) {
2484                return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2485                    'Set result types: ' . $types[$column] . ' is not a supported column type'));
2486            }
2487            $this->result_types[$result_value][$column] = $valid_types[$types[$column]];
2488        }
2489        while ($column < $columns) {
2490            $this->result_types[$result_value][$column] = MDB_TYPE_TEXT;
2491            $column++;
2492        }
2493        return(MDB_OK);
2494    }
2495
2496    // }}}
2497    // {{{ affectedRows()
2498
2499    /**
2500     * returns the affected rows of a query
2501     *
2502     * @return mixed MDB_Error or number of rows
2503     * @access public
2504     */
2505    function affectedRows()
2506    {
2507        if ($this->affected_rows == -1) {
2508            return($this->raiseError(MDB_ERROR_NEED_MORE_DATA));
2509        }
2510        return($this->affected_rows);
2511    }
2512
2513    // }}}
2514    // {{{ getColumnNames()
2515
2516    /**
2517     * Retrieve the names of columns returned by the DBMS in a query result.
2518     *
2519     * @param resource $result result identifier
2520     * @return mixed associative array variable
2521     *       that holds the names of columns. The indexes of the array are
2522     *       the column names mapped to lower case and the values are the
2523     *       respective numbers of the columns starting from 0. Some DBMS may
2524     *       not return any columns when the result set does not contain any
2525     *       rows.
2526     *      a MDB error on failure
2527     * @access public
2528     */
2529    function getColumnNames($result)
2530    {
2531        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2532            'Get column names: obtaining result column names is not implemented'));
2533    }
2534
2535    // }}}
2536    // {{{ numCols()
2537
2538    /**
2539     * Count the number of columns returned by the DBMS in a query result.
2540     *
2541     * @param resource $result result identifier
2542     * @return mixed integer value with the number of columns, a MDB error
2543     *       on failure
2544     * @access public
2545     */
2546    function numCols($result)
2547    {
2548        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2549            'Number of columns: obtaining the number of result columns is not implemented'));
2550    }
2551
2552    // }}}
2553    // {{{ endOfResult()
2554
2555    /**
2556     * check if the end of the result set has been reached
2557     *
2558     * @param resource $result result identifier
2559     * @return mixed TRUE or FALSE on sucess, a MDB error on failure
2560     * @access public
2561     */
2562    function endOfResult($result)
2563    {
2564        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2565            'End of result: end of result method not implemented'));
2566    }
2567
2568    // }}}
2569    // {{{ setFetchMode()
2570
2571    /**
2572     * Sets which fetch mode should be used by default on queries
2573     * on this connection.
2574     *
2575     * @param integer $fetchmode MDB_FETCHMODE_ORDERED or MDB_FETCHMODE_ASSOC,
2576     *       possibly bit-wise OR'ed with MDB_FETCHMODE_FLIPPED.
2577     * @access public
2578     * @see MDB_FETCHMODE_ORDERED
2579     * @see MDB_FETCHMODE_ASSOC
2580     * @see MDB_FETCHMODE_FLIPPED
2581     */
2582    function setFetchMode($fetchmode)
2583    {
2584        switch ($fetchmode) {
2585            case MDB_FETCHMODE_ORDERED:
2586            case MDB_FETCHMODE_ASSOC:
2587                $this->fetchmode = $fetchmode;
2588                break;
2589            default:
2590                return($this->raiseError('invalid fetchmode mode'));
2591        }
2592    }
2593
2594    // }}}
2595    // {{{ fetch()
2596
2597    /**
2598     * fetch value from a result set
2599     *
2600     * @param resource $result result identifier
2601     * @param int $row number of the row where the data can be found
2602     * @param int $field field number where the data can be found
2603     * @return mixed string on success, a MDB error on failure
2604     * @access public
2605     */
2606    function fetch($result, $row, $field)
2607    {
2608        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2609            'Fetch: fetch result method not implemented'));
2610    }
2611
2612    // }}}
2613    // {{{ fetchLob()
2614
2615    /**
2616     * fetch a lob value from a result set
2617     *
2618     * @param resource $result result identifier
2619     * @param int $row number of the row where the data can be found
2620     * @param int $field field number where the data can be found
2621     * @return mixed string on success, a MDB error on failure
2622     * @access public
2623     */
2624    function fetchLob($result, $row, $field)
2625    {
2626        $lob = count($this->lobs) + 1;
2627        $this->lobs[$lob] = array(
2628            'Result' => $result,
2629            'Row' => $row,
2630            'Field' => $field,
2631            'Position' => 0
2632        );
2633        $dst_lob = array(
2634            'Database' => $this,
2635            'Error' => '',
2636            'Type' => 'resultlob',
2637            'ResultLOB' => $lob
2638        );
2639        if (MDB::isError($lob = $this->createLob($dst_lob))) {
2640            return($this->raiseError(MDB_ERROR, NULL, NULL,
2641                'Fetch LOB result: ' . $dst_lob['Error']));
2642        }
2643        return($lob);
2644    }
2645
2646    // }}}
2647    // {{{ _retrieveLob()
2648
2649    /**
2650     * fetch a float value from a result set
2651     *
2652     * @param int $lob handle to a lob created by the createLob() function
2653     * @return mixed MDB_OK on success, a MDB error on failure
2654     * @access private
2655     */
2656    function _retrieveLob($lob)
2657    {
2658        if (!isset($this->lobs[$lob])) {
2659            return($this->raiseError(MDB_ERROR_NEED_MORE_DATA, NULL, NULL,
2660                'Fetch LOB result: it was not specified a valid lob'));
2661        }
2662        if (!isset($this->lobs[$lob]['Value'])) {
2663            $this->lobs[$lob]['Value'] = $this->fetch($this->lobs[$lob]['Result'], $this->lobs[$lob]['Row'], $this->lobs[$lob]['Field']);
2664        }
2665        return(MDB_OK);
2666    }
2667
2668    // }}}
2669    // {{{ endOfResultLob()
2670
2671    /**
2672     * Determine whether it was reached the end of the large object and
2673     * therefore there is no more data to be read for the its input stream.
2674     *
2675     * @param int $lob handle to a lob created by the createLob() function
2676     * @return mixed TRUE or FALSE on success, a MDB error on failure
2677     * @access public
2678     */
2679    function endOfResultLob($lob)
2680    {
2681        $result = $this->_retrieveLob($lob);
2682        if (MDB::isError($result)) {
2683            return($result);
2684        }
2685        return($this->lobs[$lob]['Position'] >= strlen($this->lobs[$lob]['Value']));
2686    }
2687
2688    // }}}
2689    // {{{ _readResultLob()
2690
2691    /**
2692     * Read data from large object input stream.
2693     *
2694     * @param int $lob handle to a lob created by the createLob() function
2695     * @param blob $data reference to a variable that will hold data to be
2696     *       read from the large object input stream
2697     * @param int $length integer value that indicates the largest ammount of
2698     *       data to be read from the large object input stream.
2699     * @return mixed length on success, a MDB error on failure
2700     * @access private
2701     */
2702    function _readResultLob($lob, &$data, $length)
2703    {
2704        $result = $this->_retrieveLob($lob);
2705        if (MDB::isError($result)) {
2706            return($result);
2707        }
2708        $length = min($length, strlen($this->lobs[$lob]['Value']) - $this->lobs[$lob]['Position']);
2709        $data = substr($this->lobs[$lob]['Value'], $this->lobs[$lob]['Position'], $length);
2710        $this->lobs[$lob]['Position'] += $length;
2711        return($length);
2712    }
2713
2714    // }}}
2715    // {{{ _destroyResultLob()
2716
2717    /**
2718     * Free any resources allocated during the lifetime of the large object
2719     * handler object.
2720     *
2721     * @param int $lob handle to a lob created by the createLob() function
2722     * @access private
2723     */
2724    function _destroyResultLob($lob)
2725    {
2726        if (isset($this->lobs[$lob])) {
2727            $this->lobs[$lob] = '';
2728        }
2729    }
2730
2731    // }}}
2732    // {{{ fetchClob()
2733
2734    /**
2735     * fetch a clob value from a result set
2736     *
2737     * @param resource $result result identifier
2738     * @param int $row number of the row where the data can be found
2739     * @param int $field field number where the data can be found
2740     * @return mixed content of the specified data cell, a MDB error on failure,
2741     *        a MDB error on failure
2742     * @access public
2743     */
2744    function fetchClob($result, $row, $field)
2745    {
2746        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2747            'fetch clob result method is not implemented'));
2748    }
2749
2750    // }}}
2751    // {{{ fetchBlob()
2752
2753    /**
2754     * fetch a blob value from a result set
2755     *
2756     * @param resource $result result identifier
2757     * @param int $row number of the row where the data can be found
2758     * @param int $field field number where the data can be found
2759     * @return mixed content of the specified data cell, a MDB error on failure
2760     * @access public
2761     */
2762    function fetchBlob($result, $row, $field)
2763    {
2764        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
2765            'fetch blob result method is not implemented'));
2766    }
2767
2768    // }}}
2769    // {{{ resultIsNull()
2770
2771    /**
2772     * Determine whether the value of a query result located in given row and
2773     *    field is a NULL.
2774     *
2775     * @param resource $result result identifier
2776     * @param int $row number of the row where the data can be found
2777     * @param int $field field number where the data can be found
2778     * @return mixed TRUE or FALSE on success, a MDB error on failure
2779     * @access public
2780     */
2781    function resultIsNull($result, $row, $field)
2782    {
2783        $result = $this->fetch($result, $row, $field);
2784        if (MDB::isError($result)) {
2785            return($result);
2786        }
2787        return(!isset($result));
2788    }
2789
2790    // }}}
2791    // {{{ _baseConvertResult()
2792
2793    /**
2794     * general type conversion method
2795     *
2796     * @param mixed $value refernce to a value to be converted
2797     * @param int $type constant that specifies which type to convert to
2798     * @return object a MDB error on failure
2799     * @access private
2800     */
2801    function _baseConvertResult($value, $type)
2802    {
2803        switch ($type) {
2804            case MDB_TYPE_TEXT:
2805                return($value);
2806            case MDB_TYPE_BLOB:
2807                return($value);
2808            case MDB_TYPE_CLOB:
2809                return($value);
2810            case MDB_TYPE_INTEGER:
2811                return(intval($value));
2812            case MDB_TYPE_BOOLEAN:
2813                return ($value == 'Y') ? TRUE : FALSE;
2814            case MDB_TYPE_DECIMAL:
2815                return($value);
2816            case MDB_TYPE_FLOAT:
2817                return(doubleval($value));
2818            case MDB_TYPE_DATE:
2819                return($value);
2820            case MDB_TYPE_TIME:
2821                return($value);
2822            case MDB_TYPE_TIMESTAMP:
2823                return($value);
2824            case MDB_TYPE_CLOB:
2825                return($value);
2826            case MDB_TYPE_BLOB:
2827                return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
2828                    'BaseConvertResult: attempt to convert result value to an unsupported type ' . $type));
2829            default:
2830                return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
2831                    'BaseConvertResult: attempt to convert result value to an unknown type ' . $type));
2832        }
2833    }
2834
2835    // }}}
2836    // {{{ convertResult()
2837
2838    /**
2839     * convert a value to a RDBMS indepdenant MDB type
2840     *
2841     * @param mixed $value value to be converted
2842     * @param int $type constant that specifies which type to convert to
2843     * @return mixed converted value or a MDB error on failure
2844     * @access public
2845     */
2846    function convertResult($value, $type)
2847    {
2848        return($this->_baseConvertResult($value, $type));
2849    }
2850
2851    // }}}
2852    // {{{ convertResultRow()
2853
2854    /**
2855     * convert a result row
2856     *
2857     * @param resource $result result identifier
2858     * @param array $row array with data
2859     * @return mixed MDB_OK on success,  a MDB error on failure
2860     * @access public
2861     */
2862    function convertResultRow($result, $row)
2863    {
2864        $result_value = intval($result);
2865        if (isset($this->result_types[$result_value])) {
2866            $current_column = -1;
2867            foreach($row as $key => $column) {
2868                ++$current_column;
2869                if (!isset($this->result_types[$result_value][$current_column])
2870                   ||!isset($column)
2871                ) {
2872                    continue;
2873                }
2874                switch ($type = $this->result_types[$result_value][$current_column]) {
2875                    case MDB_TYPE_TEXT:
2876                    case MDB_TYPE_BLOB:
2877                    case MDB_TYPE_CLOB:
2878                        break;
2879                    case MDB_TYPE_INTEGER:
2880                        $row[$key] = intval($row[$key]);
2881                        break;
2882                    default:
2883                        $value = $this->convertResult($row[$key], $type);
2884                        if (MDB::isError($value)) {
2885                            return $value;
2886                        }
2887                        $row[$key] = $value;
2888                        break;
2889                }
2890            }
2891        }
2892        return ($row);
2893    }
2894
2895    // }}}
2896    // {{{ fetchDate()
2897
2898    /**
2899     * fetch a date value from a result set
2900     *
2901     * @param resource $result result identifier
2902     * @param int $row number of the row where the data can be found
2903     * @param int $field field number where the data can be found
2904     * @return mixed content of the specified data cell, a MDB error on failure
2905     * @access public
2906     */
2907    function fetchDate($result, $row, $field)
2908    {
2909        $value = $this->fetch($result, $row, $field);
2910        return($this->convertResult($value, MDB_TYPE_DATE));
2911    }
2912
2913    // }}}
2914    // {{{ fetchTimestamp()
2915
2916    /**
2917     * fetch a timestamp value from a result set
2918     *
2919     * @param resource $result result identifier
2920     * @param int $row number of the row where the data can be found
2921     * @param int $field field number where the data can be found
2922     * @return mixed content of the specified data cell, a MDB error on failure
2923     * @access public
2924     */
2925    function fetchTimestamp($result, $row, $field)
2926    {
2927        $value = $this->fetch($result, $row, $field);
2928        return($this->convertResult($value, MDB_TYPE_TIMESTAMP));
2929    }
2930
2931    // }}}
2932    // {{{ fetchTime()
2933
2934    /**
2935     * fetch a time value from a result set
2936     *
2937     * @param resource $result result identifier
2938     * @param int $row number of the row where the data can be found
2939     * @param int $field field number where the data can be found
2940     * @return mixed content of the specified data cell, a MDB error on failure
2941     * @access public
2942     */
2943    function fetchTime($result, $row, $field)
2944    {
2945        $value = $this->fetch($result, $row, $field);
2946        return($this->convertResult($value, MDB_TYPE_TIME));
2947    }
2948
2949    // }}}
2950    // {{{ fetchBoolean()
2951
2952    /**
2953     * fetch a boolean value from a result set
2954     *
2955     * @param resource $result result identifier
2956     * @param int $row number of the row where the data can be found
2957     * @param int $field field number where the data can be found
2958     * @return mixed content of the specified data cell, a MDB error on failure
2959     * @access public
2960     */
2961    function fetchBoolean($result, $row, $field)
2962    {
2963        $value = $this->fetch($result, $row, $field);
2964        return($this->convertResult($value, MDB_TYPE_BOOLEAN));
2965    }
2966
2967    // }}}
2968    // {{{ fetchFloat()
2969
2970    /**
2971     * fetch a float value from a result set
2972     *
2973     * @param resource $result result identifier
2974     * @param int $row number of the row where the data can be found
2975     * @param int $field field number where the data can be found
2976     * @return mixed content of the specified data cell, a MDB error on failure
2977     * @access public
2978     */
2979    function fetchFloat($result, $row, $field)
2980    {
2981        $value = $this->fetch($result, $row, $field);
2982        return($this->convertResult($value, MDB_TYPE_FLOAT));
2983    }
2984
2985    // }}}
2986    // {{{ fetchDecimal()
2987
2988    /**
2989     * fetch a decimal value from a result set
2990     *
2991     * @param resource $result result identifier
2992     * @param int $row number of the row where the data can be found
2993     * @param int $field field number where the data can be found
2994     * @return mixed content of the specified data cell, a MDB error on failure
2995     * @access public
2996     */
2997    function fetchDecimal($result, $row, $field)
2998    {
2999        $value = $this->fetch($result, $row, $field);
3000        return($this->convertResult($value, MDB_TYPE_DECIMAL));
3001    }
3002
3003    // }}}
3004    // {{{ numRows()
3005
3006    /**
3007     * returns the number of rows in a result object
3008     *
3009     * @param ressource $result a valid result ressouce pointer
3010     * @return mixed MDB_Error or the number of rows
3011     * @access public
3012     */
3013    function numRows($result)
3014    {
3015        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'Num Rows: number of rows method not implemented'));
3016    }
3017
3018    // }}}
3019    // {{{ freeResult()
3020
3021    /**
3022     * Free the internal resources associated with $result.
3023     *
3024     * @param  $result result identifier
3025     * @return boolean TRUE on success, FALSE if $result is invalid
3026     * @access public
3027     */
3028    function freeResult($result)
3029    {
3030        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'Free Result: free result method not implemented'));
3031    }
3032
3033    // }}}
3034    // {{{ getIntegerDeclaration()
3035
3036    /**
3037     * Obtain DBMS specific SQL code portion needed to declare an integer type
3038     * field to be used in statements like CREATE TABLE.
3039     *
3040     * @param string $name name the field to be declared.
3041     * @param string $field associative array with the name of the properties
3042     *       of the field being declared as array indexes. Currently, the types
3043     *       of supported field properties are as follows:
3044     *
3045     *       unsigned
3046     *           Boolean flag that indicates whether the field should be
3047     *           declared as unsigned integer if possible.
3048     *
3049     *       default
3050     *           Integer value to be used as default for this field.
3051     *
3052     *       notnull
3053     *           Boolean flag that indicates whether this field is constrained
3054     *           to not be set to NULL.
3055     * @return string DBMS specific SQL code portion that should be used to
3056     *       declare the specified field.
3057     * @access public
3058     */
3059    function getIntegerDeclaration($name, $field)
3060    {
3061        if (isset($field['unsigned'])) {
3062            $this->warnings[] = "unsigned integer field \"$name\" is being
3063                declared as signed integer";
3064        }
3065        return("$name INT" . (isset($field['default']) ? ' DEFAULT ' . $field['default'] : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3066    }
3067
3068    // }}}
3069    // {{{ getTextDeclaration()
3070
3071    /**
3072     * Obtain DBMS specific SQL code portion needed to declare an text type
3073     * field to be used in statements like CREATE TABLE.
3074     *
3075     * @param string $name name the field to be declared.
3076     * @param string $field associative array with the name of the properties
3077     *       of the field being declared as array indexes. Currently, the types
3078     *       of supported field properties are as follows:
3079     *
3080     *       length
3081     *           Integer value that determines the maximum length of the text
3082     *           field. If this argument is missing the field should be
3083     *           declared to have the longest length allowed by the DBMS.
3084     *
3085     *       default
3086     *           Text value to be used as default for this field.
3087     *
3088     *       notnull
3089     *           Boolean flag that indicates whether this field is constrained
3090     *           to not be set to NULL.
3091     * @return string DBMS specific SQL code portion that should be used to
3092     *       declare the specified field.
3093     * @access public
3094     */
3095    function getTextDeclaration($name, $field)
3096    {
3097        return((isset($field['length']) ? "$name CHAR (" . $field['length'] . ')' : "$name TEXT") . (isset($field['default']) ? ' DEFAULT ' . $this->getTextValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3098    }
3099
3100    // }}}
3101    // {{{ getClobDeclaration()
3102
3103    /**
3104     * Obtain DBMS specific SQL code portion needed to declare an character
3105     * large object type field to be used in statements like CREATE TABLE.
3106     *
3107     * @param string $name name the field to be declared.
3108     * @param string $field associative array with the name of the properties
3109     *       of the field being declared as array indexes. Currently, the types
3110     *       of supported field properties are as follows:
3111     *
3112     *       length
3113     *           Integer value that determines the maximum length of the large
3114     *           object field. If this argument is missing the field should be
3115     *           declared to have the longest length allowed by the DBMS.
3116     *
3117     *       notnull
3118     *           Boolean flag that indicates whether this field is constrained
3119     *           to not be set to NULL.
3120     * @return string DBMS specific SQL code portion that should be used to
3121     *       declare the specified field.
3122     * @access public
3123     */
3124    function getClobDeclaration($name, $field)
3125    {
3126        return((isset($field['length']) ? "$name CHAR (" . $field['length'] . ')' : "$name TEXT") . (isset($field['default']) ? ' DEFAULT ' . $this->getTextValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3127    }
3128
3129    // }}}
3130    // {{{ getBlobDeclaration()
3131
3132    /**
3133     * Obtain DBMS specific SQL code portion needed to declare an binary large
3134     * object type field to be used in statements like CREATE TABLE.
3135     *
3136     * @param string $name name the field to be declared.
3137     * @param string $field associative array with the name of the properties
3138     *       of the field being declared as array indexes. Currently, the types
3139     *       of supported field properties are as follows:
3140     *
3141     *       length
3142     *           Integer value that determines the maximum length of the large
3143     *           object field. If this argument is missing the field should be
3144     *           declared to have the longest length allowed by the DBMS.
3145     *
3146     *       notnull
3147     *           Boolean flag that indicates whether this field is constrained
3148     *           to not be set to NULL.
3149     * @return string DBMS specific SQL code portion that should be used to
3150     *       declare the specified field.
3151     * @access public
3152     */
3153    function getBlobDeclaration($name, $field)
3154    {
3155        return((isset($field['length']) ? "$name CHAR (" . $field['length'] . ')' : "$name TEXT") . (isset($field['default']) ? ' DEFAULT ' . $this->getTextValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3156    }
3157
3158    // }}}
3159    // {{{ getBooleanDeclaration()
3160
3161    /**
3162     * Obtain DBMS specific SQL code portion needed to declare a boolean type
3163     * field to be used in statements like CREATE TABLE.
3164     *
3165     * @param string $name name the field to be declared.
3166     * @param string $field associative array with the name of the properties
3167     *       of the field being declared as array indexes. Currently, the types
3168     *       of supported field properties are as follows:
3169     *
3170     *       default
3171     *           Boolean value to be used as default for this field.
3172     *
3173     *       notnullL
3174     *           Boolean flag that indicates whether this field is constrained
3175     *           to not be set to NULL.
3176     * @return string DBMS specific SQL code portion that should be used to
3177     *       declare the specified field.
3178     * @access public
3179     */
3180    function getBooleanDeclaration($name, $field)
3181    {
3182        return("$name CHAR (1)" . (isset($field['default']) ? ' DEFAULT ' . $this->getBooleanValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3183    }
3184
3185    // }}}
3186    // {{{ getDateDeclaration()
3187
3188    /**
3189     * Obtain DBMS specific SQL code portion needed to declare a date type
3190     * field to be used in statements like CREATE TABLE.
3191     *
3192     * @param string $name name the field to be declared.
3193     * @param string $field associative array with the name of the properties
3194     *       of the field being declared as array indexes. Currently, the types
3195     *       of supported field properties are as follows:
3196     *
3197     *       default
3198     *           Date value to be used as default for this field.
3199     *
3200     *       notnull
3201     *           Boolean flag that indicates whether this field is constrained
3202     *           to not be set to NULL.
3203     * @return string DBMS specific SQL code portion that should be used to
3204     *       declare the specified field.
3205     * @access public
3206     */
3207    function getDateDeclaration($name, $field)
3208    {
3209        return("$name CHAR (" . strlen("YYYY-MM-DD") . ")" . (isset($field['default']) ? ' DEFAULT ' . $this->getDateValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3210    }
3211
3212    // }}}
3213    // {{{ getTimestampDeclaration()
3214
3215    /**
3216     * Obtain DBMS specific SQL code portion needed to declare a timestamp
3217     * field to be used in statements like CREATE TABLE.
3218     *
3219     * @param string $name name the field to be declared.
3220     * @param string $field associative array with the name of the properties
3221     *       of the field being declared as array indexes. Currently, the types
3222     *       of supported field properties are as follows:
3223     *
3224     *       default
3225     *           Timestamp value to be used as default for this field.
3226     *
3227     *       notnull
3228     *           Boolean flag that indicates whether this field is constrained
3229     *           to not be set to NULL.
3230     * @return string DBMS specific SQL code portion that should be used to
3231     *       declare the specified field.
3232     * @access public
3233     */
3234    function getTimestampDeclaration($name, $field)
3235    {
3236        return("$name CHAR (" . strlen("YYYY-MM-DD HH:MM:SS") . ")" . (isset($field['default']) ? ' DEFAULT ' . $this->getTimestampValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3237    }
3238
3239    // }}}
3240    // {{{ getTimeDeclaration()
3241
3242    /**
3243     * Obtain DBMS specific SQL code portion needed to declare a time
3244     * field to be used in statements like CREATE TABLE.
3245     *
3246     * @param string $name name the field to be declared.
3247     * @param string $field associative array with the name of the properties
3248     *       of the field being declared as array indexes. Currently, the types
3249     *       of supported field properties are as follows:
3250     *
3251     *       default
3252     *           Time value to be used as default for this field.
3253     *
3254     *       notnull
3255     *           Boolean flag that indicates whether this field is constrained
3256     *           to not be set to NULL.
3257     * @return string DBMS specific SQL code portion that should be used to
3258     *       declare the specified field.
3259     * @access public
3260     */
3261    function getTimeDeclaration($name, $field)
3262    {
3263        return("$name CHAR (" . strlen("HH:MM:SS") . ")" . (isset($field['default']) ? ' DEFAULT ' . $this->getTimeValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3264    }
3265
3266    // }}}
3267    // {{{ getFloatDeclaration()
3268
3269    /**
3270     * Obtain DBMS specific SQL code portion needed to declare a float type
3271     * field to be used in statements like CREATE TABLE.
3272     *
3273     * @param string $name name the field to be declared.
3274     * @param string $field associative array with the name of the properties
3275     *       of the field being declared as array indexes. Currently, the types
3276     *       of supported field properties are as follows:
3277     *
3278     *       default
3279     *           Float value to be used as default for this field.
3280     *
3281     *       notnull
3282     *           Boolean flag that indicates whether this field is constrained
3283     *           to not be set to NULL.
3284     * @return string DBMS specific SQL code portion that should be used to
3285     *       declare the specified field.
3286     * @access public
3287     */
3288    function getFloatDeclaration($name, $field)
3289    {
3290        return("$name TEXT " . (isset($field['default']) ? ' DEFAULT ' . $this->getFloatValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3291    }
3292
3293    // }}}
3294    // {{{ getDecimalDeclaration()
3295
3296    /**
3297     * Obtain DBMS specific SQL code portion needed to declare a decimal type
3298     * field to be used in statements like CREATE TABLE.
3299     *
3300     * @param string $name name the field to be declared.
3301     * @param string $field associative array with the name of the properties
3302     *       of the field being declared as array indexes. Currently, the types
3303     *       of supported field properties are as follows:
3304     *
3305     *       default
3306     *           Decimal value to be used as default for this field.
3307     *
3308     *       notnull
3309     *           Boolean flag that indicates whether this field is constrained
3310     *           to not be set to NULL.
3311     * @return string DBMS specific SQL code portion that should be used to
3312     *       declare the specified field.
3313     * @access public
3314     */
3315    function getDecimalDeclaration($name, $field)
3316    {
3317        return("$name TEXT " . (isset($field['default']) ? ' DEFAULT ' . $this->getDecimalValue($field['default']) : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
3318    }
3319
3320    // }}}
3321    // {{{ getIntegerValue()
3322
3323    /**
3324     * Convert a text value into a DBMS specific format that is suitable to
3325     * compose query statements.
3326     *
3327     * @param string $value text string value that is intended to be converted.
3328     * @return string text string that represents the given argument value in
3329     *       a DBMS specific format.
3330     * @access public
3331     */
3332    function getIntegerValue($value)
3333    {
3334        return(($value === NULL) ? 'NULL' : (int)$value);
3335    }
3336
3337    // }}}
3338    // {{{ getTextValue()
3339
3340    /**
3341     * Convert a text value into a DBMS specific format that is suitable to
3342     * compose query statements.
3343     *
3344     * @param string $value text string value that is intended to be converted.
3345     * @return string text string that already contains any DBMS specific
3346     *       escaped character sequences.
3347     * @access public
3348     */
3349    function getTextValue($value)
3350    {
3351        return(($value === NULL) ? 'NULL' : "'".$this->_quote($value)."'");
3352    }
3353
3354    // }}}
3355    // {{{ getClobValue()
3356
3357    /**
3358     * Convert a text value into a DBMS specific format that is suitable to
3359     * compose query statements.
3360     *
3361     * @param resource $prepared_query query handle from prepare()
3362     * @param  $parameter
3363     * @param  $clob
3364     * @return string text string that represents the given argument value in
3365     *       a DBMS specific format.
3366     * @access public
3367     */
3368    function getClobValue($prepared_query, $parameter, $clob)
3369    {
3370        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
3371            'Get CLOB field value: prepared queries with values of type "clob" are not yet supported'));
3372    }
3373
3374    // }}}
3375    // {{{ freeClobValue()
3376
3377    /**
3378     * free a character large object
3379     *
3380     * @param resource $prepared_query query handle from prepare()
3381     * @param string $blob
3382     * @param string $value
3383     * @access public
3384     */
3385    function freeClobValue($prepared_query, $clob, &$value)
3386    {
3387    }
3388
3389    // }}}
3390    // {{{ getBlobValue()
3391
3392    /**
3393     * Convert a text value into a DBMS specific format that is suitable to
3394     * compose query statements.
3395     *
3396     * @param resource $prepared_query query handle from prepare()
3397     * @param  $parameter
3398     * @param  $blob
3399     * @return string text string that represents the given argument value in
3400     *       a DBMS specific format.
3401     * @access public
3402     */
3403    function getBlobValue($prepared_query, $parameter, $blob)
3404    {
3405        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
3406            'Get BLOB field value: prepared queries with values of type "blob" are not yet supported'));
3407    }
3408
3409    // }}}
3410    // {{{ freeBlobValue()
3411
3412    /**
3413     * free a binary large object
3414     *
3415     * @param resource $prepared_query query handle from prepare()
3416     * @param string $blob
3417     * @param string $value
3418     * @access public
3419     */
3420    function freeBlobValue($prepared_query, $blob, &$value)
3421    {
3422    }
3423
3424    // }}}
3425    // {{{ getBooleanValue()
3426
3427    /**
3428     * Convert a text value into a DBMS specific format that is suitable to
3429     * compose query statements.
3430     *
3431     * @param string $value text string value that is intended to be converted.
3432     * @return string text string that represents the given argument value in
3433     *       a DBMS specific format.
3434     * @access public
3435     */
3436    function getBooleanValue($value)
3437    {
3438        return(($value === NULL) ? 'NULL' : ($value ? "'Y'" : "'N'"));
3439    }
3440
3441    // }}}
3442    // {{{ getDateValue()
3443
3444    /**
3445     * Convert a text value into a DBMS specific format that is suitable to
3446     * compose query statements.
3447     *
3448     * @param string $value text string value that is intended to be converted.
3449     * @return string text string that represents the given argument value in
3450     *       a DBMS specific format.
3451     * @access public
3452     */
3453    function getDateValue($value)
3454    {
3455        return(($value === NULL) ? 'NULL' : "'$value'");
3456    }
3457
3458    // }}}
3459    // {{{ getTimestampValue()
3460
3461    /**
3462     * Convert a text value into a DBMS specific format that is suitable to
3463     * compose query statements.
3464     *
3465     * @param string $value text string value that is intended to be converted.
3466     * @return string text string that represents the given argument value in
3467     *       a DBMS specific format.
3468     * @access public
3469     */
3470    function getTimestampValue($value)
3471    {
3472        return(($value === NULL) ? 'NULL' : "'$value'");
3473    }
3474
3475    // }}}
3476    // {{{ getTimeValue()
3477
3478    /**
3479     * Convert a text value into a DBMS specific format that is suitable to
3480     *       compose query statements.
3481     *
3482     * @param string $value text string value that is intended to be converted.
3483     * @return string text string that represents the given argument value in
3484     *       a DBMS specific format.
3485     * @access public
3486     */
3487    function getTimeValue($value)
3488    {
3489        return(($value === NULL) ? 'NULL' : "'$value'");
3490    }
3491
3492    // }}}
3493    // {{{ getFloatValue()
3494
3495    /**
3496     * Convert a text value into a DBMS specific format that is suitable to
3497     * compose query statements.
3498     *
3499     * @param string $value text string value that is intended to be converted.
3500     * @return string text string that represents the given argument value in
3501     *       a DBMS specific format.
3502     * @access public
3503     */
3504    function getFloatValue($value)
3505    {
3506        return(($value === NULL) ? 'NULL' : "'$value'");
3507    }
3508
3509    // }}}
3510    // {{{ getDecimalValue()
3511
3512    /**
3513     * Convert a text value into a DBMS specific format that is suitable to
3514     * compose query statements.
3515     *
3516     * @param string $value text string value that is intended to be converted.
3517     * @return string text string that represents the given argument value in
3518     *       a DBMS specific format.
3519     * @access public
3520     */
3521    function getDecimalValue($value)
3522    {
3523        return(($value === NULL) ? 'NULL' : "'$value'");
3524    }
3525
3526    // }}}
3527    // {{{ getValue()
3528
3529    /**
3530     * Convert a text value into a DBMS specific format that is suitable to
3531     * compose query statements.
3532     *
3533     * @param string $type type to which the value should be converted to
3534     * @param string $value text string value that is intended to be converted.
3535     * @return string text string that represents the given argument value in
3536     *       a DBMS specific format.
3537     * @access public
3538     */
3539    function getValue($type, $value)
3540    {
3541        if (empty($type)) {
3542            return($this->raiseError(MDB_ERROR_SYNTAX, NULL, NULL,
3543                'getValue: called without type to convert to'));
3544        }
3545        if (method_exists($this,"get{$type}Value")) {
3546            return $this->{"get{$type}Value"}($value);
3547        }
3548        return $value;
3549    }
3550
3551    // }}}
3552    // {{{ support()
3553
3554    /**
3555     * Tell whether a DB implementation or its backend extension
3556     * supports a given feature.
3557     *
3558     * @param string $feature name of the feature (see the MDB class doc)
3559     * @return boolean whether this DB implementation supports $feature
3560     * @access public
3561     */
3562    function support($feature)
3563    {
3564        return(isset($this->supported[$feature]) && $this->supported[$feature]);
3565    }
3566
3567    // }}}
3568    // {{{ getSequenceName()
3569
3570    /**
3571     * adds sequence name formating to a sequence name
3572     *
3573     * @param string $sqn name of the sequence
3574     * @return string formatted sequence name
3575     * @access public
3576     */
3577    function getSequenceName($sqn)
3578    {
3579        return sprintf($this->options['seqname_format'],
3580            preg_replace('/[^a-z0-9_]/i', '_', $sqn));
3581    }
3582
3583    // }}}
3584    // {{{ nextId()
3585
3586    /**
3587     * returns the next free id of a sequence
3588     *
3589     * @param string $seq_name name of the sequence
3590     * @param boolean $ondemand when TRUE the seqence is
3591     *                           automatic created, if it
3592     *                           not exists
3593     * @return mixed MDB_Error or id
3594     * @access public
3595     */
3596    function nextId($seq_name, $ondemand = FALSE)
3597    {
3598        return($this->raiseError(MDB_ERROR_NOT_CAPABLE, NULL, NULL,
3599            'Next Sequence: getting next sequence value not supported'));
3600    }
3601
3602    // }}}
3603    // {{{ currId()
3604
3605    /**
3606     * returns the current id of a sequence
3607     *
3608     * @param string $seq_name name of the sequence
3609     * @return mixed MDB_Error or id
3610     * @access public
3611     */
3612    function currId($seq_name)
3613    {
3614        $this->warnings[] = 'database does not support getting current
3615            sequence value, the sequence value was incremented';
3616        $this->expectError(MDB_ERROR_NOT_CAPABLE);
3617        $id = $this->nextId($seq_name);
3618        $this->popExpect(MDB_ERROR_NOT_CAPABLE);
3619        if (MDB::isError($id)) {
3620            if ($id->getCode() == MDB_ERROR_NOT_CAPABLE) {
3621                return($this->raiseError(MDB_ERROR_NOT_CAPABLE, NULL, NULL,
3622                    'Current Sequence: getting current sequence value not supported'));
3623            }
3624            return($id);
3625        }
3626        return($id);
3627    }
3628
3629    // }}}
3630    // {{{ fetchInto()
3631
3632    /**
3633     * Fetch a row and return data in an array.
3634     *
3635     * @param resource $result result identifier
3636     * @param int $fetchmode ignored
3637     * @param int $rownum the row number to fetch
3638     * @return mixed data array or NULL on success, a MDB error on failure
3639     * @access public
3640     */
3641    function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL)
3642    {
3643        $result_value = intval($result);
3644        if (MDB::isError($this->endOfResult($result))) {
3645            $this->freeResult($result);
3646            $result = $this->raiseError(MDB_ERROR_NEED_MORE_DATA, NULL, NULL,
3647                'Fetch field: result set is empty');
3648        }
3649        if ($rownum == NULL) {
3650            ++$this->highest_fetched_row[$result_value];
3651            $rownum = $this->highest_fetched_row[$result_value];
3652        } else {
3653            $this->highest_fetched_row[$result_value] =
3654                max($this->highest_fetched_row[$result_value], $row);
3655        }
3656        if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
3657            $fetchmode = $this->fetchmode;
3658        }
3659        $columns = $this->numCols($result);
3660        if (MDB::isError($columns)) {
3661            return($columns);
3662        }
3663        if ($fetchmode & MDB_FETCHMODE_ASSOC) {
3664            $column_names = $this->getColumnNames($result);
3665        }
3666        for($column = 0; $column < $columns; $column++) {
3667            if (!$this->resultIsNull($result, $rownum, $column)) {
3668                $value = $this->fetch($result, $rownum, $column);
3669                if ($value === FALSE) {
3670                    if ($this->options['autofree']) {
3671                        $this->freeResult($result);
3672                    }
3673                    return(NULL);
3674                } elseif (MDB::isError($value)) {
3675                    if ($value->getMessage() == '') {
3676                        if ($this->options['autofree']) {
3677                            $this->freeResult($result);
3678                        }
3679                        return(NULL);
3680                    } else {
3681                        return($value);
3682                    }
3683                }
3684            }
3685            $row[$column] = $value;
3686        }
3687        if ($fetchmode & MDB_FETCHMODE_ASSOC) {
3688            $row = array_combine($column_names, $row);
3689            if (is_array($row) && $this->options['optimize'] == 'portability') {
3690                $row = array_change_key_case($row, CASE_LOWER);
3691            }
3692        }
3693        if (isset($this->result_types[$result_value])) {
3694            $row = $this->convertResultRow($result, $row);
3695        }
3696        return($row);
3697    }
3698
3699    // }}}
3700    // {{{ fetchOne()
3701
3702    /**
3703     * Fetch and return a field of data (it uses fetchInto for that)
3704     *
3705     * @param resource $result result identifier
3706     * @return mixed data on success, a MDB error on failure
3707     * @access public
3708     */
3709    function fetchOne($result)
3710    {
3711        $row = $this->fetchInto($result, MDB_FETCHMODE_ORDERED);
3712        if (!$this->options['autofree'] || $row != NULL) {
3713            $this->freeResult($result);
3714        }
3715        if (is_array($row)) {
3716            return($row[0]);
3717        }
3718        return($row);
3719    }
3720
3721    // }}}
3722    // {{{ fetchRow()
3723
3724    /**
3725     * Fetch and return a row of data (it uses fetchInto for that)
3726     *
3727     * @param resource $result result identifier
3728     * @param int $fetchmode how the array data should be indexed
3729     * @param int $rownum the row number to fetch
3730     * @return mixed data array on success, a MDB error on failure
3731     * @access public
3732     */
3733    function fetchRow($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL)
3734    {
3735        $row = $this->fetchInto($result, $fetchmode, $rownum);
3736        if (!$this->options['autofree'] || $row != NULL) {
3737            $this->freeResult($result);
3738        }
3739        return($row);
3740    }
3741
3742    // }}}
3743    // {{{ fetchCol()
3744
3745    /**
3746     * Fetch and return a column of data (it uses fetchInto for that)
3747     *
3748     * @param resource $result result identifier
3749     * @param int $colnum the row number to fetch
3750     * @return mixed data array on success, a MDB error on failure
3751     * @access public
3752     */
3753    function fetchCol($result, $colnum = 0)
3754    {
3755        $fetchmode = is_numeric($colnum) ? MDB_FETCHMODE_ORDERED : MDB_FETCHMODE_ASSOC;
3756        $column = array();
3757        $row = $this->fetchInto($result, $fetchmode);
3758        if (is_array($row)) {
3759            if (!array_key_exists($colnum, $row)) {
3760                return($this->raiseError(MDB_ERROR_TRUNCATED));
3761            }
3762            do {
3763                $column[] = $row[$colnum];
3764            } while (is_array($row = $this->fetchInto($result, $fetchmode)));
3765        }
3766        if (!$this->options['autofree']) {
3767            $this->freeResult($result);
3768        }
3769        if (MDB::isError($row)) {
3770            return($row);
3771        }
3772        return($column);
3773    }
3774
3775    // }}}
3776    // {{{ fetchAll()
3777
3778    /**
3779     * Fetch and return a column of data (it uses fetchInto for that)
3780     *
3781     * @param resource $result result identifier
3782     * @param int $fetchmode how the array data should be indexed
3783     * @param boolean $rekey if set to TRUE, the $all will have the first
3784     *       column as its first dimension
3785     * @param boolean $force_array used only when the query returns exactly
3786     *       two columns. If TRUE, the values of the returned array will be
3787     *       one-element arrays instead of scalars.
3788     * @param boolean $group if TRUE, the values of the returned array is
3789     *       wrapped in another array.  If the same key value (in the first
3790     *       column) repeats itself, the values will be appended to this array
3791     *       instead of overwriting the existing values.
3792     * @return mixed data array on success, a MDB error on failure
3793     * @access public
3794     * @see getAssoc()
3795     */
3796    function fetchAll($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rekey = FALSE, $force_array = FALSE, $group = FALSE)
3797    {
3798        if ($rekey) {
3799            $cols = $this->numCols($result);
3800            if (MDB::isError($cols)) {
3801                return($cols);
3802            }
3803            if ($cols < 2) {
3804                return($this->raiseError(MDB_ERROR_TRUNCATED));
3805            }
3806        }
3807        $all = array();
3808        while (is_array($row = $this->fetchInto($result, $fetchmode))) {
3809            if ($rekey) {
3810                if ($fetchmode & MDB_FETCHMODE_ASSOC) {
3811                    $key = reset($row);
3812                    unset($row[key($row)]);
3813                } else {
3814                    $key = array_shift($row);
3815                }
3816                if (!$force_array && count($row) == 1) {
3817                    $row = array_shift($row);
3818                }
3819                if ($group) {
3820                    $all[$key][] = $row;
3821                } else {
3822                    $all[$key] = $row;
3823                }
3824            } else {
3825                if ($fetchmode & MDB_FETCHMODE_FLIPPED) {
3826                    foreach ($row as $key => $val) {
3827                        $all[$key][] = $val;
3828                    }
3829                } else {
3830                   $all[] = $row;
3831                }
3832            }
3833        }
3834        if (!$this->options['autofree']) {
3835            $this->freeResult($result);
3836        }
3837        if (MDB::isError($row)) {
3838            return($row);
3839        }
3840        return($all);
3841    }
3842
3843    // }}}
3844    // {{{ queryOne()
3845
3846    /**
3847     * Execute the specified query, fetch the value from the first column of
3848     * the first row of the result set and then frees
3849     * the result set.
3850     *
3851     * @param string $query the SELECT query statement to be executed.
3852     * @param string $type optional argument that specifies the expected
3853     *       datatype of the result set field, so that an eventual conversion
3854     *       may be performed. The default datatype is text, meaning that no
3855     *       conversion is performed
3856     * @return mixed field value on success, a MDB error on failure
3857     * @access public
3858     */
3859    function queryOne($query, $type = NULL)
3860    {
3861        if ($type != NULL) {
3862            $type = array($type);
3863        }
3864        $result = $this->query($query, $type);
3865        if (MDB::isError($result)) {
3866            return($result);
3867        }
3868        return($this->fetchOne($result));
3869    }
3870
3871    // }}}
3872    // {{{ queryRow()
3873
3874    /**
3875     * Execute the specified query, fetch the values from the first
3876     * row of the result set into an array and then frees
3877     * the result set.
3878     *
3879     * @param string $query the SELECT query statement to be executed.
3880     * @param array $types optional array argument that specifies a list of
3881     *       expected datatypes of the result set columns, so that the eventual
3882     *       conversions may be performed. The default list of datatypes is
3883     *       empty, meaning that no conversion is performed.
3884     * @param int $fetchmode how the array data should be indexed
3885     * @return mixed data array on success, a MDB error on failure
3886     * @access public
3887     */
3888    function queryRow($query, $types = NULL, $fetchmode = MDB_FETCHMODE_DEFAULT)
3889    {
3890        $result = $this->query($query, $types);
3891        if (MDB::isError($result)) {
3892            return($result);
3893        }
3894        return($this->fetchRow($result, $fetchmode));
3895    }
3896
3897    // }}}
3898    // {{{ queryCol()
3899
3900    /**
3901     * Execute the specified query, fetch the value from the first column of
3902     * each row of the result set into an array and then frees the result set.
3903     *
3904     * @param string $query the SELECT query statement to be executed.
3905     * @param string $type optional argument that specifies the expected
3906     *       datatype of the result set field, so that an eventual conversion
3907     *       may be performed. The default datatype is text, meaning that no
3908     *       conversion is performed
3909     * @param int $colnum the row number to fetch
3910     * @return mixed data array on success, a MDB error on failure
3911     * @access public
3912     */
3913    function queryCol($query, $type = NULL, $colnum = 0)
3914    {
3915        if ($type != NULL) {
3916            $type = array($type);
3917        }
3918        $result = $this->query($query, $type);
3919        if (MDB::isError($result)) {
3920            return($result);
3921        }
3922        return($this->fetchCol($result, $colnum));
3923    }
3924
3925    // }}}
3926    // {{{ queryAll()
3927
3928    /**
3929     * Execute the specified query, fetch all the rows of the result set into
3930     * a two dimensional array and then frees the result set.
3931     *
3932     * @param string $query the SELECT query statement to be executed.
3933     * @param array $types optional array argument that specifies a list of
3934     *       expected datatypes of the result set columns, so that the eventual
3935     *       conversions may be performed. The default list of datatypes is
3936     *       empty, meaning that no conversion is performed.
3937     * @param int $fetchmode how the array data should be indexed
3938     * @param boolean $rekey if set to TRUE, the $all will have the first
3939     *       column as its first dimension
3940     * @param boolean $force_array used only when the query returns exactly
3941     *       two columns. If TRUE, the values of the returned array will be
3942     *       one-element arrays instead of scalars.
3943     * @param boolean $group if TRUE, the values of the returned array is
3944     *       wrapped in another array.  If the same key value (in the first
3945     *       column) repeats itself, the values will be appended to this array
3946     *       instead of overwriting the existing values.
3947     * @return mixed data array on success, a MDB error on failure
3948     * @access public
3949     */
3950    function queryAll($query, $types = NULL, $fetchmode = MDB_FETCHMODE_DEFAULT,
3951        $rekey = FALSE, $force_array = FALSE, $group = FALSE)
3952    {
3953        if (MDB::isError($result = $this->query($query, $types))) {
3954            return($result);
3955        }
3956        return($this->fetchAll($result, $fetchmode, $rekey, $force_array, $group));
3957    }
3958
3959    // }}}
3960    // {{{ getOne()
3961
3962    /**
3963     * Fetch the first column of the first row of data returned from
3964     * a query.  Takes care of doing the query and freeing the results
3965     * when finished.
3966     *
3967     * @param string $query the SQL query
3968     * @param string $type string that contains the type of the column in the
3969     *       result set
3970     * @param array $params if supplied, prepare/execute will be used
3971     *       with this array as execute parameters
3972     * @param array $param_types array that contains the types of the values
3973     *       defined in $params
3974     * @return mixed MDB_Error or the returned value of the query
3975     * @access public
3976     */
3977    function getOne($query, $type = NULL, $params = array(), $param_types = NULL)
3978    {
3979        if ($type != NULL) {
3980            $type = array($type);
3981        }
3982        settype($params, 'array');
3983        if (count($params) > 0) {
3984            $prepared_query = $this->prepareQuery($query);
3985            if (MDB::isError($prepared_query)) {
3986                return($prepared_query);
3987            }
3988            $this->setParamArray($prepared_query, $params, $param_types);
3989            $result = $this->executeQuery($prepared_query, $type);
3990        } else {
3991            $result = $this->query($query, $type);
3992        }
3993
3994        if (MDB::isError($result)) {
3995            return($result);
3996        }
3997
3998        $value = $this->fetchOne($result, MDB_FETCHMODE_ORDERED);
3999        if (MDB::isError($value)) {
4000            return($value);
4001        }
4002        if (isset($prepared_query)) {
4003            $result = $this->freePreparedQuery($prepared_query);
4004            if (MDB::isError($result)) {
4005                return($result);
4006            }
4007        }
4008
4009        return($value);
4010    }
4011
4012    // }}}
4013    // {{{ getRow()
4014
4015    /**
4016     * Fetch the first row of data returned from a query.  Takes care
4017     * of doing the query and freeing the results when finished.
4018     *
4019     * @param string $query the SQL query
4020     * @param array $types array that contains the types of the columns in
4021     *       the result set
4022     * @param array $params array if supplied, prepare/execute will be used
4023     *       with this array as execute parameters
4024     * @param array $param_types array that contains the types of the values
4025     *       defined in $params
4026     * @param integer $fetchmode the fetch mode to use
4027     * @return array the first row of results as an array indexed from
4028     * 0, or a MDB error code.
4029     * @access public
4030     */
4031    function getRow($query, $types = NULL, $params = array(), $param_types = NULL, $fetchmode = MDB_FETCHMODE_DEFAULT)
4032    {
4033        settype($params, 'array');
4034        if (count($params) > 0) {
4035            $prepared_query = $this->prepareQuery($query);
4036            if (MDB::isError($prepared_query)) {
4037                return($prepared_query);
4038            }
4039            $this->setParamArray($prepared_query, $params, $param_types);
4040            $result = $this->executeQuery($prepared_query, $types);
4041        } else {
4042            $result = $this->query($query, $types);
4043        }
4044
4045        if (MDB::isError($result)) {
4046            return($result);
4047        }
4048
4049        $row = $this->fetchRow($result, $fetchmode);
4050        if (MDB::isError($row)) {
4051            return($row);
4052        }
4053        if (isset($prepared_query)) {
4054            $result = $this->freePreparedQuery($prepared_query);
4055            if (MDB::isError($result)) {
4056                return($result);
4057            }
4058        }
4059
4060        return($row);
4061    }
4062
4063    // }}}
4064    // {{{ getCol()
4065
4066    /**
4067     * Fetch a single column from a result set and return it as an
4068     * indexed array.
4069     *
4070     * @param string $query the SQL query
4071     * @param string $type string that contains the type of the column in the
4072     *       result set
4073     * @param array $params array if supplied, prepare/execute will be used
4074     *       with this array as execute parameters
4075     * @param array $param_types array that contains the types of the values
4076     *       defined in $params
4077     * @param mixed $colnum which column to return(integer [column number,
4078     *       starting at 0] or string [column name])
4079     * @return array an indexed array with the data from the first
4080     * row at index 0, or a MDB error code.
4081     * @access public
4082     */
4083    function getCol($query, $type = NULL, $params = array(), $param_types = NULL, $colnum = 0)
4084    {
4085        if ($type != NULL) {
4086            $type = array($type);
4087        }
4088        settype($params, 'array');
4089        if (count($params) > 0) {
4090            $prepared_query = $this->prepareQuery($query);
4091
4092            if (MDB::isError($prepared_query)) {
4093                return($prepared_query);
4094            }
4095            $this->setParamArray($prepared_query, $params, $param_types);
4096            $result = $this->executeQuery($prepared_query, $type);
4097        } else {
4098            $result = $this->query($query, $type);
4099        }
4100
4101        if (MDB::isError($result)) {
4102            return($result);
4103        }
4104
4105        $col = $this->fetchCol($result, $colnum);
4106        if (MDB::isError($col)) {
4107            return($col);
4108        }
4109        if (isset($prepared_query)) {
4110            $result = $this->freePreparedQuery($prepared_query);
4111            if (MDB::isError($result)) {
4112                return($result);
4113            }
4114        }
4115        return($col);
4116    }
4117
4118    // }}}
4119    // {{{ getAssoc()
4120
4121    /**
4122     * Fetch the entire result set of a query and return it as an
4123     * associative array using the first column as the key.
4124     *
4125     * If the result set contains more than two columns, the value
4126     * will be an array of the values from column 2-n.  If the result
4127     * set contains only two columns, the returned value will be a
4128     * scalar with the value of the second column (unless forced to an
4129     * array with the $force_array parameter).  A MDB error code is
4130     * returned on errors.  If the result set contains fewer than two
4131     * columns, a MDB_ERROR_TRUNCATED error is returned.
4132     *
4133     * For example, if the table 'mytable' contains:
4134     *
4135     *   ID      TEXT       DATE
4136     * --------------------------------
4137     *   1       'one'      944679408
4138     *   2       'two'      944679408
4139     *   3       'three'    944679408
4140     *
4141     * Then the call getAssoc('SELECT id,text FROM mytable') returns:
4142     *    array(
4143     *      '1' => 'one',
4144     *      '2' => 'two',
4145     *      '3' => 'three',
4146     *    )
4147     *
4148     * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
4149     *    array(
4150     *      '1' => array('one', '944679408'),
4151     *      '2' => array('two', '944679408'),
4152     *      '3' => array('three', '944679408')
4153     *    )
4154     *
4155     * If the more than one row occurs with the same value in the
4156     * first column, the last row overwrites all previous ones by
4157     * default.  Use the $group parameter if you don't want to
4158     * overwrite like this.  Example:
4159     *
4160     * getAssoc('SELECT category,id,name FROM mytable', NULL, NULL
4161     *           MDB_FETCHMODE_ASSOC, FALSE, TRUE) returns:
4162     *    array(
4163     *      '1' => array(array('id' => '4', 'name' => 'number four'),
4164     *                   array('id' => '6', 'name' => 'number six')
4165     *             ),
4166     *      '9' => array(array('id' => '4', 'name' => 'number four'),
4167     *                   array('id' => '6', 'name' => 'number six')
4168     *             )
4169     *    )
4170     *
4171     * Keep in mind that database functions in PHP usually return string
4172     * values for results regardless of the database's internal type.
4173     *
4174     * @param string $query the SQL query
4175     * @param array $types array that contains the types of the columns in
4176     *       the result set
4177     * @param array $params array if supplied, prepare/execute will be used
4178     *       with this array as execute parameters
4179     * @param array $param_types array that contains the types of the values
4180     *       defined in $params
4181     * @param boolean $force_array used only when the query returns
4182     * exactly two columns.  If TRUE, the values of the returned array
4183     * will be one-element arrays instead of scalars.
4184     * @param boolean $group if TRUE, the values of the returned array
4185     *       is wrapped in another array.  If the same key value (in the first
4186     *       column) repeats itself, the values will be appended to this array
4187     *       instead of overwriting the existing values.
4188     * @return array associative array with results from the query.
4189     * @access public
4190     */
4191    function getAssoc($query, $types = NULL, $params = array(), $param_types = NULL,
4192        $fetchmode = MDB_FETCHMODE_ORDERED, $force_array = FALSE, $group = FALSE)
4193    {
4194        settype($params, 'array');
4195        if (count($params) > 0) {
4196            $prepared_query = $this->prepareQuery($query);
4197
4198            if (MDB::isError($prepared_query)) {
4199                return($prepared_query);
4200            }
4201            $this->setParamArray($prepared_query, $params, $param_types);
4202            $result = $this->executeQuery($prepared_query, $types);
4203        } else {
4204            $result = $this->query($query, $types);
4205        }
4206
4207        if (MDB::isError($result)) {
4208            return($result);
4209        }
4210
4211        $all = $this->fetchAll($result, $fetchmode, TRUE, $force_array, $group);
4212        if (MDB::isError($all)) {
4213            return($all);
4214        }
4215        if (isset($prepared_query)) {
4216            $result = $this->freePreparedQuery($prepared_query);
4217            if (MDB::isError($result)) {
4218                return($result);
4219            }
4220        }
4221        return($all);
4222    }
4223
4224    // }}}
4225    // {{{ getAll()
4226
4227    /**
4228     * Fetch all the rows returned from a query.
4229     *
4230     * @param string $query the SQL query
4231     * @param array $types array that contains the types of the columns in
4232     *       the result set
4233     * @param array $params array if supplied, prepare/execute will be used
4234     *       with this array as execute parameters
4235     * @param array $param_types array that contains the types of the values
4236     *       defined in $params
4237     * @param integer $fetchmode the fetch mode to use
4238     * @return array an nested array, or a MDB error
4239     * @access public
4240     */
4241    function getAll($query, $types = NULL, $params = array(), $param_types = NULL, $fetchmode = MDB_FETCHMODE_DEFAULT)
4242    {
4243        settype($params, 'array');
4244        if (count($params) > 0) {
4245            $prepared_query = $this->prepareQuery($query);
4246
4247            if (MDB::isError($prepared_query)) {
4248                return($prepared_query);
4249            }
4250            $this->setParamArray($prepared_query, $params, $param_types);
4251            $result = $this->executeQuery($prepared_query, $types);
4252        } else {
4253            $result = $this->query($query, $types);
4254        }
4255
4256        if (MDB::isError($result)) {
4257            return($result);
4258        }
4259
4260        $all = $this->fetchAll($result, $fetchmode);
4261        if (MDB::isError($all)) {
4262            return($all);
4263        }
4264        if (isset($prepared_query)) {
4265            $result = $this->freePreparedQuery($prepared_query);
4266            if (MDB::isError($result)) {
4267                return($result);
4268            }
4269        }
4270        return($all);
4271    }
4272
4273    // }}}
4274    // {{{ tableInfo()
4275
4276    /**
4277     * returns meta data about the result set
4278     *
4279     * @param resource $result result identifier
4280     * @param mixed $mode depends on implementation
4281     * @return array an nested array, or a MDB error
4282     * @access public
4283     */
4284    function tableInfo($result, $mode = NULL)
4285    {
4286        return($this->raiseError(MDB_ERROR_NOT_CAPABLE));
4287    }
4288
4289    // }}}
4290    // {{{ createLob()
4291
4292    /**
4293     * Create a handler object of a specified class with functions to
4294     * retrieve data from a large object data stream.
4295     *
4296     * @param array $arguments An associative array with parameters to create
4297     *                  the handler object. The array indexes are the names of
4298     *                  the parameters and the array values are the respective
4299     *                  parameter values.
4300     *
4301     *                  Some parameters are specific of the class of each type
4302     *                  of handler object that is created. The following
4303     *                  parameters are common to all handler object classes:
4304     *
4305     *                  Type
4306     *
4307     *                      Name of the type of the built-in supported class
4308     *                      that will be used to create the handler object.
4309     *                      There are currently four built-in types of handler
4310     *                      object classes: data, resultlob, inputfile and
4311     *                      outputfile.
4312     *
4313     *                      The data handler class is the default class. It
4314     *                      simply reads data from a given data string.
4315     *
4316     *                      The resultlob handler class is meant to read data
4317     *                      from a large object retrieved from a query result.
4318     *                      This class is not used directly by applications.
4319     *
4320     *                      The inputfile handler class is meant to read data
4321     *                      from a file to use in prepared queries with large
4322     *                      object field parameters.
4323     *
4324     *                      The outputfile handler class is meant to write to
4325     *                      a file data from result columns with large object
4326     *                      fields. The functions to read from this type of
4327     *                      large object do not return any data. Instead, the
4328     *                      data is just written to the output file with the
4329     *                      data retrieved from a specified large object handle.
4330     *
4331     *                  Class
4332     *
4333     *                      Name of the class of the handler object that will be
4334     *                      created if the Type argument is not specified. This
4335     *                      argument should be used when you need to specify a
4336     *                      custom handler class.
4337     *
4338     *                  Database
4339     *
4340     *                      Database object as returned by MDB::connect.
4341     *                      This is an option argument needed by some handler
4342     *                      classes like resultlob.
4343     *
4344     *                  The following arguments are specific of the inputfile
4345     *                  handler class:
4346     *
4347     *                      File
4348     *
4349     *                          Integer handle value of a file already opened
4350     *                          for writing.
4351     *
4352     *                      FileName
4353     *
4354     *                          Name of a file to be opened for writing if the
4355     *                          File argument is not specified.
4356     *
4357     *                  The following arguments are specific of the outputfile
4358     *                  handler class:
4359     *
4360     *                      File
4361     *
4362     *                          Integer handle value of a file already opened
4363     *                          for writing.
4364     *
4365     *                      FileName
4366     *
4367     *                          Name of a file to be opened for writing if the
4368     *                          File argument is not specified.
4369     *
4370     *                      BufferLength
4371     *
4372     *                          Integer value that specifies the length of a
4373     *                          buffer that will be used to read from the
4374     *                          specified large object.
4375     *
4376     *                      LOB
4377     *
4378     *                          Integer handle value that specifies a large
4379     *                          object from which the data to be stored in the
4380     *                          output file will be written.
4381     *
4382     *                      Result
4383     *
4384     *                          Integer handle value as returned by the function
4385     *                          MDB::query() or MDB::executeQuery() that specifies
4386     *                          the result set that contains the large object value
4387     *                          to be retrieved. If the LOB argument is specified,
4388     *                          this argument is ignored.
4389     *
4390     *                      Row
4391     *
4392     *                          Integer value that specifies the number of the
4393     *                          row of the result set that contains the large
4394     *                          object value to be retrieved. If the LOB
4395     *                          argument is specified, this argument is ignored.
4396     *
4397     *                      Field
4398     *
4399     *                          Integer or string value that specifies the
4400     *                          number or the name of the column of the result
4401     *                          set that contains the large object value to be
4402     *                          retrieved. If the LOB argument is specified,
4403     *                          this argument is ignored.
4404     *
4405     *                      Binary
4406     *
4407     *                          Boolean value that specifies whether the large
4408     *                          object column to be retrieved is of binary type
4409     *                          (blob) or otherwise is of character type (clob).
4410     *                          If the LOB argument is specified, this argument
4411     *                          is ignored.
4412     *
4413     *                  The following argument is specific of the data
4414     *                  handler class:
4415     *
4416     *                  Data
4417     *
4418     *                      String of data that will be returned by the class
4419     *                      when it requested with the readLOB() method.
4420     *
4421     *                  The following argument is specific of the resultlob
4422     *                  handler class:
4423     *
4424     *                      ResultLOB
4425     *
4426     *                          Integer handle value of a large object result
4427     *                          row field.
4428     * @return integer handle value that should be passed as argument insubsequent
4429     * calls to functions that retrieve data from the large object input stream.
4430     * @access public
4431     */
4432    function createLob($arguments)
4433    {
4434        $result = $this->loadLob('Create LOB');
4435        if (MDB::isError($result)) {
4436            return($result);
4437        }
4438        $class_name = 'MDB_LOB';
4439        if (isset($arguments['Type'])) {
4440            switch ($arguments['Type']) {
4441                case 'data':
4442                    break;
4443                case 'resultlob':
4444                    $class_name = 'MDB_LOB_Result';
4445                    break;
4446                case 'inputfile':
4447                    $class_name = 'MDB_LOB_Input_File';
4448                    break;
4449                case 'outputfile':
4450                    $class_name = 'MDB_LOB_Output_File';
4451                    break;
4452                default:
4453                    if (isset($arguments['Error'])) {
4454                        $arguments['Error'] = $arguments['Type'] . ' is not a valid type of large object';
4455                    }
4456                    return($this->raiseError());
4457            }
4458        } else {
4459            if (isset($arguments['Class'])) {
4460                $class = $arguments['Class'];
4461            }
4462        }
4463        $lob = count($GLOBALS['_MDB_lobs']) + 1;
4464        $GLOBALS['_MDB_lobs'][$lob] = &new $class_name;
4465        if (isset($arguments['Database'])) {
4466            $GLOBALS['_MDB_lobs'][$lob]->database = $arguments['Database'];
4467        } else {
4468            $GLOBALS['_MDB_lobs'][$lob]->database = &$this;
4469        }
4470        if (MDB::isError($result = $GLOBALS['_MDB_lobs'][$lob]->create($arguments))) {
4471            $GLOBALS['_MDB_lobs'][$lob]->database->destroyLob($lob);
4472            return($result);
4473        }
4474        return($lob);
4475    }
4476
4477    // }}}
4478    // {{{ readLob()
4479
4480    /**
4481     * Read data from large object input stream.
4482     *
4483     * @param integer $lob argument handle that is returned by the
4484     *                          MDB::createLob() method.
4485     * @param string $data reference to a variable that will hold data
4486     *                          to be read from the large object input stream
4487     * @param integer $length    value that indicates the largest ammount ofdata
4488     *                          to be read from the large object input stream.
4489     * @return mixed the effective number of bytes read from the large object
4490     *                      input stream on sucess or an MDB error object.
4491     * @access public
4492     * @see endOfLob()
4493     */
4494    function readLob($lob, &$data, $length)
4495    {
4496        return($GLOBALS['_MDB_lobs'][$lob]->readLob($data, $length));
4497    }
4498
4499    // }}}
4500    // {{{ endOfLob()
4501
4502    /**
4503     * Determine whether it was reached the end of the large object and
4504     * therefore there is no more data to be read for the its input stream.
4505     *
4506     * @param integer $lob argument handle that is returned by the
4507     *                          MDB::createLob() method.
4508     * @access public
4509     * @return boolean flag that indicates whether it was reached the end of the large object input stream
4510     */
4511    function endOfLob($lob)
4512    {
4513        return($GLOBALS['_MDB_lobs'][$lob]->endOfLob());
4514    }
4515
4516    // }}}
4517    // {{{ destroyLob()
4518
4519    /**
4520     * Free any resources allocated during the lifetime of the large object
4521     * handler object.
4522     *
4523     * @param integer $lob argument handle that is returned by the
4524     *                          MDB::createLob() method.
4525     * @access public
4526     */
4527    function destroyLob($lob)
4528    {
4529        $GLOBALS['_MDB_lobs'][$lob]->destroy();
4530        unset($GLOBALS['_MDB_lobs'][$lob]);
4531    }
4532
4533    // }}}
4534    // {{{ Destructor
4535
4536    /**
4537    * this function closes open transactions to be executed at shutdown
4538    *
4539    * @access private
4540    */
4541    function _MDB_Common()
4542    {
4543        if ($this->in_transaction && !MDB::isError($this->rollback())) {
4544            $this->autoCommit(TRUE);
4545        }
4546    }
4547};
4548?>
4549