MDB2
[ class tree: MDB2 ] [ index: MDB2 ] [ all elements ]

Source for file MDB2.php

Documentation is available at MDB2.php

  1. <?php
  2. // vim: set et ts=4 sw=4 fdm=marker:
  3. // +----------------------------------------------------------------------+
  4. // | PHP versions 4 and 5                                                 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
  7. // | Stig. S. Bakken, Lukas Smith                                         |
  8. // | All rights reserved.                                                 |
  9. // +----------------------------------------------------------------------+
  10. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
  11. // | API as well as database abstraction for PHP applications.            |
  12. // | This LICENSE is in the BSD license style.                            |
  13. // |                                                                      |
  14. // | Redistribution and use in source and binary forms, with or without   |
  15. // | modification, are permitted provided that the following conditions   |
  16. // | are met:                                                             |
  17. // |                                                                      |
  18. // | Redistributions of source code must retain the above copyright       |
  19. // | notice, this list of conditions and the following disclaimer.        |
  20. // |                                                                      |
  21. // | Redistributions in binary form must reproduce the above copyright    |
  22. // | notice, this list of conditions and the following disclaimer in the  |
  23. // | documentation and/or other materials provided with the distribution. |
  24. // |                                                                      |
  25. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  26. // | Lukas Smith nor the names of his contributors may be used to endorse |
  27. // | or promote products derived from this software without specific prior|
  28. // | written permission.                                                  |
  29. // |                                                                      |
  30. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  31. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  32. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  33. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  34. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  35. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  38. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  39. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  41. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  42. // +----------------------------------------------------------------------+
  43. // | Author: Lukas Smith <smith@pooteeweet.org>                           |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: MDB2.php,v 1.335 2008/11/29 14:57:01 afz Exp $
  47. //
  48.  
  49. /**
  50.  * @package     MDB2
  51.  * @category    Database
  52.  * @author      Lukas Smith <smith@pooteeweet.org>
  53.  */
  54.  
  55. require_once 'PEAR.php';
  56.  
  57. // {{{ Error constants
  58.  
  59. /**
  60.  * The method mapErrorCode in each MDB2_dbtype implementation maps
  61.  * native error codes to one of these.
  62.  *
  63.  * If you add an error code here, make sure you also add a textual
  64.  * version of it in MDB2::errorMessage().
  65.  */
  66.  
  67. define('MDB2_OK',                      true);
  68. define('MDB2_ERROR',                     -1);
  69. define('MDB2_ERROR_SYNTAX',              -2);
  70. define('MDB2_ERROR_CONSTRAINT',          -3);
  71. define('MDB2_ERROR_NOT_FOUND',           -4);
  72. define('MDB2_ERROR_ALREADY_EXISTS',      -5);
  73. define('MDB2_ERROR_UNSUPPORTED',         -6);
  74. define('MDB2_ERROR_MISMATCH',            -7);
  75. define('MDB2_ERROR_INVALID',             -8);
  76. define('MDB2_ERROR_NOT_CAPABLE',         -9);
  77. define('MDB2_ERROR_TRUNCATED',          -10);
  78. define('MDB2_ERROR_INVALID_NUMBER',     -11);
  79. define('MDB2_ERROR_INVALID_DATE',       -12);
  80. define('MDB2_ERROR_DIVZERO',            -13);
  81. define('MDB2_ERROR_NODBSELECTED',       -14);
  82. define('MDB2_ERROR_CANNOT_CREATE',      -15);
  83. define('MDB2_ERROR_CANNOT_DELETE',      -16);
  84. define('MDB2_ERROR_CANNOT_DROP',        -17);
  85. define('MDB2_ERROR_NOSUCHTABLE',        -18);
  86. define('MDB2_ERROR_NOSUCHFIELD',        -19);
  87. define('MDB2_ERROR_NEED_MORE_DATA',     -20);
  88. define('MDB2_ERROR_NOT_LOCKED',         -21);
  89. define('MDB2_ERROR_VALUE_COUNT_ON_ROW'-22);
  90. define('MDB2_ERROR_INVALID_DSN',        -23);
  91. define('MDB2_ERROR_CONNECT_FAILED',     -24);
  92. define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25);
  93. define('MDB2_ERROR_NOSUCHDB',           -26);
  94. define('MDB2_ERROR_ACCESS_VIOLATION',   -27);
  95. define('MDB2_ERROR_CANNOT_REPLACE',     -28);
  96. define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29);
  97. define('MDB2_ERROR_DEADLOCK',           -30);
  98. define('MDB2_ERROR_CANNOT_ALTER',       -31);
  99. define('MDB2_ERROR_MANAGER',            -32);
  100. define('MDB2_ERROR_MANAGER_PARSE',      -33);
  101. define('MDB2_ERROR_LOADMODULE',         -34);
  102. define('MDB2_ERROR_INSUFFICIENT_DATA',  -35);
  103. define('MDB2_ERROR_NO_PERMISSION',      -36);
  104. define('MDB2_ERROR_DISCONNECT_FAILED',  -37);
  105.  
  106. // }}}
  107. // {{{ Verbose constants
  108. /**
  109.  * These are just helper constants to more verbosely express parameters to prepare()
  110.  */
  111.  
  112. define('MDB2_PREPARE_MANIP'false);
  113. define('MDB2_PREPARE_RESULT'null);
  114.  
  115. // }}}
  116. // {{{ Fetchmode constants
  117.  
  118. /**
  119.  * This is a special constant that tells MDB2 the user hasn't specified
  120.  * any particular get mode, so the default should be used.
  121.  */
  122. define('MDB2_FETCHMODE_DEFAULT'0);
  123.  
  124. /**
  125.  * Column data indexed by numbers, ordered from 0 and up
  126.  */
  127. define('MDB2_FETCHMODE_ORDERED'1);
  128.  
  129. /**
  130.  * Column data indexed by column names
  131.  */
  132. define('MDB2_FETCHMODE_ASSOC'2);
  133.  
  134. /**
  135.  * Column data as object properties
  136.  */
  137. define('MDB2_FETCHMODE_OBJECT'3);
  138.  
  139. /**
  140.  * For multi-dimensional results: normally the first level of arrays
  141.  * is the row number, and the second level indexed by column number or name.
  142.  * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays
  143.  * is the column name, and the second level the row number.
  144.  */
  145. define('MDB2_FETCHMODE_FLIPPED'4);
  146.  
  147. // }}}
  148. // {{{ Portability mode constants
  149.  
  150. /**
  151.  * Portability: turn off all portability features.
  152.  * @see MDB2_Driver_Common::setOption()
  153.  */
  154. define('MDB2_PORTABILITY_NONE'0);
  155.  
  156. /**
  157.  * Portability: convert names of tables and fields to case defined in the
  158.  * "field_case" option when using the query*(), fetch*() and tableInfo() methods.
  159.  * @see MDB2_Driver_Common::setOption()
  160.  */
  161. define('MDB2_PORTABILITY_FIX_CASE'1);
  162.  
  163. /**
  164.  * Portability: right trim the data output by query*() and fetch*().
  165.  * @see MDB2_Driver_Common::setOption()
  166.  */
  167. define('MDB2_PORTABILITY_RTRIM'2);
  168.  
  169. /**
  170.  * Portability: force reporting the number of rows deleted.
  171.  * @see MDB2_Driver_Common::setOption()
  172.  */
  173. define('MDB2_PORTABILITY_DELETE_COUNT'4);
  174.  
  175. /**
  176.  * Portability: not needed in MDB2 (just left here for compatibility to DB)
  177.  * @see MDB2_Driver_Common::setOption()
  178.  */
  179. define('MDB2_PORTABILITY_NUMROWS'8);
  180.  
  181. /**
  182.  * Portability: makes certain error messages in certain drivers compatible
  183.  * with those from other DBMS's.
  184.  *
  185.  * + mysql, mysqli:  change unique/primary key constraints
  186.  *   MDB2_ERROR_ALREADY_EXISTS -> MDB2_ERROR_CONSTRAINT
  187.  *
  188.  * + odbc(access):  MS's ODBC driver reports 'no such field' as code
  189.  *   07001, which means 'too few parameters.'  When this option is on
  190.  *   that code gets mapped to MDB2_ERROR_NOSUCHFIELD.
  191.  *
  192.  * @see MDB2_Driver_Common::setOption()
  193.  */
  194. define('MDB2_PORTABILITY_ERRORS'16);
  195.  
  196. /**
  197.  * Portability: convert empty values to null strings in data output by
  198.  * query*() and fetch*().
  199.  * @see MDB2_Driver_Common::setOption()
  200.  */
  201. define('MDB2_PORTABILITY_EMPTY_TO_NULL'32);
  202.  
  203. /**
  204.  * Portability: removes database/table qualifiers from associative indexes
  205.  * @see MDB2_Driver_Common::setOption()
  206.  */
  207. define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES'64);
  208.  
  209. /**
  210.  * Portability: turn on all portability features.
  211.  * @see MDB2_Driver_Common::setOption()
  212.  */
  213. define('MDB2_PORTABILITY_ALL'127);
  214.  
  215. // }}}
  216. // {{{ Globals for class instance tracking
  217.  
  218. /**
  219.  * These are global variables that are used to track the various class instances
  220.  */
  221.  
  222. $GLOBALS['_MDB2_databases'= array();
  223. $GLOBALS['_MDB2_dsninfo_default'= array(
  224.     'phptype'  => false,
  225.     'dbsyntax' => false,
  226.     'username' => false,
  227.     'password' => false,
  228.     'protocol' => false,
  229.     'hostspec' => false,
  230.     'port'     => false,
  231.     'socket'   => false,
  232.     'database' => false,
  233.     'mode'     => false,
  234. );
  235.  
  236. // }}}
  237. // {{{ class MDB2
  238.  
  239. /**
  240.  * The main 'MDB2' class is simply a container class with some static
  241.  * methods for creating DB objects as well as some utility functions
  242.  * common to all parts of DB.
  243.  *
  244.  * The object model of MDB2 is as follows (indentation means inheritance):
  245.  *
  246.  * MDB2          The main MDB2 class.  This is simply a utility class
  247.  *              with some 'static' methods for creating MDB2 objects as
  248.  *              well as common utility functions for other MDB2 classes.
  249.  *
  250.  * MDB2_Driver_Common   The base for each MDB2 implementation.  Provides default
  251.  * |            implementations (in OO lingo virtual methods) for
  252.  * |            the actual DB implementations as well as a bunch of
  253.  * |            query utility functions.
  254.  * |
  255.  * +-MDB2_Driver_mysql  The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common.
  256.  *              When calling MDB2::factory or MDB2::connect for MySQL
  257.  *              connections, the object returned is an instance of this
  258.  *              class.
  259.  * +-MDB2_Driver_pgsql  The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common.
  260.  *              When calling MDB2::factory or MDB2::connect for PostGreSQL
  261.  *              connections, the object returned is an instance of this
  262.  *              class.
  263.  *
  264.  * @package     MDB2
  265.  * @category    Database
  266.  * @author      Lukas Smith <smith@pooteeweet.org>
  267.  */
  268. class MDB2
  269. {
  270.     // {{{ function setOptions(&$db, $options)
  271.  
  272.     /**
  273.      * set option array   in an exiting database object
  274.      *
  275.      * @param   MDB2_Driver_Common  MDB2 object
  276.      * @param   array   An associative array of option names and their values.
  277.      *
  278.      * @return mixed   MDB2_OK or a PEAR Error object
  279.      *
  280.      * @access  public
  281.      */
  282.     function setOptions(&$db$options)
  283.     {
  284.         if (is_array($options)) {
  285.             foreach ($options as $option => $value{
  286.                 $test $db->setOption($option$value);
  287.                 if (PEAR::isError($test)) {
  288.                     return $test;
  289.                 }
  290.             }
  291.         }
  292.         return MDB2_OK;
  293.     }
  294.  
  295.     // }}}
  296.     // {{{ function classExists($classname)
  297.  
  298.     /**
  299.      * Checks if a class exists without triggering __autoload
  300.      *
  301.      * @param   string  classname
  302.      *
  303.      * @return  bool    true success and false on error
  304.      * @static
  305.      * @access  public
  306.      */
  307.     function classExists($classname)
  308.     {
  309.         if (version_compare(phpversion()"5.0"">=")) {
  310.             return class_exists($classnamefalse);
  311.         }
  312.         return class_exists($classname);
  313.     }
  314.  
  315.     // }}}
  316.     // {{{ function loadClass($class_name, $debug)
  317.  
  318.     /**
  319.      * Loads a PEAR class.
  320.      *
  321.      * @param   string  classname to load
  322.      * @param   bool    if errors should be suppressed
  323.      *
  324.      * @return  mixed   true success or PEAR_Error on failure
  325.      *
  326.      * @access  public
  327.      */
  328.     function loadClass($class_name$debug)
  329.     {
  330.         if (!MDB2::classExists($class_name)) {
  331.             $file_name str_replace('_'DIRECTORY_SEPARATOR$class_name).'.php';
  332.             if ($debug{
  333.                 $include include_once($file_name);
  334.             else {
  335.                 $include @include_once($file_name);
  336.             }
  337.             if (!$include{
  338.                 if (!MDB2::fileExists($file_name)) {
  339.                     $msg = "unable to find package '$class_name' file '$file_name'";
  340.                 else {
  341.                     $msg = "unable to load class '$class_name' from file '$file_name'";
  342.                 }
  343.                 $err =MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull$msg);
  344.                 return $err;
  345.             }
  346.         }
  347.         return MDB2_OK;
  348.     }
  349.  
  350.     // }}}
  351.     // {{{ function &factory($dsn, $options = false)
  352.  
  353.     /**
  354.      * Create a new MDB2 object for the specified database type
  355.      *
  356.      * IMPORTANT: In order for MDB2 to work properly it is necessary that
  357.      * you make sure that you work with a reference of the original
  358.      * object instead of a copy (this is a PHP4 quirk).
  359.      *
  360.      * For example:
  361.      *     $db =& MDB2::factory($dsn);
  362.      *          ^^
  363.      * And not:
  364.      *     $db = MDB2::factory($dsn);
  365.      *
  366.      * @param   mixed   'data source name', see the MDB2::parseDSN
  367.      *                       method for a description of the dsn format.
  368.      *                       Can also be specified as an array of the
  369.      *                       format returned by MDB2::parseDSN.
  370.      * @param   array   An associative array of option names and
  371.      *                             their values.
  372.      *
  373.      * @return  mixed   a newly created MDB2 object, or false on error
  374.      *
  375.      * @access  public
  376.      */
  377.     function &factory($dsn$options = false)
  378.     {
  379.         $dsninfo MDB2::parseDSN($dsn);
  380.         if (empty($dsninfo['phptype'])) {
  381.             $err =MDB2::raiseError(MDB2_ERROR_NOT_FOUND,
  382.                 nullnull'no RDBMS driver specified');
  383.             return $err;
  384.         }
  385.         $class_name 'MDB2_Driver_'.$dsninfo['phptype'];
  386.  
  387.         $debug (!empty($options['debug']));
  388.         $err MDB2::loadClass($class_name$debug);
  389.         if (PEAR::isError($err)) {
  390.             return $err;
  391.         }
  392.  
  393.         $db =new $class_name();
  394.         $db->setDSN($dsninfo);
  395.         $err MDB2::setOptions($db$options);
  396.         if (PEAR::isError($err)) {
  397.             return $err;
  398.         }
  399.  
  400.         return $db;
  401.     }
  402.  
  403.     // }}}
  404.     // {{{ function &connect($dsn, $options = false)
  405.  
  406.     /**
  407.      * Create a new MDB2_Driver_* connection object and connect to the specified
  408.      * database
  409.      *
  410.      * IMPORTANT: In order for MDB2 to work properly it is necessary that
  411.      * you make sure that you work with a reference of the original
  412.      * object instead of a copy (this is a PHP4 quirk).
  413.      *
  414.      * For example:
  415.      *     $db =& MDB2::connect($dsn);
  416.      *          ^^
  417.      * And not:
  418.      *     $db = MDB2::connect($dsn);
  419.      *          ^^
  420.      *
  421.      * @param mixed $dsn     'data source name', see the MDB2::parseDSN
  422.      *                        method for a description of the dsn format.
  423.      *                        Can also be specified as an array of the
  424.      *                        format returned by MDB2::parseDSN.
  425.      * @param array $options An associative array of option names and
  426.      *                        their values.
  427.      *
  428.      * @return mixed a newly created MDB2 connection object, or a MDB2
  429.      *                error object on error
  430.      *
  431.      * @access  public
  432.      * @see     MDB2::parseDSN
  433.      */
  434.     function &connect($dsn$options = false)
  435.     {
  436.         $db =MDB2::factory($dsn$options);
  437.         if (PEAR::isError($db)) {
  438.             return $db;
  439.         }
  440.  
  441.         $err $db->connect();
  442.         if (PEAR::isError($err)) {
  443.             $dsn $db->getDSN('string''xxx');
  444.             $db->disconnect();
  445.             $err->addUserInfo($dsn);
  446.             return $err;
  447.         }
  448.  
  449.         return $db;
  450.     }
  451.  
  452.     // }}}
  453.     // {{{ function &singleton($dsn = null, $options = false)
  454.  
  455.     /**
  456.      * Returns a MDB2 connection with the requested DSN.
  457.      * A new MDB2 connection object is only created if no object with the
  458.      * requested DSN exists yet.
  459.      *
  460.      * IMPORTANT: In order for MDB2 to work properly it is necessary that
  461.      * you make sure that you work with a reference of the original
  462.      * object instead of a copy (this is a PHP4 quirk).
  463.      *
  464.      * For example:
  465.      *     $db =& MDB2::singleton($dsn);
  466.      *          ^^
  467.      * And not:
  468.      *     $db = MDB2::singleton($dsn);
  469.      *          ^^
  470.      *
  471.      * @param   mixed   'data source name', see the MDB2::parseDSN
  472.      *                             method for a description of the dsn format.
  473.      *                             Can also be specified as an array of the
  474.      *                             format returned by MDB2::parseDSN.
  475.      * @param   array   An associative array of option names and
  476.      *                             their values.
  477.      *
  478.      * @return  mixed   a newly created MDB2 connection object, or a MDB2
  479.      *                   error object on error
  480.      *
  481.      * @access  public
  482.      * @see     MDB2::parseDSN
  483.      */
  484.     function &singleton($dsn = null$options = false)
  485.     {
  486.         if ($dsn{
  487.             $dsninfo MDB2::parseDSN($dsn);
  488.             $dsninfo array_merge($GLOBALS['_MDB2_dsninfo_default']$dsninfo);
  489.             $keys array_keys($GLOBALS['_MDB2_databases']);
  490.             for ($i=0$j=count($keys)$i<$j; ++$i{
  491.                 if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) {
  492.                     $tmp_dsn $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array');
  493.                     if (count(array_diff_assoc($tmp_dsn$dsninfo)) == 0{
  494.                         MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]]$options);
  495.                         return $GLOBALS['_MDB2_databases'][$keys[$i]];
  496.                     }
  497.                 }
  498.             }
  499.         elseif (is_array($GLOBALS['_MDB2_databases']&& reset($GLOBALS['_MDB2_databases'])) {
  500.             $db =$GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])];
  501.             return $db;
  502.         }
  503.         $db =MDB2::factory($dsn$options);
  504.         return $db;
  505.     }
  506.  
  507.     // }}}
  508.     // {{{ function areEquals()
  509.  
  510.     /**
  511.      * It looks like there's a memory leak in array_diff() in PHP 5.1.x,
  512.      * so use this method instead.
  513.      * @see http://pear.php.net/bugs/bug.php?id=11790
  514.      *
  515.      * @param array $arr1 
  516.      * @param array $arr2 
  517.      * @return boolean 
  518.      */
  519.     function areEquals($arr1$arr2)
  520.     {
  521.         if (count($arr1!= count($arr2)) {
  522.             return false;
  523.         }
  524.         foreach (array_keys($arr1as $k{
  525.             if (!array_key_exists($k$arr2|| $arr1[$k!= $arr2[$k]{
  526.                 return false;
  527.             }
  528.         }
  529.         return true;
  530.     }
  531.  
  532.     // }}}
  533.     // {{{ function loadFile($file)
  534.  
  535.     /**
  536.      * load a file (like 'Date')
  537.      *
  538.      * @param   string  name of the file in the MDB2 directory (without '.php')
  539.      *
  540.      * @return  string  name of the file that was included
  541.      *
  542.      * @access  public
  543.      */
  544.     function loadFile($file)
  545.     {
  546.         $file_name 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php';
  547.         if (!MDB2::fileExists($file_name)) {
  548.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  549.                 'unable to find: '.$file_name);
  550.         }
  551.         if (!include_once($file_name)) {
  552.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  553.                 'unable to load driver class: '.$file_name);
  554.         }
  555.         return $file_name;
  556.     }
  557.  
  558.     // }}}
  559.     // {{{ function apiVersion()
  560.  
  561.     /**
  562.      * Return the MDB2 API version
  563.      *
  564.      * @return  string  the MDB2 API version number
  565.      *
  566.      * @access  public
  567.      */
  568.     function apiVersion()
  569.     {
  570.         return '2.5.0b2';
  571.     }
  572.  
  573.     // }}}
  574.     // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
  575.  
  576.     /**
  577.      * This method is used to communicate an error and invoke error
  578.      * callbacks etc.  Basically a wrapper for PEAR::raiseError
  579.      * without the message string.
  580.      *
  581.      * @param   mixed  int error code
  582.      *
  583.      * @param   int    error mode, see PEAR_Error docs
  584.      *
  585.      * @param   mixed  If error mode is PEAR_ERROR_TRIGGER, this is the
  586.      *                  error level (E_USER_NOTICE etc).  If error mode is
  587.      *                  PEAR_ERROR_CALLBACK, this is the callback function,
  588.      *                  either as a function name, or as an array of an
  589.      *                  object and method name.  For other error modes this
  590.      *                  parameter is ignored.
  591.      *
  592.      * @param   string Extra debug information.  Defaults to the last
  593.      *                  query and native error code.
  594.      *
  595.      * @return PEAR_Error instance of a PEAR Error object
  596.      *
  597.      * @access  private
  598.      * @see     PEAR_Error
  599.      */
  600.     function &raiseError($code = null,
  601.                          $mode = null,
  602.                          $options = null,
  603.                          $userinfo = null,
  604.                          $dummy1 = null,
  605.                          $dummy2 = null,
  606.                          $dummy3 = false)
  607.     {
  608.         $err =PEAR::raiseError(null$code$mode$options$userinfo'MDB2_Error'true);
  609.         return $err;
  610.     }
  611.  
  612.     // }}}
  613.     // {{{ function isError($data, $code = null)
  614.  
  615.     /**
  616.      * Tell whether a value is a MDB2 error.
  617.      *
  618.      * @param   mixed   the value to test
  619.      * @param   int     if is an error object, return true
  620.      *                         only if $code is a string and
  621.      *                         $db->getMessage() == $code or
  622.      *                         $code is an integer and $db->getCode() == $code
  623.      *
  624.      * @return  bool    true if parameter is an error
  625.      *
  626.      * @access  public
  627.      */
  628.     function isError($data$code = null)
  629.     {
  630.         if (is_a($data'MDB2_Error')) {
  631.             if (is_null($code)) {
  632.                 return true;
  633.             elseif (is_string($code)) {
  634.                 return $data->getMessage(=== $code;
  635.             else {
  636.                 $code = (array)$code;
  637.                 return in_array($data->getCode()$code);
  638.             }
  639.         }
  640.         return false;
  641.     }
  642.  
  643.     // }}}
  644.     // {{{ function isConnection($value)
  645.  
  646.     /**
  647.      * Tell whether a value is a MDB2 connection
  648.      *
  649.      * @param   mixed   value to test
  650.      *
  651.      * @return  bool    whether $value is a MDB2 connection
  652.      *
  653.      * @access  public
  654.      */
  655.     function isConnection($value)
  656.     {
  657.         return is_a($value'MDB2_Driver_Common');
  658.     }
  659.  
  660.     // }}}
  661.     // {{{ function isResult($value)
  662.  
  663.     /**
  664.      * Tell whether a value is a MDB2 result
  665.      *
  666.      * @param   mixed   value to test
  667.      *
  668.      * @return  bool    whether $value is a MDB2 result
  669.      *
  670.      * @access  public
  671.      */
  672.     function isResult($value)
  673.     {
  674.         return is_a($value'MDB2_Result');
  675.     }
  676.  
  677.     // }}}
  678.     // {{{ function isResultCommon($value)
  679.  
  680.     /**
  681.      * Tell whether a value is a MDB2 result implementing the common interface
  682.      *
  683.      * @param   mixed   value to test
  684.      *
  685.      * @return  bool    whether $value is a MDB2 result implementing the common interface
  686.      *
  687.      * @access  public
  688.      */
  689.     function isResultCommon($value)
  690.     {
  691.         return is_a($value'MDB2_Result_Common');
  692.     }
  693.  
  694.     // }}}
  695.     // {{{ function isStatement($value)
  696.  
  697.     /**
  698.      * Tell whether a value is a MDB2 statement interface
  699.      *
  700.      * @param   mixed   value to test
  701.      *
  702.      * @return  bool    whether $value is a MDB2 statement interface
  703.      *
  704.      * @access  public
  705.      */
  706.     function isStatement($value)
  707.     {
  708.         return is_a($value'MDB2_Statement_Common');
  709.     }
  710.  
  711.     // }}}
  712.     // {{{ function errorMessage($value = null)
  713.  
  714.     /**
  715.      * Return a textual error message for a MDB2 error code
  716.      *
  717.      * @param   int|array  integer error code,
  718.                                 null to get the current error code-message map,
  719.                                 or an array with a new error code-message map
  720.      *
  721.      * @return  string  error message, or false if the error code was
  722.      *                   not recognized
  723.      *
  724.      * @access  public
  725.      */
  726.     function errorMessage($value = null)
  727.     {
  728.         static $errorMessages;
  729.  
  730.         if (is_array($value)) {
  731.             $errorMessages $value;
  732.             return MDB2_OK;
  733.         }
  734.  
  735.         if (!isset($errorMessages)) {
  736.             $errorMessages = array(
  737.                 MDB2_OK                       => 'no error',
  738.                 MDB2_ERROR                    => 'unknown error',
  739.                 MDB2_ERROR_ALREADY_EXISTS     => 'already exists',
  740.                 MDB2_ERROR_CANNOT_CREATE      => 'can not create',
  741.                 MDB2_ERROR_CANNOT_ALTER       => 'can not alter',
  742.                 MDB2_ERROR_CANNOT_REPLACE     => 'can not replace',
  743.                 MDB2_ERROR_CANNOT_DELETE      => 'can not delete',
  744.                 MDB2_ERROR_CANNOT_DROP        => 'can not drop',
  745.                 MDB2_ERROR_CONSTRAINT         => 'constraint violation',
  746.                 MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
  747.                 MDB2_ERROR_DIVZERO            => 'division by zero',
  748.                 MDB2_ERROR_INVALID            => 'invalid',
  749.                 MDB2_ERROR_INVALID_DATE       => 'invalid date or time',
  750.                 MDB2_ERROR_INVALID_NUMBER     => 'invalid number',
  751.                 MDB2_ERROR_MISMATCH           => 'mismatch',
  752.                 MDB2_ERROR_NODBSELECTED       => 'no database selected',
  753.                 MDB2_ERROR_NOSUCHFIELD        => 'no such field',
  754.                 MDB2_ERROR_NOSUCHTABLE        => 'no such table',
  755.                 MDB2_ERROR_NOT_CAPABLE        => 'MDB2 backend not capable',
  756.                 MDB2_ERROR_NOT_FOUND          => 'not found',
  757.                 MDB2_ERROR_NOT_LOCKED         => 'not locked',
  758.                 MDB2_ERROR_SYNTAX             => 'syntax error',
  759.                 MDB2_ERROR_UNSUPPORTED        => 'not supported',
  760.                 MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
  761.                 MDB2_ERROR_INVALID_DSN        => 'invalid DSN',
  762.                 MDB2_ERROR_CONNECT_FAILED     => 'connect failed',
  763.                 MDB2_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
  764.                 MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
  765.                 MDB2_ERROR_NOSUCHDB           => 'no such database',
  766.                 MDB2_ERROR_ACCESS_VIOLATION   => 'insufficient permissions',
  767.                 MDB2_ERROR_LOADMODULE         => 'error while including on demand module',
  768.                 MDB2_ERROR_TRUNCATED          => 'truncated',
  769.                 MDB2_ERROR_DEADLOCK           => 'deadlock detected',
  770.                 MDB2_ERROR_NO_PERMISSION      => 'no permission',
  771.                 MDB2_ERROR_DISCONNECT_FAILED  => 'disconnect failed',
  772.             );
  773.         }
  774.  
  775.         if (is_null($value)) {
  776.             return $errorMessages;
  777.         }
  778.  
  779.         if (PEAR::isError($value)) {
  780.             $value $value->getCode();
  781.         }
  782.  
  783.         return isset($errorMessages[$value]?
  784.            $errorMessages[$value$errorMessages[MDB2_ERROR];
  785.     }
  786.  
  787.     // }}}
  788.     // {{{ function parseDSN($dsn)
  789.  
  790.     /**
  791.      * Parse a data source name.
  792.      *
  793.      * Additional keys can be added by appending a URI query string to the
  794.      * end of the DSN.
  795.      *
  796.      * The format of the supplied DSN is in its fullest form:
  797.      * <code>
  798.      *  phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
  799.      * </code>
  800.      *
  801.      * Most variations are allowed:
  802.      * <code>
  803.      *  phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
  804.      *  phptype://username:password@hostspec/database_name
  805.      *  phptype://username:password@hostspec
  806.      *  phptype://username@hostspec
  807.      *  phptype://hostspec/database
  808.      *  phptype://hostspec
  809.      *  phptype(dbsyntax)
  810.      *  phptype
  811.      * </code>
  812.      *
  813.      * @param   string  Data Source Name to be parsed
  814.      *
  815.      * @return  array   an associative array with the following keys:
  816.      *   + phptype:  Database backend used in PHP (mysql, odbc etc.)
  817.      *   + dbsyntax: Database used with regards to SQL syntax etc.
  818.      *   + protocol: Communication protocol to use (tcp, unix etc.)
  819.      *   + hostspec: Host specification (hostname[:port])
  820.      *   + database: Database to use on the DBMS server
  821.      *   + username: User name for login
  822.      *   + password: Password for login
  823.      *
  824.      * @access  public
  825.      * @author  Tomas V.V.Cox <cox@idecnet.com>
  826.      */
  827.     function parseDSN($dsn)
  828.     {
  829.         $parsed $GLOBALS['_MDB2_dsninfo_default'];
  830.  
  831.         if (is_array($dsn)) {
  832.             $dsn array_merge($parsed$dsn);
  833.             if (!$dsn['dbsyntax']{
  834.                 $dsn['dbsyntax'$dsn['phptype'];
  835.             }
  836.             return $dsn;
  837.         }
  838.  
  839.         // Find phptype and dbsyntax
  840.         if (($pos strpos($dsn'://')) !== false{
  841.             $str substr($dsn0$pos);
  842.             $dsn substr($dsn$pos + 3);
  843.         else {
  844.             $str $dsn;
  845.             $dsn = null;
  846.         }
  847.  
  848.         // Get phptype and dbsyntax
  849.         // $str => phptype(dbsyntax)
  850.         if (preg_match('|^(.+?)\((.*?)\)$|'$str$arr)) {
  851.             $parsed['phptype']  $arr[1];
  852.             $parsed['dbsyntax'!$arr[2$arr[1$arr[2];
  853.         else {
  854.             $parsed['phptype']  $str;
  855.             $parsed['dbsyntax'$str;
  856.         }
  857.  
  858.         if (!count($dsn)) {
  859.             return $parsed;
  860.         }
  861.  
  862.         // Get (if found): username and password
  863.         // $dsn => username:password@protocol+hostspec/database
  864.         if (($at strrpos($dsn,'@')) !== false{
  865.             $str substr($dsn0$at);
  866.             $dsn substr($dsn$at + 1);
  867.             if (($pos strpos($str':')) !== false{
  868.                 $parsed['username'rawurldecode(substr($str0$pos));
  869.                 $parsed['password'rawurldecode(substr($str$pos + 1));
  870.             else {
  871.                 $parsed['username'rawurldecode($str);
  872.             }
  873.         }
  874.  
  875.         // Find protocol and hostspec
  876.  
  877.         // $dsn => proto(proto_opts)/database
  878.         if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|'$dsn$match)) {
  879.             $proto       $match[1];
  880.             $proto_opts  $match[2$match[2: false;
  881.             $dsn         $match[3];
  882.  
  883.         // $dsn => protocol+hostspec/database (old format)
  884.         else {
  885.             if (strpos($dsn'+'!== false{
  886.                 list($proto$dsnexplode('+'$dsn2);
  887.             }
  888.             if (   strpos($dsn'//'=== 0
  889.                 && strpos($dsn'/'2!== false
  890.                 && $parsed['phptype'== 'oci8'
  891.             {
  892.                 //oracle's "Easy Connect" syntax:
  893.                 //"username/password@[//]host[:port][/service_name]"
  894.                 //e.g. "scott/tiger@//mymachine:1521/oracle"
  895.                 $proto_opts $dsn;
  896.                 $dsn substr($proto_optsstrrpos($proto_opts'/'+ 1);
  897.             elseif (strpos($dsn'/'!== false{
  898.                 list($proto_opts$dsnexplode('/'$dsn2);
  899.             else {
  900.                 $proto_opts $dsn;
  901.                 $dsn = null;
  902.             }
  903.         }
  904.  
  905.         // process the different protocol options
  906.         $parsed['protocol'(!empty($proto)) $proto 'tcp';
  907.         $proto_opts rawurldecode($proto_opts);
  908.         if (strpos($proto_opts':'!== false{
  909.             list($proto_opts$parsed['port']explode(':'$proto_opts);
  910.         }
  911.         if ($parsed['protocol'== 'tcp'{
  912.             $parsed['hostspec'$proto_opts;
  913.         elseif ($parsed['protocol'== 'unix'{
  914.             $parsed['socket'$proto_opts;
  915.         }
  916.  
  917.         // Get dabase if any
  918.         // $dsn => database
  919.         if ($dsn{
  920.             // /database
  921.             if (($pos strpos($dsn'?')) === false{
  922.                 $parsed['database'$dsn;
  923.             // /database?param1=value1&param2=value2
  924.             else {
  925.                 $parsed['database'substr($dsn0$pos);
  926.                 $dsn substr($dsn$pos + 1);
  927.                 if (strpos($dsn'&'!== false{
  928.                     $opts explode('&'$dsn);
  929.                 else // database?param1=value1
  930.                     $opts = array($dsn);
  931.                 }
  932.                 foreach ($opts as $opt{
  933.                     list($key$valueexplode('='$opt);
  934.                     if (!isset($parsed[$key])) {
  935.                         // don't allow params overwrite
  936.                         $parsed[$keyrawurldecode($value);
  937.                     }
  938.                 }
  939.             }
  940.         }
  941.  
  942.         return $parsed;
  943.     }
  944.  
  945.     // }}}
  946.     // {{{ function fileExists($file)
  947.  
  948.     /**
  949.      * Checks if a file exists in the include path
  950.      *
  951.      * @param   string  filename
  952.      *
  953.      * @return  bool    true success and false on error
  954.      *
  955.      * @access  public
  956.      */
  957.     function fileExists($file)
  958.     {
  959.         // safe_mode does notwork with is_readable()
  960.         if (!@ini_get('safe_mode')) {
  961.              $dirs explode(PATH_SEPARATORini_get('include_path'));
  962.              foreach ($dirs as $dir{
  963.                  if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
  964.                      return true;
  965.                  }
  966.             }
  967.         else {
  968.             $fp @fopen($file'r'true);
  969.             if (is_resource($fp)) {
  970.                 @fclose($fp);
  971.                 return true;
  972.             }
  973.         }
  974.         return false;
  975.     }
  976.     // }}}
  977. }
  978.  
  979. // }}}
  980. // {{{ class MDB2_Error extends PEAR_Error
  981.  
  982. /**
  983.  * MDB2_Error implements a class for reporting portable database error
  984.  * messages.
  985.  *
  986.  * @package     MDB2
  987.  * @category    Database
  988.  * @author Stig Bakken <ssb@fast.no>
  989.  */
  990. class MDB2_Error extends PEAR_Error
  991. {
  992.     // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null)
  993.  
  994.     /**
  995.      * MDB2_Error constructor.
  996.      *
  997.      * @param   mixed   MDB2 error code, or string with error message.
  998.      * @param   int     what 'error mode' to operate in
  999.      * @param   int     what error level to use for $mode & PEAR_ERROR_TRIGGER
  1000.      * @param   mixed   additional debug info, such as the last query
  1001.      */
  1002.     function MDB2_Error($code = MDB2_ERROR$mode = PEAR_ERROR_RETURN,
  1003.               $level = E_USER_NOTICE$debuginfo = null$dummy = null)
  1004.     {
  1005.         if (is_null($code)) {
  1006.             $code MDB2_ERROR;
  1007.         }
  1008.         $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code)$code,
  1009.             $mode$level$debuginfo);
  1010.     }
  1011.  
  1012.     // }}}
  1013. }
  1014.  
  1015. // }}}
  1016. // {{{ class MDB2_Driver_Common extends PEAR
  1017.  
  1018. /**
  1019.  * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
  1020.  *
  1021.  * @package     MDB2
  1022.  * @category    Database
  1023.  * @author      Lukas Smith <smith@pooteeweet.org>
  1024.  */
  1025. class MDB2_Driver_Common extends PEAR
  1026. {
  1027.     // {{{ Variables (Properties)
  1028.  
  1029.     /**
  1030.      * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array
  1031.      * @var     int 
  1032.      * @access  public
  1033.      */
  1034.     var $db_index = 0;
  1035.  
  1036.     /**
  1037.      * DSN used for the next query
  1038.      * @var     array 
  1039.      * @access  protected
  1040.      */
  1041.     var $dsn = array();
  1042.  
  1043.     /**
  1044.      * DSN that was used to create the current connection
  1045.      * @var     array 
  1046.      * @access  protected
  1047.      */
  1048.     var $connected_dsn = array();
  1049.  
  1050.     /**
  1051.      * connection resource
  1052.      * @var     mixed 
  1053.      * @access  protected
  1054.      */
  1055.     var $connection = 0;
  1056.  
  1057.     /**
  1058.      * if the current opened connection is a persistent connection
  1059.      * @var     bool 
  1060.      * @access  protected
  1061.      */
  1062.     var $opened_persistent;
  1063.  
  1064.     /**
  1065.      * the name of the database for the next query
  1066.      * @var     string 
  1067.      * @access  protected
  1068.      */
  1069.     var $database_name = '';
  1070.  
  1071.     /**
  1072.      * the name of the database currently selected
  1073.      * @var     string 
  1074.      * @access  protected
  1075.      */
  1076.     var $connected_database_name = '';
  1077.  
  1078.     /**
  1079.      * server version information
  1080.      * @var     string 
  1081.      * @access  protected
  1082.      */
  1083.     var $connected_server_info = '';
  1084.  
  1085.     /**
  1086.      * list of all supported features of the given driver
  1087.      * @var     array 
  1088.      * @access  public
  1089.      */
  1090.     var $supported = array(
  1091.         'sequences' => false,
  1092.         'indexes' => false,
  1093.         'affected_rows' => false,
  1094.         'summary_functions' => false,
  1095.         'order_by_text' => false,
  1096.         'transactions' => false,
  1097.         'savepoints' => false,
  1098.         'current_id' => false,
  1099.         'limit_queries' => false,
  1100.         'LOBs' => false,
  1101.         'replace' => false,
  1102.         'sub_selects' => false,
  1103.         'triggers' => false,
  1104.         'auto_increment' => false,
  1105.         'primary_key' => false,
  1106.         'result_introspection' => false,
  1107.         'prepared_statements' => false,
  1108.         'identifier_quoting' => false,
  1109.         'pattern_escaping' => false,
  1110.         'new_link' => false,
  1111.     );
  1112.  
  1113.     /**
  1114.      * Array of supported options that can be passed to the MDB2 instance.
  1115.      * 
  1116.      * The options can be set during object creation, using
  1117.      * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can
  1118.      * also be set after the object is created, using MDB2::setOptions() or
  1119.      * MDB2_Driver_Common::setOption().
  1120.      * The list of available option includes:
  1121.      * <ul>
  1122.      *  <li>$options['ssl'] -> boolean: determines if ssl should be used for connections</li>
  1123.      *  <li>$options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names</li>
  1124.      *  <li>$options['disable_query'] -> boolean: determines if queries should be executed</li>
  1125.      *  <li>$options['result_class'] -> string: class used for result sets</li>
  1126.      *  <li>$options['buffered_result_class'] -> string: class used for buffered result sets</li>
  1127.      *  <li>$options['result_wrap_class'] -> string: class used to wrap result sets into</li>
  1128.      *  <li>$options['result_buffering'] -> boolean should results be buffered or not?</li>
  1129.      *  <li>$options['fetch_class'] -> string: class to use when fetch mode object is used</li>
  1130.      *  <li>$options['persistent'] -> boolean: persistent connection?</li>
  1131.      *  <li>$options['debug'] -> integer: numeric debug level</li>
  1132.      *  <li>$options['debug_handler'] -> string: function/method that captures debug messages</li>
  1133.      *  <li>$options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler</li>
  1134.      *  <li>$options['default_text_field_length'] -> integer: default text field length to use</li>
  1135.      *  <li>$options['lob_buffer_length'] -> integer: LOB buffer length</li>
  1136.      *  <li>$options['log_line_break'] -> string: line-break format</li>
  1137.      *  <li>$options['idxname_format'] -> string: pattern for index name</li>
  1138.      *  <li>$options['seqname_format'] -> string: pattern for sequence name</li>
  1139.      *  <li>$options['savepoint_format'] -> string: pattern for auto generated savepoint names</li>
  1140.      *  <li>$options['statement_format'] -> string: pattern for prepared statement names</li>
  1141.      *  <li>$options['seqcol_name'] -> string: sequence column name</li>
  1142.      *  <li>$options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used</li>
  1143.      *  <li>$options['use_transactions'] -> boolean: if transaction use should be enabled</li>
  1144.      *  <li>$options['decimal_places'] -> integer: number of decimal places to handle</li>
  1145.      *  <li>$options['portability'] -> integer: portability constant</li>
  1146.      *  <li>$options['modules'] -> array: short to long module name mapping for __call()</li>
  1147.      *  <li>$options['emulate_prepared'] -> boolean: force prepared statements to be emulated</li>
  1148.      *  <li>$options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes</li>
  1149.      *  <li>$options['datatype_map_callback'] -> array: callback function/method that should be called</li>
  1150.      *  <li>$options['bindname_format'] -> string: regular expression pattern for named parameters</li>
  1151.      *  <li>$options['multi_query'] -> boolean: determines if queries returning multiple result sets should be executed</li>
  1152.      *  <li>$options['max_identifiers_length'] -> integer: max identifier length</li>
  1153.      *  <li>$options['default_fk_action_onupdate'] -> string: default FOREIGN KEY ON UPDATE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']</li>
  1154.      *  <li>$options['default_fk_action_ondelete'] -> string: default FOREIGN KEY ON DELETE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']</li>
  1155.      * </ul>
  1156.      *
  1157.      * @var     array 
  1158.      * @access  public
  1159.      * @see     MDB2::connect()
  1160.      * @see     MDB2::factory()
  1161.      * @see     MDB2::singleton()
  1162.      * @see     MDB2_Driver_Common::setOption()
  1163.      */
  1164.     var $options = array(
  1165.         'ssl' => false,
  1166.         'field_case' => CASE_LOWER,
  1167.         'disable_query' => false,
  1168.         'result_class' => 'MDB2_Result_%s',
  1169.         'buffered_result_class' => 'MDB2_BufferedResult_%s',
  1170.         'result_wrap_class' => false,
  1171.         'result_buffering' => true,
  1172.         'fetch_class' => 'stdClass',
  1173.         'persistent' => false,
  1174.         'debug' => 0,
  1175.         'debug_handler' => 'MDB2_defaultDebugOutput',
  1176.         'debug_expanded_output' => false,
  1177.         'default_text_field_length' => 4096,
  1178.         'lob_buffer_length' => 8192,
  1179.         'log_line_break' => "\n",
  1180.         'idxname_format' => '%s_idx',
  1181.         'seqname_format' => '%s_seq',
  1182.         'savepoint_format' => 'MDB2_SAVEPOINT_%s',
  1183.         'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s',
  1184.         'seqcol_name' => 'sequence',
  1185.         'quote_identifier' => false,
  1186.         'use_transactions' => true,
  1187.         'decimal_places' => 2,
  1188.         'portability' => MDB2_PORTABILITY_ALL,
  1189.         'modules' => array(
  1190.             'ex' => 'Extended',
  1191.             'dt' => 'Datatype',
  1192.             'mg' => 'Manager',
  1193.             'rv' => 'Reverse',
  1194.             'na' => 'Native',
  1195.             'fc' => 'Function',
  1196.         ),
  1197.         'emulate_prepared' => false,
  1198.         'datatype_map' => array(),
  1199.         'datatype_map_callback' => array(),
  1200.         'nativetype_map_callback' => array(),
  1201.         'lob_allow_url_include' => false,
  1202.         'bindname_format' => '(?:\d+)|(?:[a-zA-Z][a-zA-Z0-9_]*)',
  1203.         'max_identifiers_length' => 30,
  1204.         'default_fk_action_onupdate' => 'RESTRICT',
  1205.         'default_fk_action_ondelete' => 'RESTRICT',
  1206.     );
  1207.  
  1208.     /**
  1209.      * string array
  1210.      * @var     string 
  1211.      * @access  protected
  1212.      */
  1213.     var $string_quoting = array('start' => "'"'end' => "'"'escape' => false'escape_pattern' => false);
  1214.  
  1215.     /**
  1216.      * identifier quoting
  1217.      * @var     array 
  1218.      * @access  protected
  1219.      */
  1220.     var $identifier_quoting = array('start' => '"''end' => '"''escape' => '"');
  1221.  
  1222.     /**
  1223.      * sql comments
  1224.      * @var     array 
  1225.      * @access  protected
  1226.      */
  1227.     var $sql_comments = array(
  1228.         array('start' => '--''end' => "\n"'escape' => false),
  1229.         array('start' => '/*''end' => '*/''escape' => false),
  1230.     );
  1231.  
  1232.     /**
  1233.      * comparision wildcards
  1234.      * @var     array 
  1235.      * @access  protected
  1236.      */
  1237.     var $wildcards = array('%''_');
  1238.  
  1239.     /**
  1240.      * column alias keyword
  1241.      * @var     string 
  1242.      * @access  protected
  1243.      */
  1244.     var $as_keyword = ' AS ';
  1245.  
  1246.     /**
  1247.      * warnings
  1248.      * @var     array 
  1249.      * @access  protected
  1250.      */
  1251.     var $warnings = array();
  1252.  
  1253.     /**
  1254.      * string with the debugging information
  1255.      * @var     string 
  1256.      * @access  public
  1257.      */
  1258.     var $debug_output = '';
  1259.  
  1260.     /**
  1261.      * determine if there is an open transaction
  1262.      * @var     bool 
  1263.      * @access  protected
  1264.      */
  1265.     var $in_transaction = false;
  1266.  
  1267.     /**
  1268.      * the smart transaction nesting depth
  1269.      * @var     int 
  1270.      * @access  protected
  1271.      */
  1272.     var $nested_transaction_counter = null;
  1273.  
  1274.     /**
  1275.      * the first error that occured inside a nested transaction
  1276.      * @var     MDB2_Error|bool
  1277.      * @access  protected
  1278.      */
  1279.     var $has_transaction_error = false;
  1280.  
  1281.     /**
  1282.      * result offset used in the next query
  1283.      * @var     int 
  1284.      * @access  protected
  1285.      */
  1286.     var $offset = 0;
  1287.  
  1288.     /**
  1289.      * result limit used in the next query
  1290.      * @var     int 
  1291.      * @access  protected
  1292.      */
  1293.     var $limit = 0;
  1294.  
  1295.     /**
  1296.      * Database backend used in PHP (mysql, odbc etc.)
  1297.      * @var     string 
  1298.      * @access  public
  1299.      */
  1300.     var $phptype;
  1301.  
  1302.     /**
  1303.      * Database used with regards to SQL syntax etc.
  1304.      * @var     string 
  1305.      * @access  public
  1306.      */
  1307.     var $dbsyntax;
  1308.  
  1309.     /**
  1310.      * the last query sent to the driver
  1311.      * @var     string 
  1312.      * @access  public
  1313.      */
  1314.     var $last_query;
  1315.  
  1316.     /**
  1317.      * the default fetchmode used
  1318.      * @var     int 
  1319.      * @access  protected
  1320.      */
  1321.     var $fetchmode = MDB2_FETCHMODE_ORDERED;
  1322.  
  1323.     /**
  1324.      * array of module instances
  1325.      * @var     array 
  1326.      * @access  protected
  1327.      */
  1328.     var $modules = array();
  1329.  
  1330.     /**
  1331.      * determines of the PHP4 destructor emulation has been enabled yet
  1332.      * @var     array 
  1333.      * @access  protected
  1334.      */
  1335.     var $destructor_registered = true;
  1336.  
  1337.     // }}}
  1338.     // {{{ constructor: function __construct()
  1339.  
  1340.     /**
  1341.      * Constructor
  1342.      */
  1343.     function __construct()
  1344.     {
  1345.         end($GLOBALS['_MDB2_databases']);
  1346.         $db_index key($GLOBALS['_MDB2_databases']+ 1;
  1347.         $GLOBALS['_MDB2_databases'][$db_index&$this;
  1348.         $this->db_index = $db_index;
  1349.     }
  1350.  
  1351.     // }}}
  1352.     // {{{ function MDB2_Driver_Common()
  1353.  
  1354.     /**
  1355.      * PHP 4 Constructor
  1356.      */
  1357.     function MDB2_Driver_Common()
  1358.     {
  1359.         $this->destructor_registered = false;
  1360.         $this->__construct();
  1361.     }
  1362.  
  1363.     // }}}
  1364.     // {{{ destructor: function __destruct()
  1365.  
  1366.     /**
  1367.      *  Destructor
  1368.      */
  1369.     function __destruct()
  1370.     {
  1371.         $this->disconnect(false);
  1372.     }
  1373.  
  1374.     // }}}
  1375.     // {{{ function free()
  1376.  
  1377.     /**
  1378.      * Free the internal references so that the instance can be destroyed
  1379.      *
  1380.      * @return  bool    true on success, false if result is invalid
  1381.      *
  1382.      * @access  public
  1383.      */
  1384.     function free()
  1385.     {
  1386.         unset($GLOBALS['_MDB2_databases'][$this->db_index]);
  1387.         unset($this->db_index);
  1388.         return MDB2_OK;
  1389.     }
  1390.  
  1391.     // }}}
  1392.     // {{{ function __toString()
  1393.  
  1394.     /**
  1395.      * String conversation
  1396.      *
  1397.      * @return  string representation of the object
  1398.      *
  1399.      * @access  public
  1400.      */
  1401.     function __toString()
  1402.     {
  1403.         $info get_class($this);
  1404.         $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')';
  1405.         if ($this->connection{
  1406.             $info.= ' [connected]';
  1407.         }
  1408.         return $info;
  1409.     }
  1410.  
  1411.     // }}}
  1412.     // {{{ function errorInfo($error = null)
  1413.  
  1414.     /**
  1415.      * This method is used to collect information about an error
  1416.      *
  1417.      * @param   mixed   error code or resource
  1418.      *
  1419.      * @return  array   with MDB2 errorcode, native error code, native message
  1420.      *
  1421.      * @access  public
  1422.      */
  1423.     function errorInfo($error = null)
  1424.     {
  1425.         return array($errornullnull);
  1426.     }
  1427.  
  1428.     // }}}
  1429.     // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
  1430.  
  1431.     /**
  1432.      * This method is used to communicate an error and invoke error
  1433.      * callbacks etc.  Basically a wrapper for PEAR::raiseError
  1434.      * without the message string.
  1435.      *
  1436.      * @param mixed  $code     integer error code, or a PEAR error object (all
  1437.      *                          other parameters are ignored if this parameter is
  1438.      *                          an object
  1439.      * @param int    $mode     error mode, see PEAR_Error docs
  1440.      * @param mixed  $options  If error mode is PEAR_ERROR_TRIGGER, this is the
  1441.      *                          error level (E_USER_NOTICE etc). If error mode is
  1442.      *                          PEAR_ERROR_CALLBACK, this is the callback function,
  1443.      *                          either as a function name, or as an array of an
  1444.      *                          object and method name. For other error modes this
  1445.      *                          parameter is ignored.
  1446.      * @param string $userinfo Extra debug information. Defaults to the last
  1447.      *                          query and native error code.
  1448.      * @param string $method   name of the method that triggered the error
  1449.      * @param string $dummy1   not used
  1450.      * @param bool   $dummy2   not used
  1451.      *
  1452.      * @return PEAR_Error instance of a PEAR Error object
  1453.      * @access public
  1454.      * @see    PEAR_Error
  1455.      */
  1456.     function &raiseError($code = null,
  1457.                          $mode = null,
  1458.                          $options = null,
  1459.                          $userinfo = null,
  1460.                          $method = null,
  1461.                          $dummy1 = null,
  1462.                          $dummy2 = false
  1463.     {
  1464.         $userinfo = "[Error message: $userinfo]\n";
  1465.         // The error is yet a MDB2 error object
  1466.         if (PEAR::isError($code)) {
  1467.             // because we use the static PEAR::raiseError, our global
  1468.             // handler should be used if it is set
  1469.             if (is_null($mode&& !empty($this->_default_error_mode)) {
  1470.                 $mode    $this->_default_error_mode;
  1471.                 $options $this->_default_error_options;
  1472.             }
  1473.             if (is_null($userinfo)) {
  1474.                 $userinfo $code->getUserinfo();
  1475.             }
  1476.             $code $code->getCode();
  1477.         elseif ($code == MDB2_ERROR_NOT_FOUND{
  1478.             // extension not loaded: don't call $this->errorInfo() or the script
  1479.             // will die
  1480.         elseif (isset($this->connection)) {
  1481.             if (!empty($this->last_query)) {
  1482.                 $userinfo.= "[Last executed query: {$this->last_query}]\n";
  1483.             }
  1484.             $native_errno = $native_msg = null;
  1485.             list($code, $native_errno, $native_msg) = $this->errorInfo($code);
  1486.             if (!is_null($native_errno&& $native_errno !== ''{
  1487.                 $userinfo.= "[Native code: $native_errno]\n";
  1488.             }
  1489.             if (!is_null($native_msg) && $native_msg !== '') {
  1490.                 $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n";
  1491.             }
  1492.             if (!is_null($method)) {
  1493.                 $userinfo = $method.': '.$userinfo;
  1494.             }
  1495.         }
  1496.  
  1497.         $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
  1498.         if ($err->getMode(!== PEAR_ERROR_RETURN
  1499.             && isset($this->nested_transaction_counter&& !$this->has_transaction_error{
  1500.             $this->has_transaction_error =$err;
  1501.         }
  1502.         return $err;
  1503.     }
  1504.  
  1505.     // }}}
  1506.     // {{{ function resetWarnings()
  1507.     /**
  1508.      * reset the warning array
  1509.      *
  1510.      * @return void
  1511.      *
  1512.      * @access  public
  1513.      */
  1514.     function resetWarnings()
  1515.     {
  1516.         $this->warnings = array();
  1517.     }
  1518.  
  1519.     // }}}
  1520.     // {{{ function getWarnings()
  1521.     /**
  1522.      * Get all warnings in reverse order.
  1523.      * This means that the last warning is the first element in the array
  1524.      *
  1525.      * @return  array   with warnings
  1526.      *
  1527.      * @access  public
  1528.      * @see     resetWarnings()
  1529.      */
  1530.     function getWarnings()
  1531.     {
  1532.         return array_reverse($this->warnings);
  1533.     }
  1534.  
  1535.     // }}}
  1536.     // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass')
  1537.     /**
  1538.      * Sets which fetch mode should be used by default on queries
  1539.      * on this connection
  1540.      *
  1541.      * @param   int     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC
  1542.      *                               or MDB2_FETCHMODE_OBJECT
  1543.      * @param   string  the class name of the object to be returned
  1544.      *                               by the fetch methods when the
  1545.      *                               MDB2_FETCHMODE_OBJECT mode is selected.
  1546.      *                               If no class is specified by default a cast
  1547.      *                               to object from the assoc array row will be
  1548.      *                               done.  There is also the possibility to use
  1549.      *                               and extend the 'MDB2_row' class.
  1550.      *
  1551.      * @return  mixed   MDB2_OK or MDB2 Error Object
  1552.      *
  1553.      * @access  public
  1554.      * @see     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT
  1555.      */
  1556.     function setFetchMode($fetchmode, $object_class = 'stdClass')
  1557.     {
  1558.         switch ($fetchmode) {
  1559.         case MDB2_FETCHMODE_OBJECT:
  1560.             $this->options['fetch_class'$object_class;
  1561.         case MDB2_FETCHMODE_ORDERED:
  1562.         case MDB2_FETCHMODE_ASSOC:
  1563.             $this->fetchmode = $fetchmode;
  1564.             break;
  1565.         default:
  1566.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1567.                 'invalid fetchmode mode'__FUNCTION__);
  1568.         }
  1569.  
  1570.         return MDB2_OK;
  1571.     }
  1572.  
  1573.     // }}}
  1574.     // {{{ function setOption($option, $value)
  1575.     /**
  1576.      * set the option for the db class
  1577.      *
  1578.      * @param   string  option name
  1579.      * @param   mixed   value for the option
  1580.      *
  1581.      * @return  mixed   MDB2_OK or MDB2 Error Object
  1582.      *
  1583.      * @access  public
  1584.      */
  1585.     function setOption($option, $value)
  1586.     {
  1587.         if (array_key_exists($option, $this->options)) {
  1588.             $this->options[$option$value;
  1589.             return MDB2_OK;
  1590.         }
  1591.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1592.             "unknown option $option", __FUNCTION__);
  1593.     }
  1594.  
  1595.     // }}}
  1596.     // {{{ function getOption($option)
  1597.     /**
  1598.      * Returns the value of an option
  1599.      *
  1600.      * @param   string  option name
  1601.      *
  1602.      * @return  mixed   the option value or error object
  1603.      *
  1604.      * @access  public
  1605.      */
  1606.     function getOption($option)
  1607.     {
  1608.         if (array_key_exists($option, $this->options)) {
  1609.             return $this->options[$option];
  1610.         }
  1611.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1612.             "unknown option $option", __FUNCTION__);
  1613.     }
  1614.  
  1615.     // }}}
  1616.     // {{{ function debug($message, $scope = '', $is_manip = null)
  1617.     /**
  1618.      * set a debug message
  1619.      *
  1620.      * @param   string  message that should be appended to the debug variable
  1621.      * @param   string  usually the method name that triggered the debug call:
  1622.      *                  for example 'query', 'prepare', 'execute', 'parameters',
  1623.      *                  'beginTransaction', 'commit', 'rollback'
  1624.      * @param   array   contains context information about the debug() call
  1625.      *                  common keys are: is_manip, time, result etc.
  1626.      *
  1627.      * @return void
  1628.      *
  1629.      * @access  public
  1630.      */
  1631.     function debug($message, $scope = '', $context = array())
  1632.     {
  1633.         if ($this->options['debug'&& $this->options['debug_handler']{
  1634.             if (!$this->options['debug_expanded_output']{
  1635.                 if (!empty($context['when']) && $context['when'] !== 'pre') {
  1636.                     return null;
  1637.                 }
  1638.                 $context = empty($context['is_manip']) ? false : $context['is_manip'];
  1639.             }
  1640.             return call_user_func_array($this->options['debug_handler']array(&$this$scope$message$context));
  1641.         }
  1642.         return null;
  1643.     }
  1644.  
  1645.     // }}}
  1646.     // {{{ function getDebugOutput()
  1647.     /**
  1648.      * output debug info
  1649.      *
  1650.      * @return  string  content of the debug_output class variable
  1651.      *
  1652.      * @access  public
  1653.      */
  1654.     function getDebugOutput()
  1655.     {
  1656.         return $this->debug_output;
  1657.     }
  1658.  
  1659.     // }}}
  1660.     // {{{ function escape($text)
  1661.     /**
  1662.      * Quotes a string so it can be safely used in a query. It will quote
  1663.      * the text so it can safely be used within a query.
  1664.      *
  1665.      * @param   string  the input string to quote
  1666.      * @param   bool    escape wildcards
  1667.      *
  1668.      * @return  string  quoted string
  1669.      *
  1670.      * @access  public
  1671.      */
  1672.     function escape($text, $escape_wildcards = false)
  1673.     {
  1674.         if ($escape_wildcards) {
  1675.             $text = $this->escapePattern($text);
  1676.         }
  1677.  
  1678.         $text = str_replace($this->string_quoting['end']$this->string_quoting['escape'$this->string_quoting['end']$text);
  1679.         return $text;
  1680.     }
  1681.  
  1682.     // }}}
  1683.     // {{{ function escapePattern($text)
  1684.     /**
  1685.      * Quotes pattern (% and _) characters in a string)
  1686.      *
  1687.      * @param   string  the input string to quote
  1688.      *
  1689.      * @return  string  quoted string
  1690.      *
  1691.      * @access  public
  1692.      */
  1693.     function escapePattern($text)
  1694.     {
  1695.         if ($this->string_quoting['escape_pattern']{
  1696.             $text = str_replace($this->string_quoting['escape_pattern']$this->string_quoting['escape_pattern'$this->string_quoting['escape_pattern']$text);
  1697.             foreach ($this->wildcards as $wildcard{
  1698.                 $text = str_replace($wildcard, $this->string_quoting['escape_pattern'$wildcard$text);
  1699.             }
  1700.         }
  1701.         return $text;
  1702.     }
  1703.  
  1704.     // }}}
  1705.     // {{{ function quoteIdentifier($str, $check_option = false)
  1706.     /**
  1707.      * Quote a string so it can be safely used as a table or column name
  1708.      *
  1709.      * Delimiting style depends on which database driver is being used.
  1710.      *
  1711.      * NOTE: just because you CAN use delimited identifiers doesn't mean
  1712.      * you SHOULD use them.  In general, they end up causing way more
  1713.      * problems than they solve.
  1714.      *
  1715.      * NOTE: if you have table names containing periods, don't use this method
  1716.      * (@see bug #11906)
  1717.      *
  1718.      * Portability is broken by using the following characters inside
  1719.      * delimited identifiers:
  1720.      *   + backtick (<kbd>`</kbd>) -- due to MySQL
  1721.      *   + double quote (<kbd>"</kbd>) -- due to Oracle
  1722.      *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
  1723.      *
  1724.      * Delimited identifiers are known to generally work correctly under
  1725.      * the following drivers:
  1726.      *   + mssql
  1727.      *   + mysql
  1728.      *   + mysqli
  1729.      *   + oci8
  1730.      *   + pgsql
  1731.      *   + sqlite
  1732.      *
  1733.      * InterBase doesn't seem to be able to use delimited identifiers
  1734.      * via PHP 4.  They work fine under PHP 5.
  1735.      *
  1736.      * @param   string  identifier name to be quoted
  1737.      * @param   bool    check the 'quote_identifier' option
  1738.      *
  1739.      * @return  string  quoted identifier string
  1740.      *
  1741.      * @access  public
  1742.      */
  1743.     function quoteIdentifier($str, $check_option = false)
  1744.     {
  1745.         if ($check_option && !$this->options['quote_identifier']{
  1746.             return $str;
  1747.         }
  1748.         $str = str_replace($this->identifier_quoting['end']$this->identifier_quoting['escape'$this->identifier_quoting['end']$str);
  1749.         $parts = explode('.'$str);
  1750.         foreach (array_keys($partsas $k{
  1751.             $parts[$k] = $this->identifier_quoting['start'$parts[$k$this->identifier_quoting['end'];
  1752.         }
  1753.         return implode('.', $parts);
  1754.     }
  1755.  
  1756.     // }}}
  1757.     // {{{ function getAsKeyword()
  1758.     /**
  1759.      * Gets the string to alias column
  1760.      *
  1761.      * @return string to use when aliasing a column
  1762.      */
  1763.     function getAsKeyword()
  1764.     {
  1765.         return $this->as_keyword;
  1766.     }
  1767.  
  1768.     // }}}
  1769.     // {{{ function getConnection()
  1770.     /**
  1771.      * Returns a native connection
  1772.      *
  1773.      * @return  mixed   a valid MDB2 connection object,
  1774.      *                  or a MDB2 error object on error
  1775.      *
  1776.      * @access  public
  1777.      */
  1778.     function getConnection()
  1779.     {
  1780.         $result = $this->connect();
  1781.         if (PEAR::isError($result)) {
  1782.             return $result;
  1783.         }
  1784.         return $this->connection;
  1785.     }
  1786.  
  1787.      // }}}
  1788.     // {{{ function _fixResultArrayValues(&$row, $mode)
  1789.     /**
  1790.      * Do all necessary conversions on result arrays to fix DBMS quirks
  1791.      *
  1792.      * @param   array   the array to be fixed (passed by reference)
  1793.      * @param   array   bit-wise addition of the required portability modes
  1794.      *
  1795.      * @return  void
  1796.      *
  1797.      * @access  protected
  1798.      */
  1799.     function _fixResultArrayValues(&$row, $mode)
  1800.     {
  1801.         switch ($mode) {
  1802.         case MDB2_PORTABILITY_EMPTY_TO_NULL:
  1803.             foreach ($row as $key => $value) {
  1804.                 if ($value === '') {
  1805.                     $row[$key] = null;
  1806.                 }
  1807.             }
  1808.             break;
  1809.         case MDB2_PORTABILITY_RTRIM:
  1810.             foreach ($row as $key => $value) {
  1811.                 if (is_string($value)) {
  1812.                     $row[$key] = rtrim($value);
  1813.                 }
  1814.             }
  1815.             break;
  1816.         case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES:
  1817.             $tmp_row = array();
  1818.             foreach ($row as $key => $value) {
  1819.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1820.             }
  1821.             $row = $tmp_row;
  1822.             break;
  1823.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL):
  1824.             foreach ($row as $key => $value) {
  1825.                 if ($value === '') {
  1826.                     $row[$key] = null;
  1827.                 } elseif (is_string($value)) {
  1828.                     $row[$key] = rtrim($value);
  1829.                 }
  1830.             }
  1831.             break;
  1832.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1833.             $tmp_row = array();
  1834.             foreach ($row as $key => $value) {
  1835.                 if (is_string($value)) {
  1836.                     $value = rtrim($value);
  1837.                 }
  1838.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1839.             }
  1840.             $row = $tmp_row;
  1841.             break;
  1842.         case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1843.             $tmp_row = array();
  1844.             foreach ($row as $key => $value) {
  1845.                 if ($value === '') {
  1846.                     $value = null;
  1847.                 }
  1848.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1849.             }
  1850.             $row = $tmp_row;
  1851.             break;
  1852.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1853.             $tmp_row = array();
  1854.             foreach ($row as $key => $value) {
  1855.                 if ($value === '') {
  1856.                     $value = null;
  1857.                 } elseif (is_string($value)) {
  1858.                     $value = rtrim($value);
  1859.                 }
  1860.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1861.             }
  1862.             $row = $tmp_row;
  1863.             break;
  1864.         }
  1865.     }
  1866.  
  1867.     // }}}
  1868.     // {{{ function &loadModule($module, $property = null, $phptype_specific = null)
  1869.     /**
  1870.      * loads a module
  1871.      *
  1872.      * @param   string  name of the module that should be loaded
  1873.      *                  (only used for error messages)
  1874.      * @param   string  name of the property into which the class will be loaded
  1875.      * @param   bool    if the class to load for the module is specific to the
  1876.      *                  phptype
  1877.      *
  1878.      * @return  object  on success a reference to the given module is returned
  1879.      *                  and on failure a PEAR error
  1880.      *
  1881.      * @access  public
  1882.      */
  1883.     function &loadModule($module, $property = null, $phptype_specific = null)
  1884.     {
  1885.         if (!$property) {
  1886.             $property = strtolower($module);
  1887.         }
  1888.  
  1889.         if (!isset($this->{$property})) {
  1890.             $version = $phptype_specific;
  1891.             if ($phptype_specific !== false) {
  1892.                 $version = true;
  1893.                 $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype;
  1894.                 $file_name = str_replace('_'DIRECTORY_SEPARATOR$class_name).'.php';
  1895.             }
  1896.             if ($phptype_specific === false
  1897.                 || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name))
  1898.             ) {
  1899.                 $version = false;
  1900.                 $class_name = 'MDB2_'.$module;
  1901.                 $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
  1902.             }
  1903.  
  1904.             $err = MDB2::loadClass($class_name, $this->getOption('debug'));
  1905.             if (PEAR::isError($err)) {
  1906.                 return $err;
  1907.             }
  1908.  
  1909.             // load module in a specific version
  1910.             if ($version) {
  1911.                 if (method_exists($class_name, 'getClassName')) {
  1912.                     $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index);
  1913.                     if ($class_name != $class_name_new{
  1914.                         $class_name = $class_name_new;
  1915.                         $err = MDB2::loadClass($class_name, $this->getOption('debug'));
  1916.                         if (PEAR::isError($err)) {
  1917.                             return $err;
  1918.                         }
  1919.                     }
  1920.                 }
  1921.             }
  1922.  
  1923.             if (!MDB2::classExists($class_name)) {
  1924.                 $err =& $this->raiseError(MDB2_ERROR_LOADMODULEnullnull,
  1925.                     "unable to load module '$module' into property '$property'", __FUNCTION__);
  1926.                 return $err;
  1927.             }
  1928.             $this->{$property} = new $class_name($this->db_index);
  1929.             $this->modules[$module=$this->{$property};
  1930.             if ($version) {
  1931.                 // this will be used in the connect method to determine if the module
  1932.                 // needs to be loaded with a different version if the server
  1933.                 // version changed in between connects
  1934.                 $this->loaded_version_modules[$property;
  1935.             }
  1936.         }
  1937.  
  1938.         return $this->{$property};
  1939.     }
  1940.  
  1941.     // }}}
  1942.     // {{{ function __call($method, $params)
  1943.     /**
  1944.      * Calls a module method using the __call magic method
  1945.      *
  1946.      * @param   string  Method name.
  1947.      * @param   array   Arguments.
  1948.      *
  1949.      * @return  mixed   Returned value.
  1950.      */
  1951.     function __call($method, $params)
  1952.     {
  1953.         $module = null;
  1954.         if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match)
  1955.             && isset($this->options['modules'][$match[1]])
  1956.         {
  1957.             $module = $this->options['modules'][$match[1]];
  1958.             $method = strtolower($match[2]).$match[3];
  1959.             if (!isset($this->modules[$module]|| !is_object($this->modules[$module])) {
  1960.                 $result =& $this->loadModule($module);
  1961.                 if (PEAR::isError($result)) {
  1962.                     return $result;
  1963.                 }
  1964.             }
  1965.         } else {
  1966.             foreach ($this->modules as $key => $foo{
  1967.                 if (is_object($this->modules[$key])
  1968.                     && method_exists($this->modules[$key]$method)
  1969.                 {
  1970.                     $module = $key;
  1971.                     break;
  1972.                 }
  1973.             }
  1974.         }
  1975.         if (!is_null($module)) {
  1976.             return call_user_func_array(array(&$this->modules[$module]$method)$params);
  1977.         }
  1978.         trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR);
  1979.     }
  1980.  
  1981.     // }}}
  1982.     // {{{ function beginTransaction($savepoint = null)
  1983.     /**
  1984.      * Start a transaction or set a savepoint.
  1985.      *
  1986.      * @param   string  name of a savepoint to set
  1987.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  1988.      *
  1989.      * @access  public
  1990.      */
  1991.     function beginTransaction($savepoint = null)
  1992.     {
  1993.         $this->debug('Starting transaction'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  1994.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1995.             'transactions are not supported'__FUNCTION__);
  1996.     }
  1997.  
  1998.     // }}}
  1999.     // {{{ function commit($savepoint = null)
  2000.     /**
  2001.      * Commit the database changes done during a transaction that is in
  2002.      * progress or release a savepoint. This function may only be called when
  2003.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  2004.      * transaction is implicitly started after committing the pending changes.
  2005.      *
  2006.      * @param   string  name of a savepoint to release
  2007.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2008.      *
  2009.      * @access  public
  2010.      */
  2011.     function commit($savepoint = null)
  2012.     {
  2013.         $this->debug('Committing transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  2014.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2015.             'commiting transactions is not supported'__FUNCTION__);
  2016.     }
  2017.  
  2018.     // }}}
  2019.     // {{{ function rollback($savepoint = null)
  2020.     /**
  2021.      * Cancel any database changes done during a transaction or since a specific
  2022.      * savepoint that is in progress. This function may only be called when
  2023.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  2024.      * transaction is implicitly started after canceling the pending changes.
  2025.      *
  2026.      * @param   string  name of a savepoint to rollback to
  2027.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2028.      *
  2029.      * @access  public
  2030.      */
  2031.     function rollback($savepoint = null)
  2032.     {
  2033.         $this->debug('Rolling back transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  2034.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2035.             'rolling back transactions is not supported'__FUNCTION__);
  2036.     }
  2037.  
  2038.     // }}}
  2039.     // {{{ function inTransaction($ignore_nested = false)
  2040.     /**
  2041.      * If a transaction is currently open.
  2042.      *
  2043.      * @param   bool    if the nested transaction count should be ignored
  2044.      * @return  int|bool    - an integer with the nesting depth is returned if a
  2045.      *                      nested transaction is open
  2046.      *                      - true is returned for a normal open transaction
  2047.      *                      - false is returned if no transaction is open
  2048.      *
  2049.      * @access  public
  2050.      */
  2051.     function inTransaction($ignore_nested = false)
  2052.     {
  2053.         if (!$ignore_nested && isset($this->nested_transaction_counter)) {
  2054.             return $this->nested_transaction_counter;
  2055.         }
  2056.         return $this->in_transaction;
  2057.     }
  2058.  
  2059.     // }}}
  2060.     // {{{ function setTransactionIsolation($isolation)
  2061.     /**
  2062.      * Set the transacton isolation level.
  2063.      *
  2064.      * @param   string  standard isolation level
  2065.      *                  READ UNCOMMITTED (allows dirty reads)
  2066.      *                  READ COMMITTED (prevents dirty reads)
  2067.      *                  REPEATABLE READ (prevents nonrepeatable reads)
  2068.      *                  SERIALIZABLE (prevents phantom reads)
  2069.      * @param   array some transaction options:
  2070.      *                  'wait' => 'WAIT' | 'NO WAIT'
  2071.      *                  'rw'   => 'READ WRITE' | 'READ ONLY'
  2072.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2073.      *
  2074.      * @access  public
  2075.      * @since   2.1.1
  2076.      */
  2077.     function setTransactionIsolation($isolation, $options = array())
  2078.     {
  2079.         $this->debug('Setting transaction isolation level'__FUNCTION__array('is_manip' => true));
  2080.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2081.             'isolation level setting is not supported'__FUNCTION__);
  2082.     }
  2083.  
  2084.     // }}}
  2085.     // {{{ function beginNestedTransaction($savepoint = false)
  2086.     /**
  2087.      * Start a nested transaction.
  2088.      *
  2089.      * @return  mixed   MDB2_OK on success/savepoint name, a MDB2 error on failure
  2090.      *
  2091.      * @access  public
  2092.      * @since   2.1.1
  2093.      */
  2094.     function beginNestedTransaction()
  2095.     {
  2096.         if ($this->in_transaction{
  2097.             ++$this->nested_transaction_counter;
  2098.             $savepoint = sprintf($this->options['savepoint_format']$this->nested_transaction_counter);
  2099.             if ($this->supports('savepoints'&& $savepoint{
  2100.                 return $this->beginTransaction($savepoint);
  2101.             }
  2102.             return MDB2_OK;
  2103.         }
  2104.         $this->has_transaction_error = false;
  2105.         $result $this->beginTransaction();
  2106.         $this->nested_transaction_counter = 1;
  2107.         return $result;
  2108.     }
  2109.  
  2110.     // }}}
  2111.     // {{{ function completeNestedTransaction($force_rollback = false, $release = false)
  2112.     /**
  2113.      * Finish a nested transaction by rolling back if an error occured or
  2114.      * committing otherwise.
  2115.      *
  2116.      * @param   bool    if the transaction should be rolled back regardless
  2117.      *                  even if no error was set within the nested transaction
  2118.      * @return  mixed   MDB_OK on commit/counter decrementing, false on rollback
  2119.      *                  and a MDB2 error on failure
  2120.      *
  2121.      * @access  public
  2122.      * @since   2.1.1
  2123.      */
  2124.     function completeNestedTransaction($force_rollback = false)
  2125.     {
  2126.         if ($this->nested_transaction_counter > 1{
  2127.             $savepoint = sprintf($this->options['savepoint_format']$this->nested_transaction_counter);
  2128.             if ($this->supports('savepoints'&& $savepoint{
  2129.                 if ($force_rollback || $this->has_transaction_error{
  2130.                     $result = $this->rollback($savepoint);
  2131.                     if (!PEAR::isError($result)) {
  2132.                         $result = false;
  2133.                         $this->has_transaction_error = false;
  2134.                     }
  2135.                 } else {
  2136.                     $result = $this->commit($savepoint);
  2137.                 }
  2138.             } else {
  2139.                 $result = MDB2_OK;
  2140.             }
  2141.             --$this->nested_transaction_counter;
  2142.             return $result;
  2143.         }
  2144.  
  2145.         $this->nested_transaction_counter = null;
  2146.         $result = MDB2_OK;
  2147.  
  2148.         // transaction has not yet been rolled back
  2149.         if ($this->in_transaction{
  2150.             if ($force_rollback || $this->has_transaction_error{
  2151.                 $result = $this->rollback();
  2152.                 if (!PEAR::isError($result)) {
  2153.                     $result = false;
  2154.                 }
  2155.             } else {
  2156.                 $result = $this->commit();
  2157.             }
  2158.         }
  2159.         $this->has_transaction_error = false;
  2160.         return $result;
  2161.     }
  2162.  
  2163.     // }}}
  2164.     // {{{ function failNestedTransaction($error = null, $immediately = false)
  2165.     /**
  2166.      * Force setting nested transaction to failed.
  2167.      *
  2168.      * @param   mixed   value to return in getNestededTransactionError()
  2169.      * @param   bool    if the transaction should be rolled back immediately
  2170.      * @return  bool    MDB2_OK
  2171.      *
  2172.      * @access  public
  2173.      * @since   2.1.1
  2174.      */
  2175.     function failNestedTransaction($error = null, $immediately = false)
  2176.     {
  2177.         if (is_null($error)) {
  2178.             $error = $this->has_transaction_error ? $this->has_transaction_error : true;
  2179.         } elseif (!$error) {
  2180.             $error = true;
  2181.         }
  2182.         $this->has_transaction_error = $error;
  2183.         if (!$immediately{
  2184.             return MDB2_OK;
  2185.         }
  2186.         return $this->rollback();
  2187.     }
  2188.  
  2189.     // }}}
  2190.     // {{{ function getNestedTransactionError()
  2191.     /**
  2192.      * The first error that occured since the transaction start.
  2193.      *
  2194.      * @return  MDB2_Error|bool     MDB2 error object if an error occured or false.
  2195.      *
  2196.      * @access  public
  2197.      * @since   2.1.1
  2198.      */
  2199.     function getNestedTransactionError()
  2200.     {
  2201.         return $this->has_transaction_error;
  2202.     }
  2203.  
  2204.     // }}}
  2205.     // {{{ connect()
  2206.     /**
  2207.      * Connect to the database
  2208.      *
  2209.      * @return true on success, MDB2 Error Object on failure
  2210.      */
  2211.     function connect()
  2212.     {
  2213.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2214.             'method not implemented'__FUNCTION__);
  2215.     }
  2216.  
  2217.     // }}}
  2218.     // {{{ databaseExists()
  2219.     /**
  2220.      * check if given database name is exists?
  2221.      *
  2222.      * @param string $name    name of the database that should be checked
  2223.      *
  2224.      * @return mixed true/false on success, a MDB2 error on failure
  2225.      * @access public
  2226.      */
  2227.     function databaseExists($name)
  2228.     {
  2229.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2230.             'method not implemented'__FUNCTION__);
  2231.     }
  2232.  
  2233.     // }}}
  2234.     // {{{ setCharset($charset, $connection = null)
  2235.     /**
  2236.      * Set the charset on the current connection
  2237.      *
  2238.      * @param string    charset
  2239.      * @param resource  connection handle
  2240.      *
  2241.      * @return true on success, MDB2 Error Object on failure
  2242.      */
  2243.     function setCharset($charset, $connection = null)
  2244.     {
  2245.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2246.             'method not implemented'__FUNCTION__);
  2247.     }
  2248.  
  2249.     // }}}
  2250.     // {{{ function disconnect($force = true)
  2251.     /**
  2252.      * Log out and disconnect from the database.
  2253.      *
  2254.      * @param boolean $force whether the disconnect should be forced even if the
  2255.      *                       connection is opened persistently
  2256.      *
  2257.      * @return mixed true on success, false if not connected and error object on error
  2258.      *
  2259.      * @access  public
  2260.      */
  2261.     function disconnect($force = true)
  2262.     {
  2263.         $this->connection = 0;
  2264.         $this->connected_dsn = array();
  2265.         $this->connected_database_name = '';
  2266.         $this->opened_persistent = null;
  2267.         $this->connected_server_info = '';
  2268.         $this->in_transaction = null;
  2269.         $this->nested_transaction_counter = null;
  2270.         return MDB2_OK;
  2271.     }
  2272.  
  2273.     // }}}
  2274.     // {{{ function setDatabase($name)
  2275.     /**
  2276.      * Select a different database
  2277.      *
  2278.      * @param   string  name of the database that should be selected
  2279.      *
  2280.      * @return  string  name of the database previously connected to
  2281.      *
  2282.      * @access  public
  2283.      */
  2284.     function setDatabase($name)
  2285.     {
  2286.         $previous_database_name = (isset($this->database_name)) $this->database_name : '';
  2287.         $this->database_name = $name;
  2288.         if (!empty($this->connected_database_name&& ($this->connected_database_name != $this->database_name)) {
  2289.             $this->disconnect(false);
  2290.         }
  2291.         return $previous_database_name;
  2292.     }
  2293.  
  2294.     // }}}
  2295.     // {{{ function getDatabase()
  2296.     /**
  2297.      * Get the current database
  2298.      *
  2299.      * @return  string  name of the database
  2300.      *
  2301.      * @access  public
  2302.      */
  2303.     function getDatabase()
  2304.     {
  2305.         return $this->database_name;
  2306.     }
  2307.  
  2308.     // }}}
  2309.     // {{{ function setDSN($dsn)
  2310.     /**
  2311.      * set the DSN
  2312.      *
  2313.      * @param   mixed   DSN string or array
  2314.      *
  2315.      * @return  MDB2_OK
  2316.      *
  2317.      * @access  public
  2318.      */
  2319.     function setDSN($dsn)
  2320.     {
  2321.         $dsn_default = $GLOBALS['_MDB2_dsninfo_default'];
  2322.         $dsn = MDB2::parseDSN($dsn);
  2323.         if (array_key_exists('database', $dsn)) {
  2324.             $this->database_name = $dsn['database'];
  2325.             unset($dsn['database']);
  2326.         }
  2327.         $this->dsn = array_merge($dsn_default$dsn);
  2328.         return $this->disconnect(false);
  2329.     }
  2330.  
  2331.     // }}}
  2332.     // {{{ function getDSN($type = 'string', $hidepw = false)
  2333.     /**
  2334.      * return the DSN as a string
  2335.      *
  2336.      * @param   string  format to return ("array", "string")
  2337.      * @param   string  string to hide the password with
  2338.      *
  2339.      * @return  mixed   DSN in the chosen type
  2340.      *
  2341.      * @access  public
  2342.      */
  2343.     function getDSN($type = 'string', $hidepw = false)
  2344.     {
  2345.         $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn);
  2346.         $dsn['phptype'$this->phptype;
  2347.         $dsn['database'$this->database_name;
  2348.         if ($hidepw{
  2349.             $dsn['password'] = $hidepw;
  2350.         }
  2351.         switch ($type) {
  2352.         // expand to include all possible options
  2353.         case 'string':
  2354.            $dsn = $dsn['phptype'].
  2355.                ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : '').
  2356.                '://'.$dsn['username'].':'.
  2357.                 $dsn['password'].'@'.$dsn['hostspec'].
  2358.                 ($dsn['port'] ? (':'.$dsn['port']) : '').
  2359.                 '/'.$dsn['database'];
  2360.             break;
  2361.         case 'array':
  2362.         default:
  2363.             break;
  2364.         }
  2365.         return $dsn;
  2366.     }
  2367.  
  2368.     // }}}
  2369.     // {{{ _isNewLinkSet()
  2370.     /**
  2371.      * Check if the 'new_link' option is set
  2372.      *
  2373.      * @return boolean
  2374.      *
  2375.      * @access protected
  2376.      */
  2377.     function _isNewLinkSet()
  2378.     {
  2379.         return (isset($this->dsn['new_link'])
  2380.             && ($this->dsn['new_link'=== true
  2381.              || (is_string($this->dsn['new_link']&& preg_match('/^true$/i'$this->dsn['new_link']))
  2382.              || (is_numeric($this->dsn['new_link']&& 0 != (int)$this->dsn['new_link'])
  2383.             )
  2384.         );
  2385.     }
  2386.  
  2387.     // }}}
  2388.     // {{{ function &standaloneQuery($query, $types = null, $is_manip = false)
  2389.    /**
  2390.      * execute a query as database administrator
  2391.      *
  2392.      * @param   string  the SQL query
  2393.      * @param   mixed   array that contains the types of the columns in
  2394.      *                        the result set
  2395.      * @param   bool    if the query is a manipulation query
  2396.      *
  2397.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2398.      *
  2399.      * @access  public
  2400.      */
  2401.     function &standaloneQuery($query, $types = null, $is_manip = false)
  2402.     {
  2403.         $offset = $this->offset;
  2404.         $limit $this->limit;
  2405.         $this->offset = $this->limit = 0;
  2406.         $query $this->_modifyQuery($query$is_manip$limit$offset);
  2407.  
  2408.         $connection $this->getConnection();
  2409.         if (PEAR::isError($connection)) {
  2410.             return $connection;
  2411.         }
  2412.  
  2413.         $result =& $this->_doQuery($query$is_manip$connection