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 328183 2012-10-29 15:10:42Z danielc $
  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.     static function setOptions($db$options)
  283.     {
  284.         if (is_array($options)) {
  285.             foreach ($options as $option => $value{
  286.                 $test $db->setOption($option$value);
  287.                 if (MDB2::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.     static function classExists($classname)
  308.     {
  309.         return class_exists($classnamefalse);
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ function loadClass($class_name, $debug)
  314.  
  315.     /**
  316.      * Loads a PEAR class.
  317.      *
  318.      * @param   string  classname to load
  319.      * @param   bool    if errors should be suppressed
  320.      *
  321.      * @return  mixed   true success or PEAR_Error on failure
  322.      *
  323.      * @access  public
  324.      */
  325.     static function loadClass($class_name$debug)
  326.     {
  327.         if (!MDB2::classExists($class_name)) {
  328.             $file_name str_replace('_'DIRECTORY_SEPARATOR$class_name).'.php';
  329.             if ($debug{
  330.                 $include include_once($file_name);
  331.             else {
  332.                 $include @include_once($file_name);
  333.             }
  334.             if (!$include{
  335.                 if (!MDB2::fileExists($file_name)) {
  336.                     $msg = "unable to find package '$class_name' file '$file_name'";
  337.                 else {
  338.                     $msg = "unable to load class '$class_name' from file '$file_name'";
  339.                 }
  340.                 $err MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull$msg);
  341.                 return $err;
  342.             }
  343.             if (!MDB2::classExists($class_name)) {
  344.                 $msg = "unable to load class '$class_name' from file '$file_name'";
  345.                 $err MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull$msg);
  346.                 return $err;
  347.             }
  348.         }
  349.         return MDB2_OK;
  350.     }
  351.  
  352.     // }}}
  353.     // {{{ function factory($dsn, $options = false)
  354.  
  355.     /**
  356.      * Create a new MDB2 object for the specified database type
  357.      *
  358.      * @param   mixed   'data source name', see the MDB2::parseDSN
  359.      *                       method for a description of the dsn format.
  360.      *                       Can also be specified as an array of the
  361.      *                       format returned by MDB2::parseDSN.
  362.      * @param   array   An associative array of option names and
  363.      *                             their values.
  364.      *
  365.      * @return  mixed   a newly created MDB2 object, or false on error
  366.      *
  367.      * @access  public
  368.      */
  369.     static function factory($dsn$options = false)
  370.     {
  371.         $dsninfo MDB2::parseDSN($dsn);
  372.         if (empty($dsninfo['phptype'])) {
  373.             $err MDB2::raiseError(MDB2_ERROR_NOT_FOUND,
  374.                 nullnull'no RDBMS driver specified');
  375.             return $err;
  376.         }
  377.         $class_name 'MDB2_Driver_'.$dsninfo['phptype'];
  378.  
  379.         $debug (!empty($options['debug']));
  380.         $err MDB2::loadClass($class_name$debug);
  381.         if (MDB2::isError($err)) {
  382.             return $err;
  383.         }
  384.  
  385.         $db = new $class_name();
  386.         $db->setDSN($dsninfo);
  387.         $err MDB2::setOptions($db$options);
  388.         if (MDB2::isError($err)) {
  389.             return $err;
  390.         }
  391.  
  392.         return $db;
  393.     }
  394.  
  395.     // }}}
  396.     // {{{ function connect($dsn, $options = false)
  397.  
  398.     /**
  399.      * Create a new MDB2_Driver_* connection object and connect to the specified
  400.      * database
  401.      *
  402.      * @param mixed $dsn     'data source name', see the MDB2::parseDSN
  403.      *                        method for a description of the dsn format.
  404.      *                        Can also be specified as an array of the
  405.      *                        format returned by MDB2::parseDSN.
  406.      * @param array $options An associative array of option names and
  407.      *                        their values.
  408.      *
  409.      * @return mixed a newly created MDB2 connection object, or a MDB2
  410.      *                error object on error
  411.      *
  412.      * @access  public
  413.      * @see     MDB2::parseDSN
  414.      */
  415.     static function connect($dsn$options = false)
  416.     {
  417.         $db MDB2::factory($dsn$options);
  418.         if (MDB2::isError($db)) {
  419.             return $db;
  420.         }
  421.  
  422.         $err $db->connect();
  423.         if (MDB2::isError($err)) {
  424.             $dsn $db->getDSN('string''xxx');
  425.             $db->disconnect();
  426.             $err->addUserInfo($dsn);
  427.             return $err;
  428.         }
  429.  
  430.         return $db;
  431.     }
  432.  
  433.     // }}}
  434.     // {{{ function singleton($dsn = null, $options = false)
  435.  
  436.     /**
  437.      * Returns a MDB2 connection with the requested DSN.
  438.      * A new MDB2 connection object is only created if no object with the
  439.      * requested DSN exists yet.
  440.      *
  441.      * @param   mixed   'data source name', see the MDB2::parseDSN
  442.      *                             method for a description of the dsn format.
  443.      *                             Can also be specified as an array of the
  444.      *                             format returned by MDB2::parseDSN.
  445.      * @param   array   An associative array of option names and
  446.      *                             their values.
  447.      *
  448.      * @return  mixed   a newly created MDB2 connection object, or a MDB2
  449.      *                   error object on error
  450.      *
  451.      * @access  public
  452.      * @see     MDB2::parseDSN
  453.      */
  454.     static function singleton($dsn = null$options = false)
  455.     {
  456.         if ($dsn{
  457.             $dsninfo MDB2::parseDSN($dsn);
  458.             $dsninfo array_merge($GLOBALS['_MDB2_dsninfo_default']$dsninfo);
  459.             $keys array_keys($GLOBALS['_MDB2_databases']);
  460.             for ($i=0$j=count($keys)$i<$j; ++$i{
  461.                 if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) {
  462.                     $tmp_dsn $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array');
  463.                     if (count(array_diff_assoc($tmp_dsn$dsninfo)) == 0{
  464.                         MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]]$options);
  465.                         return $GLOBALS['_MDB2_databases'][$keys[$i]];
  466.                     }
  467.                 }
  468.             }
  469.         elseif (is_array($GLOBALS['_MDB2_databases']&& reset($GLOBALS['_MDB2_databases'])) {
  470.             return $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])];
  471.         }
  472.         $db MDB2::factory($dsn$options);
  473.         return $db;
  474.     }
  475.  
  476.     // }}}
  477.     // {{{ function areEquals()
  478.  
  479.     /**
  480.      * It looks like there's a memory leak in array_diff() in PHP 5.1.x,
  481.      * so use this method instead.
  482.      * @see http://pear.php.net/bugs/bug.php?id=11790
  483.      *
  484.      * @param array $arr1 
  485.      * @param array $arr2 
  486.      * @return boolean 
  487.      */
  488.     static function areEquals($arr1$arr2)
  489.     {
  490.         if (count($arr1!= count($arr2)) {
  491.             return false;
  492.         }
  493.         foreach (array_keys($arr1as $k{
  494.             if (!array_key_exists($k$arr2|| $arr1[$k!= $arr2[$k]{
  495.                 return false;
  496.             }
  497.         }
  498.         return true;
  499.     }
  500.  
  501.     // }}}
  502.     // {{{ function loadFile($file)
  503.  
  504.     /**
  505.      * load a file (like 'Date')
  506.      *
  507.      * @param string $file name of the file in the MDB2 directory (without '.php')
  508.      *
  509.      * @return string name of the file that was included
  510.      *
  511.      * @access  public
  512.      */
  513.     static function loadFile($file)
  514.     {
  515.         $file_name 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php';
  516.         if (!MDB2::fileExists($file_name)) {
  517.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  518.                 'unable to find: '.$file_name);
  519.         }
  520.         if (!include_once($file_name)) {
  521.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  522.                 'unable to load driver class: '.$file_name);
  523.         }
  524.         return $file_name;
  525.     }
  526.  
  527.     // }}}
  528.     // {{{ function apiVersion()
  529.  
  530.     /**
  531.      * Return the MDB2 API version
  532.      *
  533.      * @return  string  the MDB2 API version number
  534.      *
  535.      * @access  public
  536.      */
  537.     static function apiVersion()
  538.     {
  539.         return '2.5.0b5';
  540.     }
  541.  
  542.     // }}}
  543.     // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
  544.  
  545.     /**
  546.      * This method is used to communicate an error and invoke error
  547.      * callbacks etc.  Basically a wrapper for PEAR::raiseError
  548.      * without the message string.
  549.      *
  550.      * @param   mixed  int error code
  551.      *
  552.      * @param   int    error mode, see PEAR_Error docs
  553.      *
  554.      * @param   mixed  If error mode is PEAR_ERROR_TRIGGER, this is the
  555.      *                  error level (E_USER_NOTICE etc).  If error mode is
  556.      *                  PEAR_ERROR_CALLBACK, this is the callback function,
  557.      *                  either as a function name, or as an array of an
  558.      *                  object and method name.  For other error modes this
  559.      *                  parameter is ignored.
  560.      *
  561.      * @param   string Extra debug information.  Defaults to the last
  562.      *                  query and native error code.
  563.      *
  564.      * @return PEAR_Error instance of a PEAR Error object
  565.      *
  566.      * @access  private
  567.      * @see     PEAR_Error
  568.      */
  569.     public static function &raiseError($code = null,
  570.                          $mode = null,
  571.                          $options = null,
  572.                          $userinfo = null,
  573.                          $dummy1 = null,
  574.                          $dummy2 = null,
  575.                          $dummy3 = false)
  576.     {
  577.         $pear = new PEAR;
  578.         $err =$pear->raiseError(null$code$mode$options$userinfo'MDB2_Error'true);
  579.         return $err;
  580.     }
  581.  
  582.     // }}}
  583.     // {{{ function isError($data, $code = null)
  584.  
  585.     /**
  586.      * Tell whether a value is a MDB2 error.
  587.      *
  588.      * @param   mixed   the value to test
  589.      * @param   int     if is an error object, return true
  590.      *                         only if $code is a string and
  591.      *                         $db->getMessage() == $code or
  592.      *                         $code is an integer and $db->getCode() == $code
  593.      *
  594.      * @return  bool    true if parameter is an error
  595.      *
  596.      * @access  public
  597.      */
  598.     static function isError($data$code = null)
  599.     {
  600.         if ($data instanceof MDB2_Error{
  601.             if (null === $code{
  602.                 return true;
  603.             }
  604.             if (is_string($code)) {
  605.                 return $data->getMessage(=== $code;
  606.             }
  607.             return in_array($data->getCode()(array)$code);
  608.         }
  609.         return false;
  610.     }
  611.  
  612.     // }}}
  613.     // {{{ function isConnection($value)
  614.  
  615.     /**
  616.      * Tell whether a value is a MDB2 connection
  617.      *
  618.      * @param   mixed   value to test
  619.      *
  620.      * @return  bool    whether $value is a MDB2 connection
  621.      * @access  public
  622.      */
  623.     static function isConnection($value)
  624.     {
  625.         return ($value instanceof MDB2_Driver_Common);
  626.     }
  627.  
  628.     // }}}
  629.     // {{{ function isResult($value)
  630.  
  631.     /**
  632.      * Tell whether a value is a MDB2 result
  633.      *
  634.      * @param mixed $value value to test
  635.      *
  636.      * @return bool whether $value is a MDB2 result
  637.      *
  638.      * @access public
  639.      */
  640.     static function isResult($value)
  641.     {
  642.         return ($value instanceof MDB2_Result);
  643.     }
  644.  
  645.     // }}}
  646.     // {{{ function isResultCommon($value)
  647.  
  648.     /**
  649.      * Tell whether a value is a MDB2 result implementing the common interface
  650.      *
  651.      * @param mixed $value value to test
  652.      *
  653.      * @return bool whether $value is a MDB2 result implementing the common interface
  654.      *
  655.      * @access  public
  656.      */
  657.     static function isResultCommon($value)
  658.     {
  659.         return ($value instanceof MDB2_Result_Common);
  660.     }
  661.  
  662.     // }}}
  663.     // {{{ function isStatement($value)
  664.  
  665.     /**
  666.      * Tell whether a value is a MDB2 statement interface
  667.      *
  668.      * @param   mixed   value to test
  669.      *
  670.      * @return  bool    whether $value is a MDB2 statement interface
  671.      *
  672.      * @access  public
  673.      */
  674.     static function isStatement($value)
  675.     {
  676.         return ($value instanceof MDB2_Statement_Common);
  677.     }
  678.  
  679.     // }}}
  680.     // {{{ function errorMessage($value = null)
  681.  
  682.     /**
  683.      * Return a textual error message for a MDB2 error code
  684.      *
  685.      * @param   int|array  integer error code,
  686.                                 null to get the current error code-message map,
  687.                                 or an array with a new error code-message map
  688.      *
  689.      * @return  string  error message, or false if the error code was
  690.      *                   not recognized
  691.      *
  692.      * @access  public
  693.      */
  694.     static function errorMessage($value = null)
  695.     {
  696.         static $errorMessages;
  697.  
  698.         if (is_array($value)) {
  699.             $errorMessages $value;
  700.             return MDB2_OK;
  701.         }
  702.  
  703.         if (!isset($errorMessages)) {
  704.             $errorMessages = array(
  705.                 MDB2_OK                       => 'no error',
  706.                 MDB2_ERROR                    => 'unknown error',
  707.                 MDB2_ERROR_ALREADY_EXISTS     => 'already exists',
  708.                 MDB2_ERROR_CANNOT_CREATE      => 'can not create',
  709.                 MDB2_ERROR_CANNOT_ALTER       => 'can not alter',
  710.                 MDB2_ERROR_CANNOT_REPLACE     => 'can not replace',
  711.                 MDB2_ERROR_CANNOT_DELETE      => 'can not delete',
  712.                 MDB2_ERROR_CANNOT_DROP        => 'can not drop',
  713.                 MDB2_ERROR_CONSTRAINT         => 'constraint violation',
  714.                 MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
  715.                 MDB2_ERROR_DIVZERO            => 'division by zero',
  716.                 MDB2_ERROR_INVALID            => 'invalid',
  717.                 MDB2_ERROR_INVALID_DATE       => 'invalid date or time',
  718.                 MDB2_ERROR_INVALID_NUMBER     => 'invalid number',
  719.                 MDB2_ERROR_MISMATCH           => 'mismatch',
  720.                 MDB2_ERROR_NODBSELECTED       => 'no database selected',
  721.                 MDB2_ERROR_NOSUCHFIELD        => 'no such field',
  722.                 MDB2_ERROR_NOSUCHTABLE        => 'no such table',
  723.                 MDB2_ERROR_NOT_CAPABLE        => 'MDB2 backend not capable',
  724.                 MDB2_ERROR_NOT_FOUND          => 'not found',
  725.                 MDB2_ERROR_NOT_LOCKED         => 'not locked',
  726.                 MDB2_ERROR_SYNTAX             => 'syntax error',
  727.                 MDB2_ERROR_UNSUPPORTED        => 'not supported',
  728.                 MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
  729.                 MDB2_ERROR_INVALID_DSN        => 'invalid DSN',
  730.                 MDB2_ERROR_CONNECT_FAILED     => 'connect failed',
  731.                 MDB2_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
  732.                 MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
  733.                 MDB2_ERROR_NOSUCHDB           => 'no such database',
  734.                 MDB2_ERROR_ACCESS_VIOLATION   => 'insufficient permissions',
  735.                 MDB2_ERROR_LOADMODULE         => 'error while including on demand module',
  736.                 MDB2_ERROR_TRUNCATED          => 'truncated',
  737.                 MDB2_ERROR_DEADLOCK           => 'deadlock detected',
  738.                 MDB2_ERROR_NO_PERMISSION      => 'no permission',
  739.                 MDB2_ERROR_DISCONNECT_FAILED  => 'disconnect failed',
  740.             );
  741.         }
  742.  
  743.         if (null === $value{
  744.             return $errorMessages;
  745.         }
  746.  
  747.         if (MDB2::isError($value)) {
  748.             $value $value->getCode();
  749.         }
  750.  
  751.         return isset($errorMessages[$value]?
  752.            $errorMessages[$value$errorMessages[MDB2_ERROR];
  753.     }
  754.  
  755.     // }}}
  756.     // {{{ function parseDSN($dsn)
  757.  
  758.     /**
  759.      * Parse a data source name.
  760.      *
  761.      * Additional keys can be added by appending a URI query string to the
  762.      * end of the DSN.
  763.      *
  764.      * The format of the supplied DSN is in its fullest form:
  765.      * <code>
  766.      *  phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
  767.      * </code>
  768.      *
  769.      * Most variations are allowed:
  770.      * <code>
  771.      *  phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
  772.      *  phptype://username:password@hostspec/database_name
  773.      *  phptype://username:password@hostspec
  774.      *  phptype://username@hostspec
  775.      *  phptype://hostspec/database
  776.      *  phptype://hostspec
  777.      *  phptype(dbsyntax)
  778.      *  phptype
  779.      * </code>
  780.      *
  781.      * @param   string  Data Source Name to be parsed
  782.      *
  783.      * @return  array   an associative array with the following keys:
  784.      *   + phptype:  Database backend used in PHP (mysql, odbc etc.)
  785.      *   + dbsyntax: Database used with regards to SQL syntax etc.
  786.      *   + protocol: Communication protocol to use (tcp, unix etc.)
  787.      *   + hostspec: Host specification (hostname[:port])
  788.      *   + database: Database to use on the DBMS server
  789.      *   + username: User name for login
  790.      *   + password: Password for login
  791.      *
  792.      * @access  public
  793.      * @author  Tomas V.V.Cox <cox@idecnet.com>
  794.      */
  795.     static function parseDSN($dsn)
  796.     {
  797.         $parsed $GLOBALS['_MDB2_dsninfo_default'];
  798.  
  799.         if (is_array($dsn)) {
  800.             $dsn array_merge($parsed$dsn);
  801.             if (!$dsn['dbsyntax']{
  802.                 $dsn['dbsyntax'$dsn['phptype'];
  803.             }
  804.             return $dsn;
  805.         }
  806.  
  807.         // Find phptype and dbsyntax
  808.         if (($pos strpos($dsn'://')) !== false{
  809.             $str substr($dsn0$pos);
  810.             $dsn substr($dsn$pos + 3);
  811.         else {
  812.             $str $dsn;
  813.             $dsn = null;
  814.         }
  815.  
  816.         // Get phptype and dbsyntax
  817.         // $str => phptype(dbsyntax)
  818.         if (preg_match('|^(.+?)\((.*?)\)$|'$str$arr)) {
  819.             $parsed['phptype']  $arr[1];
  820.             $parsed['dbsyntax'!$arr[2$arr[1$arr[2];
  821.         else {
  822.             $parsed['phptype']  $str;
  823.             $parsed['dbsyntax'$str;
  824.         }
  825.  
  826.         if (!count($dsn)) {
  827.             return $parsed;
  828.         }
  829.  
  830.         // Get (if found): username and password
  831.         // $dsn => username:password@protocol+hostspec/database
  832.         if (($at strrpos($dsn,'@')) !== false{
  833.             $str substr($dsn0$at);
  834.             $dsn substr($dsn$at + 1);
  835.             if (($pos strpos($str':')) !== false{
  836.                 $parsed['username'rawurldecode(substr($str0$pos));
  837.                 $parsed['password'rawurldecode(substr($str$pos + 1));
  838.             else {
  839.                 $parsed['username'rawurldecode($str);
  840.             }
  841.         }
  842.  
  843.         // Find protocol and hostspec
  844.  
  845.         // $dsn => proto(proto_opts)/database
  846.         if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|'$dsn$match)) {
  847.             $proto       $match[1];
  848.             $proto_opts  $match[2$match[2: false;
  849.             $dsn         $match[3];
  850.  
  851.         // $dsn => protocol+hostspec/database (old format)
  852.         else {
  853.             if (strpos($dsn'+'!== false{
  854.                 list($proto$dsnexplode('+'$dsn2);
  855.             }
  856.             if (   strpos($dsn'//'=== 0
  857.                 && strpos($dsn'/'2!== false
  858.                 && $parsed['phptype'== 'oci8'
  859.             {
  860.                 //oracle's "Easy Connect" syntax:
  861.                 //"username/password@[//]host[:port][/service_name]"
  862.                 //e.g. "scott/tiger@//mymachine:1521/oracle"
  863.                 $proto_opts $dsn;
  864.                 $pos strrpos($proto_opts'/');
  865.                 $dsn substr($proto_opts$pos + 1);
  866.                 $proto_opts substr($proto_opts0$pos);
  867.             elseif (strpos($dsn'/'!== false{
  868.                 list($proto_opts$dsnexplode('/'$dsn2);
  869.             else {
  870.                 $proto_opts $dsn;
  871.                 $dsn = null;
  872.             }
  873.         }
  874.  
  875.         // process the different protocol options
  876.         $parsed['protocol'(!empty($proto)) $proto 'tcp';
  877.         $proto_opts rawurldecode($proto_opts);
  878.         if (strpos($proto_opts':'!== false{
  879.             list($proto_opts$parsed['port']explode(':'$proto_opts);
  880.         }
  881.         if ($parsed['protocol'== 'tcp'{
  882.             $parsed['hostspec'$proto_opts;
  883.         elseif ($parsed['protocol'== 'unix'{
  884.             $parsed['socket'$proto_opts;
  885.         }
  886.  
  887.         // Get dabase if any
  888.         // $dsn => database
  889.         if ($dsn{
  890.             // /database
  891.             if (($pos strpos($dsn'?')) === false{
  892.                 $parsed['database'rawurldecode($dsn);
  893.             // /database?param1=value1&param2=value2
  894.             else {
  895.                 $parsed['database'rawurldecode(substr($dsn0$pos));
  896.                 $dsn substr($dsn$pos + 1);
  897.                 if (strpos($dsn'&'!== false{
  898.                     $opts explode('&'$dsn);
  899.                 else // database?param1=value1
  900.                     $opts = array($dsn);
  901.                 }
  902.                 foreach ($opts as $opt{
  903.                     list($key$valueexplode('='$opt);
  904.                     if (!array_key_exists($key$parsed|| false === $parsed[$key]{
  905.                         // don't allow params overwrite
  906.                         $parsed[$keyrawurldecode($value);
  907.                     }
  908.                 }
  909.             }
  910.         }
  911.  
  912.         return $parsed;
  913.     }
  914.  
  915.     // }}}
  916.     // {{{ function fileExists($file)
  917.  
  918.     /**
  919.      * Checks if a file exists in the include path
  920.      *
  921.      * @param   string  filename
  922.      *
  923.      * @return  bool    true success and false on error
  924.      *
  925.      * @access  public
  926.      */
  927.     static function fileExists($file)
  928.     {
  929.         // safe_mode does notwork with is_readable()
  930.         if (!@ini_get('safe_mode')) {
  931.              $dirs explode(PATH_SEPARATORini_get('include_path'));
  932.              foreach ($dirs as $dir{
  933.                  if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
  934.                      return true;
  935.                  }
  936.             }
  937.         else {
  938.             $fp @fopen($file'r'true);
  939.             if (is_resource($fp)) {
  940.                 @fclose($fp);
  941.                 return true;
  942.             }
  943.         }
  944.         return false;
  945.     }
  946.     // }}}
  947. }
  948.  
  949. // }}}
  950. // {{{ class MDB2_Error extends PEAR_Error
  951.  
  952. /**
  953.  * MDB2_Error implements a class for reporting portable database error
  954.  * messages.
  955.  *
  956.  * @package     MDB2
  957.  * @category    Database
  958.  * @author Stig Bakken <ssb@fast.no>
  959.  */
  960. class MDB2_Error extends PEAR_Error
  961. {
  962.     // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null)
  963.  
  964.     /**
  965.      * MDB2_Error constructor.
  966.      *
  967.      * @param   mixed   MDB2 error code, or string with error message.
  968.      * @param   int     what 'error mode' to operate in
  969.      * @param   int     what error level to use for $mode & PEAR_ERROR_TRIGGER
  970.      * @param   mixed   additional debug info, such as the last query
  971.      */
  972.     function __construct($code = MDB2_ERROR$mode = PEAR_ERROR_RETURN,
  973.               $level = E_USER_NOTICE$debuginfo = null$dummy = null)
  974.     {
  975.         if (null === $code{
  976.             $code MDB2_ERROR;
  977.         }
  978.         $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code)$code,
  979.             $mode$level$debuginfo);
  980.     }
  981.  
  982.     // }}}
  983. }
  984.  
  985. // }}}
  986. // {{{ class MDB2_Driver_Common extends PEAR
  987.  
  988. /**
  989.  * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
  990.  *
  991.  * @package     MDB2
  992.  * @category    Database
  993.  * @author      Lukas Smith <smith@pooteeweet.org>
  994.  */
  995. {
  996.     // {{{ Variables (Properties)
  997.  
  998.     /**
  999.      * @var MDB2_Driver_Datatype_Common 
  1000.      */
  1001.     public $datatype;
  1002.  
  1003.     /**
  1004.      * @var MDB2_Extended 
  1005.      */
  1006.     public $extended;
  1007.  
  1008.     /**
  1009.      * @var MDB2_Driver_Function_Common 
  1010.      */
  1011.     public $function;
  1012.  
  1013.     /**
  1014.      * @var MDB2_Driver_Manager_Common 
  1015.      */
  1016.     public $manager;
  1017.  
  1018.     /**
  1019.      * @var MDB2_Driver_Native_Commonn 
  1020.      */
  1021.     public $native;
  1022.  
  1023.     /**
  1024.      * @var MDB2_Driver_Reverse_Common 
  1025.      */
  1026.     public $reverse;
  1027.  
  1028.     /**
  1029.      * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array
  1030.      * @var     int 
  1031.      * @access  public
  1032.      */
  1033.     public $db_index = 0;
  1034.  
  1035.     /**
  1036.      * DSN used for the next query
  1037.      * @var     array 
  1038.      * @access  protected
  1039.      */
  1040.     public $dsn = array();
  1041.  
  1042.     /**
  1043.      * DSN that was used to create the current connection
  1044.      * @var     array 
  1045.      * @access  protected
  1046.      */
  1047.     public $connected_dsn = array();
  1048.  
  1049.     /**
  1050.      * connection resource
  1051.      * @var     mixed 
  1052.      * @access  protected
  1053.      */
  1054.     public $connection = 0;
  1055.  
  1056.     /**
  1057.      * if the current opened connection is a persistent connection
  1058.      * @var     bool 
  1059.      * @access  protected
  1060.      */
  1061.     public $opened_persistent;
  1062.  
  1063.     /**
  1064.      * the name of the database for the next query
  1065.      * @var     string 
  1066.      * @access  public
  1067.      */
  1068.     public $database_name = '';
  1069.  
  1070.     /**
  1071.      * the name of the database currently selected
  1072.      * @var     string 
  1073.      * @access  protected
  1074.      */
  1075.     public $connected_database_name = '';
  1076.  
  1077.     /**
  1078.      * server version information
  1079.      * @var     string 
  1080.      * @access  protected
  1081.      */
  1082.     public $connected_server_info = '';
  1083.  
  1084.     /**
  1085.      * list of all supported features of the given driver
  1086.      * @var     array 
  1087.      * @access  public
  1088.      */
  1089.     public $supported = array(
  1090.         'sequences' => false,
  1091.         'indexes' => false,
  1092.         'affected_rows' => false,
  1093.         'summary_functions' => false,
  1094.         'order_by_text' => false,
  1095.         'transactions' => false,
  1096.         'savepoints' => false,
  1097.         'current_id' => false,
  1098.         'limit_queries' => false,
  1099.         'LOBs' => false,
  1100.         'replace' => false,
  1101.         'sub_selects' => false,
  1102.         'triggers' => false,
  1103.         'auto_increment' => false,
  1104.         'primary_key' => false,
  1105.         'result_introspection' => false,
  1106.         'prepared_statements' => false,
  1107.         'identifier_quoting' => false,
  1108.         'pattern_escaping' => false,
  1109.         'new_link' => false,
  1110.     );
  1111.  
  1112.     /**
  1113.      * Array of supported options that can be passed to the MDB2 instance.
  1114.      *
  1115.      * The options can be set during object creation, using
  1116.      * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can
  1117.      * also be set after the object is created, using MDB2::setOptions() or
  1118.      * MDB2_Driver_Common::setOption().
  1119.      * The list of available option includes:
  1120.      * <ul>
  1121.      *  <li>$options['ssl'] -> boolean: determines if ssl should be used for connections</li>
  1122.      *  <li>$options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names</li>
  1123.      *  <li>$options['disable_query'] -> boolean: determines if queries should be executed</li>
  1124.      *  <li>$options['result_class'] -> string: class used for result sets</li>
  1125.      *  <li>$options['buffered_result_class'] -> string: class used for buffered result sets</li>
  1126.      *  <li>$options['result_wrap_class'] -> string: class used to wrap result sets into</li>
  1127.      *  <li>$options['result_buffering'] -> boolean should results be buffered or not?</li>
  1128.      *  <li>$options['fetch_class'] -> string: class to use when fetch mode object is used</li>
  1129.      *  <li>$options['persistent'] -> boolean: persistent connection?</li>
  1130.      *  <li>$options['debug'] -> integer: numeric debug level</li>
  1131.      *  <li>$options['debug_handler'] -> string: function/method that captures debug messages</li>
  1132.      *  <li>$options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler</li>
  1133.      *  <li>$options['default_text_field_length'] -> integer: default text field length to use</li>
  1134.      *  <li>$options['lob_buffer_length'] -> integer: LOB buffer length</li>
  1135.      *  <li>$options['log_line_break'] -> string: line-break format</li>
  1136.      *  <li>$options['idxname_format'] -> string: pattern for index name</li>
  1137.      *  <li>$options['seqname_format'] -> string: pattern for sequence name</li>
  1138.      *  <li>$options['savepoint_format'] -> string: pattern for auto generated savepoint names</li>
  1139.      *  <li>$options['statement_format'] -> string: pattern for prepared statement names</li>
  1140.      *  <li>$options['seqcol_name'] -> string: sequence column name</li>
  1141.      *  <li>$options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used</li>
  1142.      *  <li>$options['use_transactions'] -> boolean: if transaction use should be enabled</li>
  1143.      *  <li>$options['decimal_places'] -> integer: number of decimal places to handle</li>
  1144.      *  <li>$options['portability'] -> integer: portability constant</li>
  1145.      *  <li>$options['modules'] -> array: short to long module name mapping for __call()</li>
  1146.      *  <li>$options['emulate_prepared'] -> boolean: force prepared statements to be emulated</li>
  1147.      *  <li>$options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes</li>
  1148.      *  <li>$options['datatype_map_callback'] -> array: callback function/method that should be called</li>
  1149.      *  <li>$options['bindname_format'] -> string: regular expression pattern for named parameters</li>
  1150.      *  <li>$options['multi_query'] -> boolean: determines if queries returning multiple result sets should be executed</li>
  1151.      *  <li>$options['max_identifiers_length'] -> integer: max identifier length</li>
  1152.      *  <li>$options['default_fk_action_onupdate'] -> string: default FOREIGN KEY ON UPDATE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']</li>
  1153.      *  <li>$options['default_fk_action_ondelete'] -> string: default FOREIGN KEY ON DELETE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']</li>
  1154.      * </ul>
  1155.      *
  1156.      * @var     array 
  1157.      * @access  public
  1158.      * @see     MDB2::connect()
  1159.      * @see     MDB2::factory()
  1160.      * @see     MDB2::singleton()
  1161.      * @see     MDB2_Driver_Common::setOption()
  1162.      */
  1163.     public $options = array(
  1164.         'ssl' => false,
  1165.         'field_case' => CASE_LOWER,
  1166.         'disable_query' => false,
  1167.         'result_class' => 'MDB2_Result_%s',
  1168.         'buffered_result_class' => 'MDB2_BufferedResult_%s',
  1169.         'result_wrap_class' => false,
  1170.         'result_buffering' => true,
  1171.         'fetch_class' => 'stdClass',
  1172.         'persistent' => false,
  1173.         'debug' => 0,
  1174.         'debug_handler' => 'MDB2_defaultDebugOutput',
  1175.         'debug_expanded_output' => false,
  1176.         'default_text_field_length' => 4096,
  1177.         'lob_buffer_length' => 8192,
  1178.         'log_line_break' => "\n",
  1179.         'idxname_format' => '%s_idx',
  1180.         'seqname_format' => '%s_seq',
  1181.         'savepoint_format' => 'MDB2_SAVEPOINT_%s',
  1182.         'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s',
  1183.         'seqcol_name' => 'sequence',
  1184.         'quote_identifier' => false,
  1185.         'use_transactions' => true,
  1186.         'decimal_places' => 2,
  1187.         'portability' => MDB2_PORTABILITY_ALL,
  1188.         'modules' => array(
  1189.             'ex' => 'Extended',
  1190.             'dt' => 'Datatype',
  1191.             'mg' => 'Manager',
  1192.             'rv' => 'Reverse',
  1193.             'na' => 'Native',
  1194.             'fc' => 'Function',
  1195.         ),
  1196.         'emulate_prepared' => false,
  1197.         'datatype_map' => array(),
  1198.         'datatype_map_callback' => array(),
  1199.         'nativetype_map_callback' => array(),
  1200.         'lob_allow_url_include' => false,
  1201.         'bindname_format' => '(?:\d+)|(?:[a-zA-Z][a-zA-Z0-9_]*)',
  1202.         'max_identifiers_length' => 30,
  1203.         'default_fk_action_onupdate' => 'RESTRICT',
  1204.         'default_fk_action_ondelete' => 'RESTRICT',
  1205.     );
  1206.  
  1207.     /**
  1208.      * string array
  1209.      * @var     string 
  1210.      * @access  public
  1211.      */
  1212.     public $string_quoting = array(
  1213.         'start'  => "'",
  1214.         'end'    => "'",
  1215.         'escape' => false,
  1216.         'escape_pattern' => false,
  1217.     );
  1218.  
  1219.     /**
  1220.      * identifier quoting
  1221.      * @var     array 
  1222.      * @access  public
  1223.      */
  1224.     public $identifier_quoting = array(
  1225.         'start'  => '"',
  1226.         'end'    => '"',
  1227.         'escape' => '"',
  1228.     );
  1229.  
  1230.     /**
  1231.      * sql comments
  1232.      * @var     array 
  1233.      * @access  protected
  1234.      */
  1235.     public $sql_comments = array(
  1236.         array('start' => '--''end' => "\n"'escape' => false),
  1237.         array('start' => '/*''end' => '*/''escape' => false),
  1238.     );
  1239.  
  1240.     /**
  1241.      * comparision wildcards
  1242.      * @var     array 
  1243.      * @access  protected
  1244.      */
  1245.     protected $wildcards = array('%''_');
  1246.  
  1247.     /**
  1248.      * column alias keyword
  1249.      * @var     string 
  1250.      * @access  protected
  1251.      */
  1252.     public $as_keyword = ' AS ';
  1253.  
  1254.     /**
  1255.      * warnings
  1256.      * @var     array 
  1257.      * @access  protected
  1258.      */
  1259.     public $warnings = array();
  1260.  
  1261.     /**
  1262.      * string with the debugging information
  1263.      * @var     string 
  1264.      * @access  public
  1265.      */
  1266.     public $debug_output = '';
  1267.  
  1268.     /**
  1269.      * determine if there is an open transaction
  1270.      * @var     bool 
  1271.      * @access  protected
  1272.      */
  1273.     public $in_transaction = false;
  1274.  
  1275.     /**
  1276.      * the smart transaction nesting depth
  1277.      * @var     int 
  1278.      * @access  protected
  1279.      */
  1280.     public $nested_transaction_counter = null;
  1281.  
  1282.     /**
  1283.      * the first error that occured inside a nested transaction
  1284.      * @var     MDB2_Error|bool
  1285.      * @access  protected
  1286.      */
  1287.     protected $has_transaction_error = false;
  1288.  
  1289.     /**
  1290.      * result offset used in the next query
  1291.      * @var     int 
  1292.      * @access  public
  1293.      */
  1294.     public $offset = 0;
  1295.  
  1296.     /**
  1297.      * result limit used in the next query
  1298.      * @var     int 
  1299.      * @access  public
  1300.      */
  1301.     public $limit = 0;
  1302.  
  1303.     /**
  1304.      * Database backend used in PHP (mysql, odbc etc.)
  1305.      * @var     string 
  1306.      * @access  public
  1307.      */
  1308.     public $phptype;
  1309.  
  1310.     /**
  1311.      * Database used with regards to SQL syntax etc.
  1312.      * @var     string 
  1313.      * @access  public
  1314.      */
  1315.     public $dbsyntax;
  1316.  
  1317.     /**
  1318.      * the last query sent to the driver
  1319.      * @var     string 
  1320.      * @access  public
  1321.      */
  1322.     public $last_query;
  1323.  
  1324.     /**
  1325.      * the default fetchmode used
  1326.      * @var     int 
  1327.      * @access  public
  1328.      */
  1329.     public $fetchmode = MDB2_FETCHMODE_ORDERED;
  1330.  
  1331.     /**
  1332.      * array of module instances
  1333.      * @var     array 
  1334.      * @access  protected
  1335.      */
  1336.     protected $modules = array();
  1337.  
  1338.     /**
  1339.      * determines of the PHP4 destructor emulation has been enabled yet
  1340.      * @var     array 
  1341.      * @access  protected
  1342.      */
  1343.     protected $destructor_registered = true;
  1344.  
  1345.     /**
  1346.      * @var PEAR 
  1347.      */
  1348.     protected $pear;
  1349.  
  1350.     // }}}
  1351.     // {{{ constructor: function __construct()
  1352.  
  1353.     /**
  1354.      * Constructor
  1355.      */
  1356.     function __construct()
  1357.     {
  1358.         end($GLOBALS['_MDB2_databases']);
  1359.         $db_index key($GLOBALS['_MDB2_databases']+ 1;
  1360.         $GLOBALS['_MDB2_databases'][$db_index&$this;
  1361.         $this->db_index = $db_index;
  1362.         $this->pear = new PEAR;
  1363.     }
  1364.  
  1365.     // }}}
  1366.     // {{{ destructor: function __destruct()
  1367.  
  1368.     /**
  1369.      *  Destructor
  1370.      */
  1371.     function __destruct()
  1372.     {
  1373.         $this->disconnect(false);
  1374.     }
  1375.  
  1376.     // }}}
  1377.     // {{{ function free()
  1378.  
  1379.     /**
  1380.      * Free the internal references so that the instance can be destroyed
  1381.      *
  1382.      * @return  bool    true on success, false if result is invalid
  1383.      *
  1384.      * @access  public
  1385.      */
  1386.     function free()
  1387.     {
  1388.         unset($GLOBALS['_MDB2_databases'][$this->db_index]);
  1389.         unset($this->db_index);
  1390.         return MDB2_OK;
  1391.     }
  1392.  
  1393.     // }}}
  1394.     // {{{ function __toString()
  1395.  
  1396.     /**
  1397.      * String conversation
  1398.      *
  1399.      * @return  string representation of the object
  1400.      *
  1401.      * @access  public
  1402.      */
  1403.     function __toString()
  1404.     {
  1405.         $info get_class($this);
  1406.         $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')';
  1407.         if ($this->connection{
  1408.             $info.= ' [connected]';
  1409.         }
  1410.         return $info;
  1411.     }
  1412.  
  1413.     // }}}
  1414.     // {{{ function errorInfo($error = null)
  1415.  
  1416.     /**
  1417.      * This method is used to collect information about an error
  1418.      *
  1419.      * @param   mixed   error code or resource
  1420.      *
  1421.      * @return  array   with MDB2 errorcode, native error code, native message
  1422.      *
  1423.      * @access  public
  1424.      */
  1425.     function errorInfo($error = null)
  1426.     {
  1427.         return array($errornullnull);
  1428.     }
  1429.  
  1430.     // }}}
  1431.     // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
  1432.  
  1433.     /**
  1434.      * This method is used to communicate an error and invoke error
  1435.      * callbacks etc.  Basically a wrapper for PEAR::raiseError
  1436.      * without the message string.
  1437.      *
  1438.      * @param mixed  $code     integer error code, or a PEAR error object (all
  1439.      *                          other parameters are ignored if this parameter is
  1440.      *                          an object
  1441.      * @param int    $mode     error mode, see PEAR_Error docs
  1442.      * @param mixed  $options  If error mode is PEAR_ERROR_TRIGGER, this is the
  1443.      *                          error level (E_USER_NOTICE etc). If error mode is
  1444.      *                          PEAR_ERROR_CALLBACK, this is the callback function,
  1445.      *                          either as a function name, or as an array of an
  1446.      *                          object and method name. For other error modes this
  1447.      *                          parameter is ignored.
  1448.      * @param string $userinfo Extra debug information. Defaults to the last
  1449.      *                          query and native error code.
  1450.      * @param string $method   name of the method that triggered the error
  1451.      * @param string $dummy1   not used
  1452.      * @param bool   $dummy2   not used
  1453.      *
  1454.      * @return PEAR_Error instance of a PEAR Error object
  1455.      * @access public
  1456.      * @see    PEAR_Error
  1457.      */
  1458.     function &raiseError($code = null,
  1459.                          $mode = null,
  1460.                          $options = null,
  1461.                          $userinfo = null,
  1462.                          $method = null,
  1463.                          $dummy1 = null,
  1464.                          $dummy2 = false
  1465.     {
  1466.         $userinfo = "[Error message: $userinfo]\n";
  1467.         // The error is yet a MDB2 error object
  1468.         if (MDB2::isError($code)) {
  1469.             // because we use the static PEAR::raiseError, our global
  1470.             // handler should be used if it is set
  1471.             if ((null === $mode&& !empty($this->_default_error_mode)) {
  1472.                 $mode    $this->_default_error_mode;
  1473.                 $options $this->_default_error_options;
  1474.             }
  1475.             if (null === $userinfo{
  1476.                 $userinfo $code->getUserinfo();
  1477.             }
  1478.             $code $code->getCode();
  1479.         elseif ($code == MDB2_ERROR_NOT_FOUND{
  1480.             // extension not loaded: don't call $this->errorInfo() or the script
  1481.             // will die
  1482.         elseif (isset($this->connection)) {
  1483.             if (!empty($this->last_query)) {
  1484.                 $userinfo.= "[Last executed query: {$this->last_query}]\n";
  1485.             }
  1486.             $native_errno = $native_msg = null;
  1487.             list($code, $native_errno, $native_msg) = $this->errorInfo($code);
  1488.             if ((null !== $native_errno&& $native_errno !== ''{
  1489.                 $userinfo.= "[Native code: $native_errno]\n";
  1490.             }
  1491.             if ((null !== $native_msg) && $native_msg !== '') {
  1492.                 $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n";
  1493.             }
  1494.             if (null !== $method) {
  1495.                 $userinfo = $method.': '.$userinfo;
  1496.             }
  1497.         }
  1498.  
  1499.         $err = $this->pear->raiseError(null$code$mode$options$userinfo'MDB2_Error'true);
  1500.         if ($err->getMode(!== PEAR_ERROR_RETURN
  1501.             && isset($this->nested_transaction_counter&& !$this->has_transaction_error{
  1502.             $this->has_transaction_error = $err;
  1503.         }
  1504.         return $err;
  1505.     }
  1506.  
  1507.     // }}}
  1508.     // {{{ function resetWarnings()
  1509.     /**
  1510.      * reset the warning array
  1511.      *
  1512.      * @return void
  1513.      *
  1514.      * @access  public
  1515.      */
  1516.     function resetWarnings()
  1517.     {
  1518.         $this->warnings = array();
  1519.     }
  1520.  
  1521.     // }}}
  1522.     // {{{ function getWarnings()
  1523.     /**
  1524.      * Get all warnings in reverse order.
  1525.      * This means that the last warning is the first element in the array
  1526.      *
  1527.      * @return  array   with warnings
  1528.      *
  1529.      * @access  public
  1530.      * @see     resetWarnings()
  1531.      */
  1532.     function getWarnings()
  1533.     {
  1534.         return array_reverse($this->warnings);
  1535.     }
  1536.  
  1537.     // }}}
  1538.     // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass')
  1539.     /**
  1540.      * Sets which fetch mode should be used by default on queries
  1541.      * on this connection
  1542.      *
  1543.      * @param   int     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC
  1544.      *                               or MDB2_FETCHMODE_OBJECT
  1545.      * @param   string  the class name of the object to be returned
  1546.      *                               by the fetch methods when the
  1547.      *                               MDB2_FETCHMODE_OBJECT mode is selected.
  1548.      *                               If no class is specified by default a cast
  1549.      *                               to object from the assoc array row will be
  1550.      *                               done.  There is also the possibility to use
  1551.      *                               and extend the 'MDB2_row' class.
  1552.      *
  1553.      * @return  mixed   MDB2_OK or MDB2 Error Object
  1554.      *
  1555.      * @access  public
  1556.      * @see     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT
  1557.      */
  1558.     function setFetchMode($fetchmode, $object_class = 'stdClass')
  1559.     {
  1560.         switch ($fetchmode) {
  1561.         case MDB2_FETCHMODE_OBJECT:
  1562.             $this->options['fetch_class'$object_class;
  1563.         case MDB2_FETCHMODE_ORDERED:
  1564.         case MDB2_FETCHMODE_ASSOC:
  1565.             $this->fetchmode = $fetchmode;
  1566.             break;
  1567.         default:
  1568.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1569.                 'invalid fetchmode mode'__FUNCTION__);
  1570.         }
  1571.  
  1572.         return MDB2_OK;
  1573.     }
  1574.  
  1575.     // }}}
  1576.     // {{{ function setOption($option, $value)
  1577.     /**
  1578.      * set the option for the db class
  1579.      *
  1580.      * @param   string  option name
  1581.      * @param   mixed   value for the option
  1582.      *
  1583.      * @return  mixed   MDB2_OK or MDB2 Error Object
  1584.      *
  1585.      * @access  public
  1586.      */
  1587.     function setOption($option, $value)
  1588.     {
  1589.         if (array_key_exists($option, $this->options)) {
  1590.             $this->options[$option$value;
  1591.             return MDB2_OK;
  1592.         }
  1593.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1594.             "unknown option $option", __FUNCTION__);
  1595.     }
  1596.  
  1597.     // }}}
  1598.     // {{{ function getOption($option)
  1599.     /**
  1600.      * Returns the value of an option
  1601.      *
  1602.      * @param   string  option name
  1603.      *
  1604.      * @return  mixed   the option value or error object
  1605.      *
  1606.      * @access  public
  1607.      */
  1608.     function getOption($option)
  1609.     {
  1610.         if (array_key_exists($option, $this->options)) {
  1611.             return $this->options[$option];
  1612.         }
  1613.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1614.             "unknown option $option", __FUNCTION__);
  1615.     }
  1616.  
  1617.     // }}}
  1618.     // {{{ function debug($message, $scope = '', $is_manip = null)
  1619.     /**
  1620.      * set a debug message
  1621.      *
  1622.      * @param   string  message that should be appended to the debug variable
  1623.      * @param   string  usually the method name that triggered the debug call:
  1624.      *                  for example 'query', 'prepare', 'execute', 'parameters',
  1625.      *                  'beginTransaction', 'commit', 'rollback'
  1626.      * @param   array   contains context information about the debug() call
  1627.      *                  common keys are: is_manip, time, result etc.
  1628.      *
  1629.      * @return void
  1630.      *
  1631.      * @access  public
  1632.      */
  1633.     function debug($message, $scope = '', $context = array())
  1634.     {
  1635.         if ($this->options['debug'&& $this->options['debug_handler']{
  1636.             if (!$this->options['debug_expanded_output']{
  1637.                 if (!empty($context['when']) && $context['when'] !== 'pre') {
  1638.                     return null;
  1639.                 }
  1640.                 $context = empty($context['is_manip']) ? false : $context['is_manip'];
  1641.             }
  1642.             return call_user_func_array($this->options['debug_handler']array(&$this$scope$message$context));
  1643.         }
  1644.         return null;
  1645.     }
  1646.  
  1647.     // }}}
  1648.     // {{{ function getDebugOutput()
  1649.     /**
  1650.      * output debug info
  1651.      *
  1652.      * @return  string  content of the debug_output class variable
  1653.      *
  1654.      * @access  public
  1655.      */
  1656.     function getDebugOutput()
  1657.     {
  1658.         return $this->debug_output;
  1659.     }
  1660.  
  1661.     // }}}
  1662.     // {{{ function escape($text)
  1663.     /**
  1664.      * Quotes a string so it can be safely used in a query. It will quote
  1665.      * the text so it can safely be used within a query.
  1666.      *
  1667.      * @param   string  the input string to quote
  1668.      * @param   bool    escape wildcards
  1669.      *
  1670.      * @return  string  quoted string
  1671.      *
  1672.      * @access  public
  1673.      */
  1674.     function escape($text, $escape_wildcards = false)
  1675.     {
  1676.         if ($escape_wildcards) {
  1677.             $text = $this->escapePattern($text);
  1678.         }
  1679.  
  1680.         $text = str_replace($this->string_quoting['end']$this->string_quoting['escape'$this->string_quoting['end']$text);
  1681.         return $text;
  1682.     }
  1683.  
  1684.     // }}}
  1685.     // {{{ function escapePattern($text)
  1686.     /**
  1687.      * Quotes pattern (% and _) characters in a string)
  1688.      *
  1689.      * @param   string  the input string to quote
  1690.      *
  1691.      * @return  string  quoted string
  1692.      *
  1693.      * @access  public
  1694.      */
  1695.     function escapePattern($text)
  1696.     {
  1697.         if ($this->string_quoting['escape_pattern']{
  1698.             $text = str_replace($this->string_quoting['escape_pattern']$this->string_quoting['escape_pattern'$this->string_quoting['escape_pattern']$text);
  1699.             foreach ($this->wildcards as $wildcard{
  1700.                 $text = str_replace($wildcard, $this->string_quoting['escape_pattern'$wildcard$text);
  1701.             }
  1702.         }
  1703.         return $text;
  1704.     }
  1705.  
  1706.     // }}}
  1707.     // {{{ function quoteIdentifier($str, $check_option = false)
  1708.     /**
  1709.      * Quote a string so it can be safely used as a table or column name
  1710.      *
  1711.      * Delimiting style depends on which database driver is being used.
  1712.      *
  1713.      * NOTE: just because you CAN use delimited identifiers doesn't mean
  1714.      * you SHOULD use them.  In general, they end up causing way more
  1715.      * problems than they solve.
  1716.      *
  1717.      * NOTE: if you have table names containing periods, don't use this method
  1718.      * (@see bug #11906)
  1719.      *
  1720.      * Portability is broken by using the following characters inside
  1721.      * delimited identifiers:
  1722.      *   + backtick (<kbd>`</kbd>) -- due to MySQL
  1723.      *   + double quote (<kbd>"</kbd>) -- due to Oracle
  1724.      *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
  1725.      *
  1726.      * Delimited identifiers are known to generally work correctly under
  1727.      * the following drivers:
  1728.      *   + mssql
  1729.      *   + mysql
  1730.      *   + mysqli
  1731.      *   + oci8
  1732.      *   + pgsql
  1733.      *   + sqlite
  1734.      *
  1735.      * InterBase doesn't seem to be able to use delimited identifiers
  1736.      * via PHP 4.  They work fine under PHP 5.
  1737.      *
  1738.      * @param   string  identifier name to be quoted
  1739.      * @param   bool    check the 'quote_identifier' option
  1740.      *
  1741.      * @return  string  quoted identifier string
  1742.      *
  1743.      * @access  public
  1744.      */
  1745.     function quoteIdentifier($str, $check_option = false)
  1746.     {
  1747.         if ($check_option && !$this->options['quote_identifier']{
  1748.             return $str;
  1749.         }
  1750.         $str = str_replace($this->identifier_quoting['end']$this->identifier_quoting['escape'$this->identifier_quoting['end']$str);
  1751.         $parts = explode('.'$str);
  1752.         foreach (array_keys($partsas $k{
  1753.             $parts[$k] = $this->identifier_quoting['start'$parts[$k$this->identifier_quoting['end'];
  1754.         }
  1755.         return implode('.', $parts);
  1756.     }
  1757.  
  1758.     // }}}
  1759.     // {{{ function getAsKeyword()
  1760.     /**
  1761.      * Gets the string to alias column
  1762.      *
  1763.      * @return string to use when aliasing a column
  1764.      */
  1765.     function getAsKeyword()
  1766.     {
  1767.         return $this->as_keyword;
  1768.     }
  1769.  
  1770.     // }}}
  1771.     // {{{ function getConnection()
  1772.     /**
  1773.      * Returns a native connection
  1774.      *
  1775.      * @return  mixed   a valid MDB2 connection object,
  1776.      *                  or a MDB2 error object on error
  1777.      *
  1778.      * @access  public
  1779.      */
  1780.     function getConnection()
  1781.     {
  1782.         $result = $this->connect();
  1783.         if (MDB2::isError($result)) {
  1784.             return $result;
  1785.         }
  1786.         return $this->connection;
  1787.     }
  1788.  
  1789.      // }}}
  1790.     // {{{ function _fixResultArrayValues(&$row, $mode)
  1791.     /**
  1792.      * Do all necessary conversions on result arrays to fix DBMS quirks
  1793.      *
  1794.      * @param   array   the array to be fixed (passed by reference)
  1795.      * @param   array   bit-wise addition of the required portability modes
  1796.      *
  1797.      * @return  void
  1798.      *
  1799.      * @access  protected
  1800.      */
  1801.     function _fixResultArrayValues(&$row, $mode)
  1802.     {
  1803.         switch ($mode) {
  1804.         case MDB2_PORTABILITY_EMPTY_TO_NULL:
  1805.             foreach ($row as $key => $value) {
  1806.                 if ($value === '') {
  1807.                     $row[$key] = null;
  1808.                 }
  1809.             }
  1810.             break;
  1811.         case MDB2_PORTABILITY_RTRIM:
  1812.             foreach ($row as $key => $value) {
  1813.                 if (is_string($value)) {
  1814.                     $row[$key] = rtrim($value);
  1815.                 }
  1816.             }
  1817.             break;
  1818.         case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES:
  1819.             $tmp_row = array();
  1820.             foreach ($row as $key => $value) {
  1821.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1822.             }
  1823.             $row = $tmp_row;
  1824.             break;
  1825.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL):
  1826.             foreach ($row as $key => $value) {
  1827.                 if ($value === '') {
  1828.                     $row[$key] = null;
  1829.                 } elseif (is_string($value)) {
  1830.                     $row[$key] = rtrim($value);
  1831.                 }
  1832.             }
  1833.             break;
  1834.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1835.             $tmp_row = array();
  1836.             foreach ($row as $key => $value) {
  1837.                 if (is_string($value)) {
  1838.                     $value = rtrim($value);
  1839.                 }
  1840.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1841.             }
  1842.             $row = $tmp_row;
  1843.             break;
  1844.         case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1845.             $tmp_row = array();
  1846.             foreach ($row as $key => $value) {
  1847.                 if ($value === '') {
  1848.                     $value = null;
  1849.                 }
  1850.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1851.             }
  1852.             $row = $tmp_row;
  1853.             break;
  1854.         case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
  1855.             $tmp_row = array();
  1856.             foreach ($row as $key => $value) {
  1857.                 if ($value === '') {
  1858.                     $value = null;
  1859.                 } elseif (is_string($value)) {
  1860.                     $value = rtrim($value);
  1861.                 }
  1862.                 $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
  1863.             }
  1864.             $row = $tmp_row;
  1865.             break;
  1866.         }
  1867.     }
  1868.  
  1869.     // }}}
  1870.     // {{{ function loadModule($module, $property = null, $phptype_specific = null)
  1871.     /**
  1872.      * loads a module
  1873.      *
  1874.      * @param   string  name of the module that should be loaded
  1875.      *                  (only used for error messages)
  1876.      * @param   string  name of the property into which the class will be loaded
  1877.      * @param   bool    if the class to load for the module is specific to the
  1878.      *                  phptype
  1879.      *
  1880.      * @return  object  on success a reference to the given module is returned
  1881.      *                  and on failure a PEAR error
  1882.      *
  1883.      * @access  public
  1884.      */
  1885.     function loadModule($module, $property = null, $phptype_specific = null)
  1886.     {
  1887.         if (!$property) {
  1888.             $property = strtolower($module);
  1889.         }
  1890.  
  1891.         if (!isset($this->{$property})) {
  1892.             $version = $phptype_specific;
  1893.             if ($phptype_specific !== false) {
  1894.                 $version = true;
  1895.                 $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype;
  1896.                 $file_name = str_replace('_'DIRECTORY_SEPARATOR$class_name).'.php';
  1897.             }
  1898.             if ($phptype_specific === false
  1899.                 || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name))
  1900.             ) {
  1901.                 $version = false;
  1902.                 $class_name = 'MDB2_'.$module;
  1903.                 $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
  1904.             }
  1905.  
  1906.             $err = MDB2::loadClass($class_name, $this->getOption('debug'));
  1907.             if (MDB2::isError($err)) {
  1908.                 return $err;
  1909.             }
  1910.  
  1911.             // load module in a specific version
  1912.             if ($version) {
  1913.                 if (method_exists($class_name, 'getClassName')) {
  1914.                     $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index);
  1915.                     if ($class_name != $class_name_new{
  1916.                         $class_name = $class_name_new;
  1917.                         $err = MDB2::loadClass($class_name, $this->getOption('debug'));
  1918.                         if (MDB2::isError($err)) {
  1919.                             return $err;
  1920.                         }
  1921.                     }
  1922.                 }
  1923.             }
  1924.  
  1925.             if (!MDB2::classExists($class_name)) {
  1926.                 $err = $this->raiseError(MDB2_ERROR_LOADMODULEnullnull,
  1927.                     "unable to load module '$module' into property '$property'", __FUNCTION__);
  1928.                 return $err;
  1929.             }
  1930.             $this->{$property} = new $class_name($this->db_index);
  1931.             $this->modules[$module$this->{$property};
  1932.             if ($version) {
  1933.                 // this will be used in the connect method to determine if the module
  1934.                 // needs to be loaded with a different version if the server
  1935.                 // version changed in between connects
  1936.                 $this->loaded_version_modules[$property;
  1937.             }
  1938.         }
  1939.  
  1940.         return $this->{$property};
  1941.     }
  1942.  
  1943.     // }}}
  1944.     // {{{ function __call($method, $params)
  1945.     /**
  1946.      * Calls a module method using the __call magic method
  1947.      *
  1948.      * @param   string  Method name.
  1949.      * @param   array   Arguments.
  1950.      *
  1951.      * @return  mixed   Returned value.
  1952.      */
  1953.     function __call($method, $params)
  1954.     {
  1955.         $module = null;
  1956.         if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match)
  1957.             && isset($this->options['modules'][$match[1]])
  1958.         {
  1959.             $module = $this->options['modules'][$match[1]];
  1960.             $method = strtolower($match[2]).$match[3];
  1961.             if (!isset($this->modules[$module]|| !is_object($this->modules[$module])) {
  1962.                 $result = $this->loadModule($module);
  1963.                 if (MDB2::isError($result)) {
  1964.                     return $result;
  1965.                 }
  1966.             }
  1967.         } else {
  1968.             foreach ($this->modules as $key => $foo{
  1969.                 if (is_object($this->modules[$key])
  1970.                     && method_exists($this->modules[$key]$method)
  1971.                 {
  1972.                     $module = $key;
  1973.                     break;
  1974.                 }
  1975.             }
  1976.         }
  1977.         if (null !== $module) {
  1978.             return call_user_func_array(array(&$this->modules[$module]$method)$params);
  1979.         }
  1980.  
  1981.         $class = get_class($this);
  1982.         $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  1983.         $loc = 'in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'];
  1984.         if ($method == 'isError') {
  1985.             trigger_error("Deprecated: $class::isError() is deprecated, use MDB2::isError() $loc", E_USER_DEPRECATED);
  1986.             if (!array_key_exists(0, $params)) {
  1987.                 trigger_error("Missing argument 1 for $class::$method, called $loc", E_USER_ERROR);
  1988.             }
  1989.             return MDB2::isError($params[0]);
  1990.         }
  1991.         trigger_error("Call to undefined function: $class::$method() $loc.", E_USER_ERROR);
  1992.     }
  1993.  
  1994.     // }}}
  1995.     // {{{ function __callStatic($method, $params)
  1996.     /**
  1997.      * Calls a module method using the __callStatic magic method
  1998.      *
  1999.      * @param   string  Method name.
  2000.      * @param   array   Arguments.
  2001.      *
  2002.      * @return  mixed   Returned value.
  2003.      */
  2004.     public static function __callStatic($method, $params)
  2005.     {
  2006.         $class = get_called_class();
  2007.         $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  2008.         $loc = 'in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'];
  2009.         if ($method == 'isError') {
  2010.             trigger_error("Deprecated: $class::isError() is deprecated, use MDB2::isError() $loc", E_USER_DEPRECATED);
  2011.             if (!array_key_exists(0, $params)) {
  2012.                 trigger_error("Missing argument 1 for $class::$method, called $loc", E_USER_ERROR);
  2013.             }
  2014.             return MDB2::isError($params[0]);
  2015.         }
  2016.         trigger_error("Call to undefined function: $class::$method() $loc.", E_USER_ERROR);
  2017.     }
  2018.  
  2019.     // }}}
  2020.     // {{{ function beginTransaction($savepoint = null)
  2021.     /**
  2022.      * Start a transaction or set a savepoint.
  2023.      *
  2024.      * @param   string  name of a savepoint to set
  2025.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2026.      *
  2027.      * @access  public
  2028.      */
  2029.     function beginTransaction($savepoint = null)
  2030.     {
  2031.         $this->debug('Starting transaction'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  2032.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2033.             'transactions are not supported'__FUNCTION__);
  2034.     }
  2035.  
  2036.     // }}}
  2037.     // {{{ function commit($savepoint = null)
  2038.     /**
  2039.      * Commit the database changes done during a transaction that is in
  2040.      * progress or release a savepoint. This function may only be called when
  2041.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  2042.      * transaction is implicitly started after committing the pending changes.
  2043.      *
  2044.      * @param   string  name of a savepoint to release
  2045.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2046.      *
  2047.      * @access  public
  2048.      */
  2049.     function commit($savepoint = null)
  2050.     {
  2051.         $this->debug('Committing transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  2052.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2053.             'commiting transactions is not supported'__FUNCTION__);
  2054.     }
  2055.  
  2056.     // }}}
  2057.     // {{{ function rollback($savepoint = null)
  2058.     /**
  2059.      * Cancel any database changes done during a transaction or since a specific
  2060.      * savepoint that is in progress. This function may only be called when
  2061.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  2062.      * transaction is implicitly started after canceling the pending changes.
  2063.      *
  2064.      * @param   string  name of a savepoint to rollback to
  2065.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2066.      *
  2067.      * @access  public
  2068.      */
  2069.     function rollback($savepoint = null)
  2070.     {
  2071.         $this->debug('Rolling back transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  2072.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2073.             'rolling back transactions is not supported'__FUNCTION__);
  2074.     }
  2075.  
  2076.     // }}}
  2077.     // {{{ function inTransaction($ignore_nested = false)
  2078.     /**
  2079.      * If a transaction is currently open.
  2080.      *
  2081.      * @param   bool    if the nested transaction count should be ignored
  2082.      * @return  int|bool    - an integer with the nesting depth is returned if a
  2083.      *                      nested transaction is open
  2084.      *                      - true is returned for a normal open transaction
  2085.      *                      - false is returned if no transaction is open
  2086.      *
  2087.      * @access  public
  2088.      */
  2089.     function inTransaction($ignore_nested = false)
  2090.     {
  2091.         if (!$ignore_nested && isset($this->nested_transaction_counter)) {
  2092.             return $this->nested_transaction_counter;
  2093.         }
  2094.         return $this->in_transaction;
  2095.     }
  2096.  
  2097.     // }}}
  2098.     // {{{ function setTransactionIsolation($isolation)
  2099.     /**
  2100.      * Set the transacton isolation level.
  2101.      *
  2102.      * @param   string  standard isolation level
  2103.      *                  READ UNCOMMITTED (allows dirty reads)
  2104.      *                  READ COMMITTED (prevents dirty reads)
  2105.      *                  REPEATABLE READ (prevents nonrepeatable reads)
  2106.      *                  SERIALIZABLE (prevents phantom reads)
  2107.      * @param   array some transaction options:
  2108.      *                  'wait' => 'WAIT' | 'NO WAIT'
  2109.      *                  'rw'   => 'READ WRITE' | 'READ ONLY'
  2110.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2111.      *
  2112.      * @access  public
  2113.      * @since   2.1.1
  2114.      */
  2115.     function setTransactionIsolation($isolation, $options = array())
  2116.     {
  2117.         $this->debug('Setting transaction isolation level'__FUNCTION__array('is_manip' => true));
  2118.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2119.             'isolation level setting is not supported'__FUNCTION__);
  2120.     }
  2121.  
  2122.     // }}}
  2123.     // {{{ function beginNestedTransaction($savepoint = false)
  2124.     /**
  2125.      * Start a nested transaction.
  2126.      *
  2127.      * @return  mixed   MDB2_OK on success/savepoint name, a MDB2 error on failure
  2128.      *
  2129.      * @access  public
  2130.      * @since   2.1.1
  2131.      */
  2132.     function beginNestedTransaction()
  2133.     {
  2134.         if ($this->in_transaction{
  2135.             ++$this->nested_transaction_counter;
  2136.             $savepoint = sprintf($this->options['savepoint_format']$this->nested_transaction_counter);
  2137.             if ($this->supports('savepoints'&& $savepoint{
  2138.                 return $this->beginTransaction($savepoint);
  2139.             }
  2140.             return MDB2_OK;
  2141.         }
  2142.         $this->has_transaction_error = false;
  2143.         $result $this->beginTransaction();
  2144.         $this->nested_transaction_counter = 1;
  2145.         return $result;
  2146.     }
  2147.  
  2148.     // }}}
  2149.     // {{{ function completeNestedTransaction($force_rollback = false, $release = false)
  2150.     /**
  2151.      * Finish a nested transaction by rolling back if an error occured or
  2152.      * committing otherwise.
  2153.      *
  2154.      * @param   bool    if the transaction should be rolled back regardless
  2155.      *                  even if no error was set within the nested transaction
  2156.      * @return  mixed   MDB_OK on commit/counter decrementing, false on rollback
  2157.      *                  and a MDB2 error on failure
  2158.      *
  2159.      * @access  public
  2160.      * @since   2.1.1
  2161.      */
  2162.     function completeNestedTransaction($force_rollback = false)
  2163.     {
  2164.         if ($this->nested_transaction_counter > 1{
  2165.             $savepoint = sprintf($this->options['savepoint_format']$this->nested_transaction_counter);
  2166.             if ($this->supports('savepoints'&& $savepoint{
  2167.                 if ($force_rollback || $this->has_transaction_error{
  2168.                     $result = $this->rollback($savepoint);
  2169.                     if (!MDB2::isError($result)) {
  2170.                         $result = false;
  2171.                         $this->has_transaction_error = false;
  2172.                     }
  2173.                 } else {
  2174.                     $result = $this->commit($savepoint);
  2175.                 }
  2176.             } else {
  2177.                 $result = MDB2_OK;
  2178.             }
  2179.             --$this->nested_transaction_counter;
  2180.             return $result;
  2181.         }
  2182.  
  2183.         $this->nested_transaction_counter = null;
  2184.         $result = MDB2_OK;
  2185.  
  2186.         // transaction has not yet been rolled back
  2187.         if ($this->in_transaction{
  2188.             if ($force_rollback || $this->has_transaction_error{
  2189.                 $result = $this->rollback();
  2190.                 if (!MDB2::isError($result)) {
  2191.                     $result = false;
  2192.                 }
  2193.             } else {
  2194.                 $result = $this->commit();
  2195.             }
  2196.         }
  2197.         $this->has_transaction_error = false;
  2198.         return $result;
  2199.     }
  2200.  
  2201.     // }}}
  2202.     // {{{ function failNestedTransaction($error = null, $immediately = false)
  2203.     /**
  2204.      * Force setting nested transaction to failed.
  2205.      *
  2206.      * @param   mixed   value to return in getNestededTransactionError()
  2207.      * @param   bool    if the transaction should be rolled back immediately
  2208.      * @return  bool    MDB2_OK
  2209.      *
  2210.      * @access  public
  2211.      * @since   2.1.1
  2212.      */
  2213.     function failNestedTransaction($error = null, $immediately = false)
  2214.     {
  2215.         if (null !== $error) {
  2216.             $error = $this->has_transaction_error ? $this->has_transaction_error : true;
  2217.         } elseif (!$error) {
  2218.             $error = true;
  2219.         }
  2220.         $this->has_transaction_error = $error;
  2221.         if (!$immediately{
  2222.             return MDB2_OK;
  2223.         }
  2224.         return $this->rollback();
  2225.     }
  2226.  
  2227.     // }}}
  2228.     // {{{ function getNestedTransactionError()
  2229.     /**
  2230.      * The first error that occured since the transaction start.
  2231.      *
  2232.      * @return  MDB2_Error|bool     MDB2 error object if an error occured or false.
  2233.      *
  2234.      * @access  public
  2235.      * @since   2.1.1
  2236.      */
  2237.     function getNestedTransactionError()
  2238.     {
  2239.         return $this->has_transaction_error;
  2240.     }
  2241.  
  2242.     // }}}
  2243.     // {{{ connect()
  2244.     /**
  2245.      * Connect to the database
  2246.      *
  2247.      * @return true on success, MDB2 Error Object on failure
  2248.      */
  2249.     function connect()
  2250.     {
  2251.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2252.             'method not implemented'__FUNCTION__);
  2253.     }
  2254.  
  2255.     // }}}
  2256.     // {{{ databaseExists()
  2257.     /**
  2258.      * check if given database name is exists?
  2259.      *
  2260.      * @param string $name    name of the database that should be checked
  2261.      *
  2262.      * @return mixed true/false on success, a MDB2 error on failure
  2263.      * @access public
  2264.      */
  2265.     function databaseExists($name)
  2266.     {
  2267.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2268.             'method not implemented'__FUNCTION__);
  2269.     }
  2270.  
  2271.     // }}}
  2272.     // {{{ setCharset($charset, $connection = null)
  2273.     /**
  2274.      * Set the charset on the current connection
  2275.      *
  2276.      * @param string    charset
  2277.      * @param resource  connection handle
  2278.      *
  2279.      * @return true on success, MDB2 Error Object on failure
  2280.      */
  2281.     function setCharset($charset, $connection = null)
  2282.     {
  2283.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  2284.             'method not implemented'__FUNCTION__);
  2285.     }
  2286.  
  2287.     // }}}
  2288.     // {{{ function disconnect($force = true)
  2289.     /**
  2290.      * Log out and disconnect from the database.
  2291.      *
  2292.      * @param boolean $force whether the disconnect should be forced even if the
  2293.      *                       connection is opened persistently
  2294.      *
  2295.      * @return mixed true on success, false if not connected and error object on error
  2296.      *
  2297.      * @access  public
  2298.      */
  2299.     function disconnect($force = true)
  2300.     {
  2301.         $this->connection = 0;
  2302.         $this->connected_dsn = array();
  2303.         $this->connected_database_name = '';
  2304.         $this->opened_persistent = null;
  2305.         $this->connected_server_info = '';
  2306.         $this->in_transaction = null;
  2307.         $this->nested_transaction_counter = null;
  2308.         return MDB2_OK;
  2309.     }
  2310.  
  2311.     // }}}
  2312.     // {{{ function setDatabase($name)
  2313.     /**
  2314.      * Select a different database
  2315.      *
  2316.      * @param   string  name of the database that should be selected
  2317.      *
  2318.      * @return  string  name of the database previously connected to
  2319.      *
  2320.      * @access  public
  2321.      */
  2322.     function setDatabase($name)
  2323.     {
  2324.         $previous_database_name = (isset($this->database_name)) $this->database_name : '';
  2325.         $this->database_name = $name;
  2326.         if (!empty($this->connected_database_name&& ($this->connected_database_name != $this->database_name)) {
  2327.             $this->disconnect(false);
  2328.         }
  2329.         return $previous_database_name;
  2330.     }
  2331.  
  2332.     // }}}
  2333.     // {{{ function getDatabase()
  2334.     /**
  2335.      * Get the current database
  2336.      *
  2337.      * @return  string  name of the database
  2338.      *
  2339.      * @access  public
  2340.      */
  2341.     function getDatabase()
  2342.     {
  2343.         return $this->database_name;
  2344.     }
  2345.  
  2346.     // }}}
  2347.     // {{{ function setDSN($dsn)
  2348.     /**
  2349.      * set the DSN
  2350.      *
  2351.      * @param   mixed   DSN string or array
  2352.      *
  2353.      * @return  MDB2_OK
  2354.      *
  2355.      * @access  public
  2356.      */
  2357.     function setDSN($dsn)
  2358.     {
  2359.         $dsn_default = $GLOBALS['_MDB2_dsninfo_default'];
  2360.         $dsn = MDB2::parseDSN($dsn);
  2361.         if (array_key_exists('database', $dsn)) {
  2362.             $this->database_name = $dsn['database'];
  2363.             unset($dsn['database']);
  2364.         }
  2365.         $this->dsn = array_merge($dsn_default$dsn);
  2366.         return $this->disconnect(false);
  2367.     }
  2368.  
  2369.     // }}}
  2370.     // {{{ function getDSN($type = 'string', $hidepw = false)
  2371.     /**
  2372.      * return the DSN as a string
  2373.      *
  2374.      * @param   string  format to return ("array", "string")
  2375.      * @param   string  string to hide the password with
  2376.      *
  2377.      * @return  mixed   DSN in the chosen type
  2378.      *
  2379.      * @access  public
  2380.      */
  2381.     function getDSN($type = 'string', $hidepw = false)
  2382.     {
  2383.         $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn);
  2384.         $dsn['phptype'$this->phptype;
  2385.         $dsn['database'$this->database_name;
  2386.         if ($hidepw{
  2387.             $dsn['password'] = $hidepw;
  2388.         }
  2389.         switch ($type) {
  2390.         // expand to include all possible options
  2391.         case 'string':
  2392.            $dsn = $dsn['phptype'].
  2393.                ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : '').
  2394.                '://'.$dsn['username'].':'.
  2395.                 $dsn['password'].'@'.$dsn['hostspec'].
  2396.                 ($dsn['port'] ? (':'.$dsn['port']) : '').
  2397.                 '/'.$dsn['database'];
  2398.             break;
  2399.         case 'array':
  2400.         default:
  2401.             break;
  2402.         }
  2403.         return $dsn;
  2404.     }
  2405.  
  2406.     // }}}
  2407.     // {{{ _isNewLinkSet()
  2408.     /**
  2409.      * Check if the 'new_link' option is set
  2410.      *
  2411.      * @return boolean
  2412.      *
  2413.      * @access protected
  2414.      */
  2415.     function _isNewLinkSet()
  2416.     {
  2417.         return (isset($this->dsn['new_link'])
  2418.             && ($this->dsn['new_link'=== true
  2419.              || (is_string($this->dsn['new_link']&& preg_match('/^true$/i'$this->dsn['new_link']))
  2420.              || (is_numeric($this->dsn['new_link']&& 0 != (int)$this->dsn['new_link'])
  2421.             )
  2422.         );
  2423.     }
  2424.  
  2425.     // }}}
  2426.     // {{{ function &standaloneQuery($query, $types = null, $is_manip = false)
  2427.    /**
  2428.      * execute a query as database administrator
  2429.      *
  2430.      * @param   string  the SQL query
  2431.      * @param   mixed   array that contains the types of the columns in
  2432.      *                        the result set
  2433.      * @param   bool    if the query is a manipulation query
  2434.      *
  2435.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2436.      *
  2437.      * @access  public
  2438.      */
  2439.     function standaloneQuery($query, $types = null, $is_manip = false)
  2440.     {
  2441.         $offset = $this->offset;
  2442.         $limit $this->limit;
  2443.         $this->offset = $this->limit = 0;
  2444.         $query $this->_modifyQuery($query$is_manip$limit$offset);
  2445.  
  2446.         $connection $this->getConnection();
  2447.         if (MDB2::isError($connection)) {
  2448.             return $connection;
  2449.         }
  2450.  
  2451.         $result = $this->_doQuery($query$is_manip$connectionfalse);
  2452.         if (MDB2::isError($result)) {
  2453.             return $result;
  2454.         }
  2455.  
  2456.         if ($is_manip) {
  2457.             $affected_rows =  $this->_affectedRows($connection$result);
  2458.             return $affected_rows;
  2459.         }
  2460.         $result = $this->_wrapResult($result$typestruetrue$limit$offset);
  2461.         return $result;
  2462.     }
  2463.  
  2464.     // }}}
  2465.     // {{{ function _modifyQuery($query, $is_manip, $limit, $offset)
  2466.     /**
  2467.      * Changes a query string for various DBMS specific reasons
  2468.      *
  2469.      * @param   string  query to modify
  2470.      * @param   bool    if it is a DML query
  2471.      * @param   int  limit the number of rows
  2472.      * @param   int  start reading from given offset
  2473.      *
  2474.      * @return  string  modified query
  2475.      *
  2476.      * @access  protected
  2477.      */
  2478.     function _modifyQuery($query, $is_manip, $limit, $offset)
  2479.     {
  2480.         return $query;
  2481.     }
  2482.  
  2483.     // }}}
  2484.     // {{{ function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)
  2485.     /**
  2486.      * Execute a query
  2487.      * @param   string  query
  2488.      * @param   bool    if the query is a manipulation query
  2489.      * @param   resource connection handle
  2490.      * @param   string  database name
  2491.      *
  2492.      * @return  result or error object
  2493.      *
  2494.      * @access  protected
  2495.      */
  2496.     function _doQuery($query, $is_manip = false, $connection = null, $database_name = null)
  2497.     {
  2498.         $this->last_query = $query;
  2499.         $result $this->debug($query'query'array('is_manip' => $is_manip'when' => 'pre'));
  2500.         if ($result{
  2501.             if (MDB2::isError($result)) {
  2502.                 return $result;
  2503.             }
  2504.             $query = $result;
  2505.         }
  2506.         $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2507.             'method not implemented', __FUNCTION__);
  2508.         return $err;
  2509.     }
  2510.  
  2511.     // }}}
  2512.     // {{{ function _affectedRows($connection, $result = null)
  2513.     /**
  2514.      * Returns the number of rows affected
  2515.      *
  2516.      * @param   resource result handle
  2517.      * @param   resource connection handle
  2518.      *
  2519.      * @return  mixed   MDB2 Error Object or the number of rows affected
  2520.      *
  2521.      * @access  private
  2522.      */
  2523.     function _affectedRows($connection, $result = null)
  2524.     {
  2525.         return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2526.             'method not implemented', __FUNCTION__);
  2527.     }
  2528.  
  2529.     // }}}
  2530.     // {{{ function &exec($query)
  2531.     /**
  2532.      * Execute a manipulation query to the database and return the number of affected rows
  2533.      *
  2534.      * @param   string  the SQL query
  2535.      *
  2536.      * @return  mixed   number of affected rows on success, a MDB2 error on failure
  2537.      *
  2538.      * @access  public
  2539.      */
  2540.     function exec($query)
  2541.     {
  2542.         $offset = $this->offset;
  2543.         $limit $this->limit;
  2544.         $this->offset = $this->limit = 0;
  2545.         $query $this->_modifyQuery($querytrue$limit$offset);
  2546.  
  2547.         $connection $this->getConnection();
  2548.         if (MDB2::isError($connection)) {
  2549.             return $connection;
  2550.         }
  2551.  
  2552.         $result = $this->_doQuery($querytrue$connection$this->database_name);
  2553.         if (MDB2::isError($result)) {
  2554.             return $result;
  2555.         }
  2556.  
  2557.         $affectedRows = $this->_affectedRows($connection$result);
  2558.         return $affectedRows;
  2559.     }
  2560.  
  2561.     // }}}
  2562.     // {{{ function &query($query, $types = null, $result_class = true, $result_wrap_class = false)
  2563.     /**
  2564.      * Send a query to the database and return any results
  2565.      *
  2566.      * @param   string  the SQL query
  2567.      * @param   mixed   array that contains the types of the columns in
  2568.      *                        the result set
  2569.      * @param   mixed   string which specifies which result class to use
  2570.      * @param   mixed   string which specifies which class to wrap results in
  2571.      *
  2572.      * @return mixed   an MDB2_Result handle on success, a MDB2 error on failure
  2573.      *
  2574.      * @access  public
  2575.      */
  2576.     function query($query, $types = null, $result_class = true, $result_wrap_class = true)
  2577.     {
  2578.         $offset = $this->offset;
  2579.         $limit $this->limit;
  2580.         $this->offset = $this->limit = 0;
  2581.         $query $this->_modifyQuery($queryfalse$limit$offset);
  2582.  
  2583.         $connection $this->getConnection();
  2584.         if (MDB2::isError($connection)) {
  2585.             return $connection;
  2586.         }
  2587.  
  2588.         $result = $this->_doQuery($queryfalse$connection$this->database_name);
  2589.         if (MDB2::isError($result)) {
  2590.             return $result;
  2591.         }
  2592.  
  2593.         $result = $this->_wrapResult($result$types$result_class$result_wrap_class$limit$offset);
  2594.         return $result;
  2595.     }
  2596.  
  2597.     // }}}
  2598.     // {{{ function _wrapResult($result_resource, $types = array(), $result_class = true, $result_wrap_class = false, $limit = null, $offset = null)
  2599.     /**
  2600.      * wrap a result set into the correct class
  2601.      *
  2602.      * @param   resource result handle
  2603.      * @param   mixed   array that contains the types of the columns in
  2604.      *                        the result set
  2605.      * @param   mixed   string which specifies which result class to use
  2606.      * @param   mixed   string which specifies which class to wrap results in
  2607.      * @param   string  number of rows to select
  2608.      * @param   string  first row to select
  2609.      *
  2610.      * @return mixed   an MDB2_Result, a MDB2 error on failure
  2611.      *
  2612.      * @access  protected
  2613.      */
  2614.     function _wrapResult($result_resource, $types = array(), $result_class = true,
  2615.         $result_wrap_class = true, $limit = null, $offset = null)
  2616.     {
  2617.         if ($types === true) {
  2618.             if ($this->supports('result_introspection')) {
  2619.                 $this->loadModule('Reverse'nulltrue);
  2620.                 $tableInfo $this->reverse->tableInfo($result_resource);
  2621.                 if (MDB2::isError($tableInfo)) {
  2622.                     return $tableInfo;
  2623.                 }
  2624.                 $types = array();
  2625.                 $types_assoc = array();
  2626.                 foreach ($tableInfo as $field) {
  2627.                     $types[] = $field['mdb2type'];
  2628.                     $types_assoc[$field['name']] = $field['mdb2type'];
  2629.                 }
  2630.             } else {
  2631.                 $types = null;
  2632.             }
  2633.         }
  2634.  
  2635.         if ($result_class === true) {
  2636.             $result_class = $this->options['result_buffering']
  2637.                 ? $this->options['buffered_result_class'$this->options['result_class'];
  2638.         }
  2639.  
  2640.         if ($result_class) {
  2641.             $class_name = sprintf($result_class, $this->phptype);
  2642.             if (!MDB2::classExists($class_name)) {
  2643.                 $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  2644.                     'result class does not exist '.$class_name, __FUNCTION__);
  2645.                 return $err;
  2646.             }
  2647.             $result = new $class_name($this, $result_resource, $limit, $offset);
  2648.             if (!MDB2::isResultCommon($result)) {
  2649.                 $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  2650.                     'result class is not extended from MDB2_Result_Common', __FUNCTION__);
  2651.                 return $err;
  2652.             }
  2653.  
  2654.             if (!empty($types)) {
  2655.                 $err = $result->setResultTypes($types);
  2656.                 if (MDB2::isError($err)) {
  2657.                     $result->free();
  2658.                     return $err;
  2659.                 }
  2660.             }
  2661.             if (!empty($types_assoc)) {
  2662.                 $err = $result->setResultTypes($types_assoc);
  2663.                 if (MDB2::isError($err)) {
  2664.                     $result->free();
  2665.                     return $err;
  2666.                 }
  2667.             }
  2668.  
  2669.             if ($result_wrap_class === true) {
  2670.                 $result_wrap_class = $this->options['result_wrap_class'];
  2671.             }
  2672.             if ($result_wrap_class) {
  2673.                 if (!MDB2::classExists($result_wrap_class)) {
  2674.                     $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  2675.                         'result wrap class does not exist '.$result_wrap_class, __FUNCTION__);
  2676.                     return $err;
  2677.                 }
  2678.                 $result = new $result_wrap_class($result, $this->fetchmode);
  2679.             }
  2680.  
  2681.             return $result;
  2682.         }
  2683.  
  2684.         return $result_resource;
  2685.     }
  2686.  
  2687.     // }}}
  2688.     // {{{ function getServerVersion($native = false)
  2689.     /**
  2690.      * return version information about the server
  2691.      *
  2692.      * @param   bool    determines if the raw version string should be returned
  2693.      *
  2694.      * @return  mixed   array with version information or row string
  2695.      *
  2696.      * @access  public
  2697.      */
  2698.     function getServerVersion($native = false)
  2699.     {
  2700.         return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2701.             'method not implemented', __FUNCTION__);
  2702.     }
  2703.  
  2704.     // }}}
  2705.     // {{{ function setLimit($limit, $offset = null)
  2706.     /**
  2707.      * set the range of the next query
  2708.      *
  2709.      * @param   string  number of rows to select
  2710.      * @param   string  first row to select
  2711.      *
  2712.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2713.      *
  2714.      * @access  public
  2715.      */
  2716.     function setLimit($limit, $offset = null)
  2717.     {
  2718.         if (!$this->supports('limit_queries')) {
  2719.             return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2720.                 'limit is not supported by this driver', __FUNCTION__);
  2721.         }
  2722.         $limit = (int)$limit;
  2723.         if ($limit < 0) {
  2724.             return MDB2_Driver_Common::raiseError(MDB2_ERROR_SYNTAX, null, null,
  2725.                 'it was not specified a valid selected range row limit', __FUNCTION__);
  2726.         }
  2727.         $this->limit = $limit;
  2728.         if (null !== $offset{
  2729.             $offset = (int)$offset;
  2730.             if ($offset < 0) {
  2731.                 return MDB2_Driver_Common::raiseError(MDB2_ERROR_SYNTAX, null, null,
  2732.                     'it was not specified a valid first selected range row', __FUNCTION__);
  2733.             }
  2734.             $this->offset = $offset;
  2735.         }
  2736.         return MDB2_OK;
  2737.     }
  2738.  
  2739.     // }}}
  2740.     // {{{ function subSelect($query, $type = false)
  2741.     /**
  2742.      * simple subselect emulation: leaves the query untouched for all RDBMS
  2743.      * that support subselects
  2744.      *
  2745.      * @param   string  the SQL query for the subselect that may only
  2746.      *                      return a column
  2747.      * @param   string  determines type of the field
  2748.      *
  2749.      * @return  string  the query
  2750.      *
  2751.      * @access  public
  2752.      */
  2753.     function subSelect($query, $type = false)
  2754.     {
  2755.         if ($this->supports('sub_selects'=== true{
  2756.             return $query;
  2757.         }
  2758.  
  2759.         if (!$this->supports('sub_selects')) {
  2760.             return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2761.                 'method not implemented', __FUNCTION__);
  2762.         }
  2763.  
  2764.         $col = $this->queryCol($query$type);
  2765.         if (MDB2::isError($col)) {
  2766.             return $col;
  2767.         }
  2768.         if (!is_array($col) || count($col) == 0) {
  2769.             return 'NULL';
  2770.         }
  2771.         if ($type) {
  2772.             $this->loadModule('Datatype'nulltrue);
  2773.             return $this->datatype->implodeArray($col$type);
  2774.         }
  2775.         return implode(', ', $col);
  2776.     }
  2777.  
  2778.     // }}}
  2779.     // {{{ function replace($table, $fields)
  2780.     /**
  2781.      * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
  2782.      * query, except that if there is already a row in the table with the same
  2783.      * key field values, the old row is deleted before the new row is inserted.
  2784.      *
  2785.      * The REPLACE type of query does not make part of the SQL standards. Since
  2786.      * practically only MySQL and SQLite implement it natively, this type of
  2787.      * query isemulated through this method for other DBMS using standard types
  2788.      * of queries inside a transaction to assure the atomicity of the operation.
  2789.      *
  2790.      * @param   string  name of the table on which the REPLACE query will
  2791.      *       be executed.
  2792.      * @param   array   associative array   that describes the fields and the
  2793.      *       values that will be inserted or updated in the specified table. The
  2794.      *       indexes of the array are the names of all the fields of the table.
  2795.      *       The values of the array are also associative arrays that describe
  2796.      *       the values and other properties of the table fields.
  2797.      *
  2798.      *       Here follows a list of field properties that need to be specified:
  2799.      *
  2800.      *       value
  2801.      *           Value to be assigned to the specified field. This value may be
  2802.      *           of specified in database independent type format as this
  2803.      *           function can perform the necessary datatype conversions.
  2804.      *
  2805.      *           Default: this property is required unless the Null property is
  2806.      *           set to 1.
  2807.      *
  2808.      *       type
  2809.      *           Name of the type of the field. Currently, all types MDB2
  2810.      *           are supported except for clob and blob.
  2811.      *
  2812.      *           Default: no type conversion
  2813.      *
  2814.      *       null
  2815.      *           bool    property that indicates that the value for this field
  2816.      *           should be set to null.
  2817.      *
  2818.      *           The default value for fields missing in INSERT queries may be
  2819.      *           specified the definition of a table. Often, the default value
  2820.      *           is already null, but since the REPLACE may be emulated using
  2821.      *           an UPDATE query, make sure that all fields of the table are
  2822.      *           listed in this function argument array.
  2823.      *
  2824.      *           Default: 0
  2825.      *
  2826.      *       key
  2827.      *           bool    property that indicates that this field should be
  2828.      *           handled as a primary key or at least as part of the compound
  2829.      *           unique index of the table that will determine the row that will
  2830.      *           updated if it exists or inserted a new row otherwise.
  2831.      *
  2832.      *           This function will fail if no key field is specified or if the
  2833.      *           value of a key field is set to null because fields that are
  2834.      *           part of unique index they may not be null.
  2835.      *
  2836.      *           Default: 0
  2837.      *
  2838.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  2839.      *
  2840.      * @access  public
  2841.      */
  2842.     function replace($table, $fields)
  2843.     {
  2844.         if (!$this->supports('replace')) {
  2845.             return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  2846.                 'replace query is not supported', __FUNCTION__);
  2847.         }
  2848.         $count = count($fields);
  2849.         $condition = $values = array();
  2850.         for ($colnum = 0, reset($fields)$colnum < $count; next($fields), $colnum++) {
  2851.             $name = key($fields);
  2852.             if (isset($fields[$name]['null']) && $fields[$name]['null']) {
  2853.                 $value = 'NULL';
  2854.             } else {
  2855.                 $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
  2856.                 $value = $this->quote($fields[$name]['value']$type);
  2857.             }
  2858.             $values[$name] = $value;
  2859.             if (isset($fields[$name]['key']) && $fields[$name]['key']) {
  2860.                 if ($value === 'NULL') {
  2861.                     return MDB2_Driver_Common::raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
  2862.                         'key value '.$name.' may not be NULL', __FUNCTION__);
  2863.                 }
  2864.                 $condition[] = $this->quoteIdentifier($nametrue'=' $value;
  2865.             }
  2866.         }
  2867.         if (empty($condition)) {
  2868.             return MDB2_Driver_Common::raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
  2869.                 'not specified which fields are keys', __FUNCTION__);
  2870.         }
  2871.  
  2872.         $result = null;
  2873.         $in_transaction = $this->in_transaction;
  2874.         if (!$in_transaction && MDB2::isError($result $this->beginTransaction())) {
  2875.             return $result;
  2876.         }
  2877.  
  2878.         $connection = $this->getConnection();
  2879.         if (MDB2::isError($connection)) {
  2880.             return $connection;
  2881.         }
  2882.  
  2883.         $condition = ' WHERE '.implode(' AND ', $condition);
  2884.         $query = 'DELETE FROM ' . $this->quoteIdentifier($tabletrue$condition;
  2885.         $result $this->_doQuery($querytrue$connection);
  2886.         if (!MDB2::isError($result)) {
  2887.             $affected_rows = $this->_affectedRows($connection$result);
  2888.             $insert '';
  2889.             foreach ($values as $key => $value{
  2890.                 $insert .= ($insert?', ':'') . $this->quoteIdentifier($keytrue);
  2891.             }
  2892.             $values = implode(', ', $values);
  2893.             $query = 'INSERT INTO '$this->quoteIdentifier($tabletrue"($insert) VALUES ($values)";
  2894.             $result = $this->_doQuery($querytrue$connection);
  2895.             if (!MDB2::isError($result)) {
  2896.                 $affected_rows += $this->_affectedRows($connection$result);;
  2897.             }
  2898.         }
  2899.  
  2900.         if (!$in_transaction) {
  2901.             if (MDB2::isError($result)) {
  2902.                 $this->rollback();
  2903.             } else {
  2904.                 $result = $this->commit();
  2905.             }
  2906.         }
  2907.  
  2908.         if (MDB2::isError($result)) {
  2909.             return $result;
  2910.         }
  2911.  
  2912.         return $affected_rows;
  2913.     }
  2914.  
  2915.     // }}}
  2916.     // {{{ function &prepare($query, $types = null, $result_types = null, $lobs = array())
  2917.     /**
  2918.      * Prepares a query for multiple execution with execute().
  2919.      * With some database backends, this is emulated.
  2920.      * prepare() requires a generic query as string like
  2921.      * 'INSERT INTO numbers VALUES(?,?)' or
  2922.      * 'INSERT INTO numbers VALUES(:foo,:bar)'.
  2923.      * The ? and :name and are placeholders which can be set using
  2924.      * bindParam() and the query can be sent off using the execute() method.
  2925.      * The allowed format for :name can be set with the 'bindname_format' option.
  2926.      *
  2927.      * @param   string  the query to prepare
  2928.      * @param   mixed   array that contains the types of the placeholders
  2929.      * @param   mixed   array that contains the types of the columns in
  2930.      *                        the result set or MDB2_PREPARE_RESULT, if set to
  2931.      *                        MDB2_PREPARE_MANIP the query is handled as a manipulation query
  2932.      * @param   mixed   key (field) value (parameter) pair for all lob placeholders
  2933.      *
  2934.      * @return  mixed   resource handle for the prepared query on success,
  2935.      *                  a MDB2 error on failure
  2936.      *
  2937.      * @access  public
  2938.      * @see     bindParam, execute
  2939.      */
  2940.     function prepare($query, $types = null, $result_types = null, $lobs = array())
  2941.     {
  2942.         $is_manip = ($result_types === MDB2_PREPARE_MANIP);
  2943.         $offset = $this->offset;
  2944.         $limit $this->limit;
  2945.         $this->offset = $this->limit = 0;
  2946.         $result $this->debug($query__FUNCTION__array('is_manip' => $is_manip'when' => 'pre'));
  2947.         if ($result{
  2948.             if (MDB2::isError($result)) {
  2949.                 return $result;
  2950.             }
  2951.             $query = $result;
  2952.         }
  2953.         $placeholder_type_guess = $placeholder_type = null;
  2954.         $question  = '?';
  2955.         $colon     = ':';
  2956.         $positions = array();
  2957.         $position  = 0;
  2958.         while ($position < strlen($query)) {
  2959.             $q_position = strpos($query, $question, $position);
  2960.             $c_position = strpos($query, $colon, $position);
  2961.             if ($q_position && $c_position) {
  2962.                 $p_position = min($q_position, $c_position);
  2963.             } elseif ($q_position) {
  2964.                 $p_position = $q_position;
  2965.             } elseif ($c_position) {
  2966.                 $p_position = $c_position;
  2967.             } else {
  2968.                 break;
  2969.             }
  2970.             if (null === $placeholder_type) {
  2971.                 $placeholder_type_guess = $query[$p_position];
  2972.             }
  2973.  
  2974.             $new_pos = $this->_skipDelimitedStrings($query$position$p_position);
  2975.             if (MDB2::isError($new_pos)) {
  2976.                 return $new_pos;
  2977.             }
  2978.             if ($new_pos != $position) {
  2979.                 $position = $new_pos;
  2980.                 continue; //evaluate again starting from the new position
  2981.             }
  2982.  
  2983.             if ($query[$position] == $placeholder_type_guess) {
  2984.                 if (null === $placeholder_type) {
  2985.                     $placeholder_type = $query[$p_position];
  2986.                     $question = $colon = $placeholder_type;
  2987.                     if (!empty($types) && is_array($types)) {
  2988.                         if ($placeholder_type == ':') {
  2989.                             if (is_int(key($types))) {
  2990.                                 $types_tmp = $types;
  2991.                                 $types = array();
  2992.                                 $count = -1;
  2993.                             }
  2994.                         } else {
  2995.                             $types = array_values($types);
  2996.                         }
  2997.                     }
  2998.                 }
  2999.                 if ($placeholder_type == ':') {
  3000.                     $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s';
  3001.                     $parameter = preg_replace($regexp'\\1'$query);
  3002.                     if ($parameter === ''{
  3003.                         $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_SYNTAX, null, null,
  3004.                             'named parameter name must match "bindname_format" option', __FUNCTION__);
  3005.                         return $err;
  3006.                     }
  3007.                     $positions[$p_position] = $parameter;
  3008.                     $query = substr_replace($query, '?', $position, strlen($parameter)+1);
  3009.                     // use parameter name in type array
  3010.                     if (isset($count) && isset($types_tmp[++$count])) {
  3011.                         $types[$parameter] = $types_tmp[$count];
  3012.                     }
  3013.                 } else {
  3014.                     $positions[$p_position] = count($positions);
  3015.                 }
  3016.                 $position = $p_position + 1;
  3017.             } else {
  3018.                 $position = $p_position;
  3019.             }
  3020.         }
  3021.         $class_name = 'MDB2_Statement_'.$this->phptype;
  3022.         $statement = null;
  3023.         $obj = new $class_name($this$statement$positions$query$types$result_types$is_manip$limit$offset);
  3024.         $this->debug($query__FUNCTION__array('is_manip' => $is_manip'when' => 'post''result' => $obj));
  3025.         return $obj;
  3026.     }
  3027.  
  3028.     // }}}
  3029.     // {{{ function _skipDelimitedStrings($query, $position, $p_position)
  3030.     /**
  3031.      * Utility method, used by prepare() to avoid replacing placeholders within delimited strings.
  3032.      * Check if the placeholder is contained within a delimited string.
  3033.      * If so, skip it and advance the position, otherwise return the current position,
  3034.      * which is valid
  3035.      *
  3036.      * @param string $query
  3037.      * @param integer $position current string cursor position
  3038.      * @param integer $p_position placeholder position
  3039.      *
  3040.      * @return mixed integer $new_position on success
  3041.      *               MDB2_Error on failure
  3042.      *
  3043.      * @access  protected
  3044.      */
  3045.     function _skipDelimitedStrings($query, $position, $p_position)
  3046.     {
  3047.         $ignores = array();
  3048.         $ignores[] = $this->string_quoting;
  3049.         $ignores[$this->identifier_quoting;
  3050.         $ignores = array_merge($ignores$this->sql_comments);
  3051.  
  3052.         foreach ($ignores as $ignore{
  3053.             if (!empty($ignore['start'])) {
  3054.                 if (is_int($start_quote = strpos($query, $ignore['start'], $position)) && $start_quote < $p_position) {
  3055.                     $end_quote = $start_quote;
  3056.                     do {
  3057.                         if (!is_int($end_quote = strpos($query, $ignore['end'], $end_quote + 1))) {
  3058.                             if ($ignore['end'] === "\n") {
  3059.                                 $end_quote = strlen($query) - 1;
  3060.                             } else {
  3061.                                 $err = MDB2_Driver_Common::raiseError(MDB2_ERROR_SYNTAX, null, null,
  3062.                                     'query with an unterminated text string specified', __FUNCTION__);
  3063.                                 return $err;
  3064.                             }
  3065.                         }
  3066.                     } while ($ignore['escape']
  3067.                         && $end_quote-1 != $start_quote
  3068.                         && $query[($end_quote - 1)] == $ignore['escape']
  3069.                         && (   $ignore['escape_pattern'] !== $ignore['escape']
  3070.                             || $query[($end_quote - 2)] != $ignore['escape'])
  3071.                     );
  3072.  
  3073.                     $position = $end_quote + 1;
  3074.                     return $position;
  3075.                 }
  3076.             }
  3077.         }
  3078.         return $position;
  3079.     }
  3080.  
  3081.     // }}}
  3082.     // {{{ function quote($value, $type = null, $quote = true)
  3083.     /**
  3084.      * Convert a text value into a DBMS specific format that is suitable to
  3085.      * compose query statements.
  3086.      *
  3087.      * @param   string  text string value that is intended to be converted.
  3088.      * @param   string  type to which the value should be converted to
  3089.      * @param   bool    quote
  3090.      * @param   bool    escape wildcards
  3091.      *
  3092.      * @return  string  text string that represents the given argument value in
  3093.      *       a DBMS specific format.
  3094.      *
  3095.      * @access  public
  3096.      */
  3097.     function quote($value, $type = null, $quote = true, $escape_wildcards = false)
  3098.     {
  3099.         $result = $this->loadModule('Datatype'nulltrue);
  3100.         if (MDB2::isError($result)) {
  3101.             return $result;
  3102.         }
  3103.  
  3104.         return $this->datatype->quote($value$type$quote$escape_wildcards);
  3105.     }
  3106.  
  3107.     // }}}
  3108.     // {{{ function getDeclaration($type, $name, $field)
  3109.     /**
  3110.      * Obtain DBMS specific SQL code portion needed to declare
  3111.      * of the given type
  3112.      *
  3113.      * @param   string  type to which the value should be converted to
  3114.      * @param   string  name the field to be declared.
  3115.      * @param   string  definition of the field
  3116.      *
  3117.      * @return  string  DBMS specific SQL code portion that should be used to
  3118.      *                 declare the specified field.
  3119.      *
  3120.      * @access  public
  3121.      */
  3122.     function getDeclaration($type, $name, $field)
  3123.     {
  3124.         $result = $this->loadModule('Datatype'nulltrue);
  3125.         if (MDB2::isError($result)) {
  3126.             return $result;
  3127.         }
  3128.         return $this->datatype->getDeclaration($type$name$field);
  3129.     }
  3130.  
  3131.     // }}}
  3132.     // {{{ function compareDefinition($current, $previous)
  3133.     /**
  3134.      * Obtain an array of changes that may need to applied
  3135.      *
  3136.      * @param   array   new definition
  3137.      * @param   array   old definition
  3138.      *
  3139.      * @return  array   containing all changes that will need to be applied
  3140.      *
  3141.      * @access  public
  3142.      */
  3143.     function compareDefinition($current, $previous)
  3144.     {
  3145.         $result = $this->loadModule('Datatype'nulltrue);
  3146.         if (MDB2::isError($result)) {
  3147.             return $result;
  3148.         }
  3149.         return $this->datatype->compareDefinition($current$previous);
  3150.     }
  3151.  
  3152.     // }}}
  3153.     // {{{ function supports($feature)
  3154.     /**
  3155.      * Tell whether a DB implementation or its backend extension
  3156.      * supports a given feature.
  3157.      *
  3158.      * @param   string  name of the feature (see the MDB2 class doc)
  3159.      *
  3160.      * @return  bool|string if this DB implementation supports a given feature
  3161.      *                      false means no, true means native,
  3162.      *                      'emulated' means emulated
  3163.      *
  3164.      * @access  public
  3165.      */
  3166.     function supports($feature)
  3167.     {
  3168.         if (array_key_exists($feature, $this->supported)) {
  3169.             return $this->supported[$feature];
  3170.         }
  3171.         return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3172.             "unknown support feature $feature", __FUNCTION__);
  3173.     }
  3174.  
  3175.     // }}}
  3176.     // {{{ function getSequenceName($sqn)
  3177.     /**
  3178.      * adds sequence name formatting to a sequence name
  3179.      *
  3180.      * @param   string  name of the sequence
  3181.      *
  3182.      * @return  string  formatted sequence name
  3183.      *
  3184.      * @access  public
  3185.      */
  3186.     function getSequenceName($sqn)
  3187.     {
  3188.         return sprintf($this->options['seqname_format'],
  3189.             preg_replace('/[^a-z0-9_\-\$.]/i''_'$sqn));
  3190.     }
  3191.  
  3192.     // }}}
  3193.     // {{{ function getIndexName($idx)
  3194.     /**
  3195.      * adds index name formatting to a index name
  3196.      *
  3197.      * @param   string  name of the index
  3198.      *
  3199.      * @return  string  formatted index name
  3200.      *
  3201.      * @access  public
  3202.      */
  3203.     function getIndexName($idx)
  3204.     {
  3205.         return sprintf($this->options['idxname_format'],
  3206.             preg_replace('/[^a-z0-9_\-\$.]/i''_'$idx));
  3207.     }
  3208.  
  3209.     // }}}
  3210.     // {{{ function nextID($seq_name, $ondemand = true)
  3211.     /**
  3212.      * Returns the next free id of a sequence
  3213.      *
  3214.      * @param   string  name of the sequence
  3215.      * @param   bool    when true missing sequences are automatic created
  3216.      *
  3217.      * @return  mixed   MDB2 Error Object or id
  3218.      *
  3219.      * @access  public
  3220.      */
  3221.     function nextID($seq_name, $ondemand = true)
  3222.     {
  3223.         return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3224.             'method not implemented', __FUNCTION__);
  3225.     }
  3226.  
  3227.     // }}}
  3228.     // {{{ function lastInsertID($table = null, $field = null)
  3229.     /**
  3230.      * Returns the autoincrement ID if supported or $id or fetches the current
  3231.      * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
  3232.      *
  3233.      * @param   string  name of the table into which a new row was inserted
  3234.      * @param   string  name of the field into which a new row was inserted
  3235.      *
  3236.      * @return  mixed   MDB2 Error Object or id
  3237.      *
  3238.      * @access  public
  3239.      */
  3240.     function lastInsertID($table = null, $field = null)
  3241.     {
  3242.         return MDB2_Driver_Common::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3243.             'method not implemented', __FUNCTION__);
  3244.     }
  3245.  
  3246.     // }}}
  3247.     // {{{ function currID($seq_name)
  3248.     /**
  3249.      * Returns the current id of a sequence
  3250.      *
  3251.      * @param   string  name of the sequence
  3252.      *
  3253.      * @return  mixed   MDB2 Error Object or id
  3254.      *
  3255.      * @access  public
  3256.      */
  3257.     function currID($seq_name)
  3258.     {
  3259.         $this->warnings['database does not support getting current
  3260.             sequence value, the sequence value was incremented';
  3261.         return $this->nextID($seq_name);
  3262.     }
  3263.  
  3264.     // }}}
  3265.     // {{{ function queryOne($query, $type = null, $colnum = 0)
  3266.     /**
  3267.      * Execute the specified query, fetch the value from the first column of
  3268.      * the first row of the result set and then frees
  3269.      * the result set.
  3270.      *
  3271.      * @param string $query  the SELECT query statement to be executed.
  3272.      * @param string $type   optional argument that specifies the expected
  3273.      *                       datatype of the result set field, so that an eventual
  3274.      *                       conversion may be performed. The default datatype is
  3275.      *                       text, meaning that no conversion is performed
  3276.      * @param mixed  $colnum the column number (or name) to fetch
  3277.      *
  3278.      * @return  mixed   MDB2_OK or field value on success, a MDB2 error on failure
  3279.      *
  3280.      * @access  public
  3281.      */
  3282.     function queryOne($query, $type = null, $colnum = 0)
  3283.     {
  3284.         $result = $this->query($query$type);
  3285.         if (!MDB2::isResultCommon($result)) {
  3286.             return $result;
  3287.         }
  3288.  
  3289.         $one = $result->fetchOne($colnum);
  3290.         $result->free();
  3291.         return $one;
  3292.     }
  3293.  
  3294.     // }}}
  3295.     // {{{ function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
  3296.     /**
  3297.      * Execute the specified query, fetch the values from the first
  3298.      * row of the result set into an array and then frees
  3299.      * the result set.
  3300.      *
  3301.      * @param   string  the SELECT query statement to be executed.
  3302.      * @param   array   optional array argument that specifies a list of
  3303.      *       expected datatypes of the result set columns, so that the eventual
  3304.      *       conversions may be performed. The default list of datatypes is
  3305.      *       empty, meaning that no conversion is performed.
  3306.      * @param   int     how the array data should be indexed
  3307.      *
  3308.      * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
  3309.      *
  3310.      * @access  public
  3311.      */
  3312.     function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
  3313.     {
  3314.         $result = $this->query($query$types);
  3315.         if (!MDB2::isResultCommon($result)) {
  3316.             return $result;
  3317.         }
  3318.  
  3319.         $row = $result->fetchRow($fetchmode);
  3320.         $result->free();
  3321.         return $row;
  3322.     }
  3323.  
  3324.     // }}}
  3325.     // {{{ function queryCol($query, $type = null, $colnum = 0)
  3326.     /**
  3327.      * Execute the specified query, fetch the value from the first column of
  3328.      * each row of the result set into an array and then frees the result set.
  3329.      *
  3330.      * @param string $query  the SELECT query statement to be executed.
  3331.      * @param string $type   optional argument that specifies the expected
  3332.      *                       datatype of the result set field, so that an eventual
  3333.      *                       conversion may be performed. The default datatype is text,
  3334.      *                       meaning that no conversion is performed
  3335.      * @param mixed  $colnum the column number (or name) to fetch
  3336.      *
  3337.      * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
  3338.      * @access  public
  3339.      */
  3340.     function queryCol($query, $type = null, $colnum = 0)
  3341.     {
  3342.         $result = $this->query($query$type);
  3343.         if (!MDB2::isResultCommon($result)) {
  3344.             return $result;
  3345.         }
  3346.  
  3347.         $col = $result->fetchCol($colnum);
  3348.         $result->free();
  3349.         return $col;
  3350.     }
  3351.  
  3352.     // }}}
  3353.     // {{{ function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)
  3354.     /**
  3355.      * Execute the specified query, fetch all the rows of the result set into
  3356.      * a two dimensional array and then frees the result set.
  3357.      *
  3358.      * @param   string  the SELECT query statement to be executed.
  3359.      * @param   array   optional array argument that specifies a list of
  3360.      *       expected datatypes of the result set columns, so that the eventual
  3361.      *       conversions may be performed. The default list of datatypes is
  3362.      *       empty, meaning that no conversion is performed.
  3363.      * @param   int     how the array data should be indexed
  3364.      * @param   bool    if set to true, the $all will have the first
  3365.      *       column as its first dimension
  3366.      * @param   bool    used only when the query returns exactly
  3367.      *       two columns. If true, the values of the returned array will be
  3368.      *       one-element arrays instead of scalars.
  3369.      * @param   bool    if true, the values of the returned array is
  3370.      *       wrapped in another array.  If the same key value (in the first
  3371.      *       column) repeats itself, the values will be appended to this array
  3372.      *       instead of overwriting the existing values.
  3373.      *
  3374.      * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
  3375.      *
  3376.      * @access  public
  3377.      */
  3378.     function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT,
  3379.         $rekey = false, $force_array = false, $group = false)
  3380.     {
  3381.         $result = $this->query($query$types);
  3382.         if (!MDB2::isResultCommon($result)) {
  3383.             return $result;
  3384.         }
  3385.  
  3386.         $all = $result->fetchAll($fetchmode$rekey$force_array$group);
  3387.         $result->free();
  3388.         return $all;
  3389.     }
  3390.  
  3391.     // }}}
  3392.     // {{{ function delExpect($error_code)
  3393.     /**
  3394.      * This method deletes all occurences of the specified element from
  3395.      * the expected error codes stack.
  3396.      *
  3397.      * @param  mixed $error_code error code that should be deleted
  3398.      * @return mixed list of error codes that were deleted or error
  3399.      *
  3400.      * @uses PEAR::delExpect()
  3401.      */
  3402.     public function delExpect($error_code)
  3403.     {
  3404.         return $this->pear->delExpect($error_code);
  3405.     }
  3406.  
  3407.     // }}}
  3408.     // {{{ function expectError($code)
  3409.     /**
  3410.      * This method is used to tell which errors you expect to get.
  3411.      * Expected errors are always returned with error mode
  3412.      * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
  3413.      * and this method pushes a new element onto it.  The list of
  3414.      * expected errors are in effect until they are popped off the
  3415.      * stack with the popExpect() method.
  3416.      *
  3417.      * Note that this method can not be called statically
  3418.      *
  3419.      * @param mixed $code a single error code or an array of error codes to expect
  3420.      *
  3421.      * @return int     the new depth of the "expected errors" stack
  3422.      *
  3423.      * @uses PEAR::expectError()
  3424.      */
  3425.     public function expectError($code = '*')
  3426.     {
  3427.         return $this->pear->expectError($code);
  3428.     }
  3429.  
  3430.     // }}}
  3431.     // {{{ function getStaticProperty($class, $var)
  3432.     /**
  3433.      * If you have a class that's mostly/entirely static, and you need static
  3434.      * properties, you can use this method to simulate them. Eg. in your method(s)
  3435.      * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
  3436.      * You MUST use a reference, or they will not persist!
  3437.      *
  3438.      * @param  string $class  The calling classname, to prevent clashes
  3439.      * @param  string $var    The variable to retrieve.
  3440.      * @return mixed   A reference to the variable. If not set it will be
  3441.      *                 auto initialised to NULL.
  3442.      *
  3443.      * @uses PEAR::getStaticProperty()
  3444.      */
  3445.     public function &getStaticProperty($class, $var)
  3446.     {
  3447.         $tmp =& $this->pear->getStaticProperty($class$var);
  3448.         return $tmp;
  3449.     }
  3450.  
  3451.     // }}}
  3452.     // {{{ function popErrorHandling()
  3453.     /**
  3454.      * Pop the last error handler used
  3455.      *
  3456.      * @return bool Always true
  3457.      *
  3458.      * @see PEAR::pushErrorHandling
  3459.      * @uses PEAR::popErrorHandling()
  3460.      */
  3461.     public function popErrorHandling()
  3462.     {
  3463.         return $this->pear->popErrorHandling();
  3464.     }
  3465.  
  3466.     // }}}
  3467.     // {{{ function popExpect()
  3468.     /**
  3469.      * This method pops one element off the expected error codes
  3470.      * stack.
  3471.      *
  3472.      * @return array   the list of error codes that were popped
  3473.      *
  3474.      * @uses PEAR::popExpect()
  3475.      */
  3476.     public function popExpect()
  3477.     {
  3478.         return $this->pear->popExpect();
  3479.     }
  3480.  
  3481.     // }}}
  3482.     // {{{ function pushErrorHandling($mode, $options = null)
  3483.     /**
  3484.      * Push a new error handler on top of the error handler options stack. With this
  3485.      * you can easily override the actual error handler for some code and restore
  3486.      * it later with popErrorHandling.
  3487.      *
  3488.      * @param mixed $mode (same as setErrorHandling)
  3489.      * @param mixed $options (same as setErrorHandling)
  3490.      *
  3491.      * @return bool Always true
  3492.      *
  3493.      * @see PEAR::setErrorHandling
  3494.      * @uses PEAR::pushErrorHandling()
  3495.      */
  3496.     public function pushErrorHandling($mode, $options = null)
  3497.     {
  3498.         return $this->pear->pushErrorHandling($mode$options);
  3499.     }
  3500.  
  3501.     // }}}
  3502.     // {{{ function registerShutdownFunc($func, $args = array())
  3503.     /**
  3504.      * Use this function to register a shutdown method for static
  3505.      * classes.
  3506.      *
  3507.      * @param  mixed $func  The function name (or array of class/method) to call
  3508.      * @param  mixed $args  The arguments to pass to the function
  3509.      * @return void
  3510.      *
  3511.      * @uses PEAR::registerShutdownFunc()
  3512.      */
  3513.     public function registerShutdownFunc($func, $args = array())
  3514.     {
  3515.         return $this->pear->registerShutdownFunc($func$args);
  3516.     }
  3517.  
  3518.     // }}}
  3519.     // {{{ function setErrorHandling($mode = null, $options = null)
  3520.     /**
  3521.      * Sets how errors generated by this object should be handled.
  3522.      * Can be invoked both in objects and statically.  If called
  3523.      * statically, setErrorHandling sets the default behaviour for all
  3524.      * PEAR objects.  If called in an object, setErrorHandling sets
  3525.      * the default behaviour for that object.
  3526.      *
  3527.      * @param int $mode
  3528.      *        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  3529.      *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  3530.      *        PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
  3531.      *
  3532.      * @param mixed $options
  3533.      *        When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
  3534.      *        of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  3535.      *
  3536.      *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  3537.      *        to be the callback function or method.  A callback
  3538.      *        function is a string with the name of the function, a
  3539.      *        callback method is an array of two elements: the element
  3540.      *        at index 0 is the object, and the element at index 1 is
  3541.      *        the name of the method to call in the object.
  3542.      *
  3543.      *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
  3544.      *        a printf format string used when printing the error
  3545.      *        message.
  3546.      *
  3547.      * @access public
  3548.      * @return void
  3549.      * @see PEAR_ERROR_RETURN
  3550.      * @see PEAR_ERROR_PRINT
  3551.      * @see PEAR_ERROR_TRIGGER
  3552.      * @see PEAR_ERROR_DIE
  3553.      * @see PEAR_ERROR_CALLBACK
  3554.      * @see PEAR_ERROR_EXCEPTION
  3555.      *
  3556.      * @since PHP 4.0.5
  3557.      * @uses PEAR::setErrorHandling($mode, $options)
  3558.      */
  3559.     public function setErrorHandling($mode = null, $options = null)
  3560.     {
  3561.         return $this->pear->setErrorHandling($mode$options);
  3562.     }
  3563.  
  3564.     /**
  3565.      * @uses PEAR::staticPopErrorHandling() 
  3566.      */
  3567.     public function staticPopErrorHandling()
  3568.     {
  3569.         return $this->pear->staticPopErrorHandling();
  3570.     }
  3571.  
  3572.     // }}}
  3573.     // {{{ function staticPushErrorHandling($mode, $options = null)
  3574.     /**
  3575.      * @uses PEAR::staticPushErrorHandling($mode, $options)
  3576.      */
  3577.     public function staticPushErrorHandling($mode, $options = null)
  3578.     {
  3579.         return $this->pear->staticPushErrorHandling($mode$options);
  3580.     }
  3581.  
  3582.     // }}}
  3583.     // {{{ function &throwError($message = null, $code = null, $userinfo = null)
  3584.     /**
  3585.      * Simpler form of raiseError with fewer options.  In most cases
  3586.      * message, code and userinfo are enough.
  3587.      *
  3588.      * @param mixed $message a text error message or a PEAR error object
  3589.      *
  3590.      * @param int $code      a numeric error code (it is up to your class
  3591.      *                  to define these if you want to use codes)
  3592.      *
  3593.      * @param string $userinfo If you need to pass along for example debug
  3594.      *                  information, this parameter is meant for that.
  3595.      *
  3596.      * @return object   a PEAR error object
  3597.      * @see PEAR::raiseError
  3598.      * @uses PEAR::&throwError()
  3599.      */
  3600.     public function &throwError($message = null, $code = null, $userinfo = null)
  3601.     {
  3602.         $tmp =& $this->pear->throwError($message$code$userinfo);
  3603.         return $tmp;
  3604.     }
  3605.  
  3606.     // }}}
  3607. }
  3608.  
  3609. // }}}
  3610. // {{{ class MDB2_Result
  3611. /**
  3612.  * The dummy class that all user space result classes should extend from
  3613.  *
  3614.  * @package     MDB2
  3615.  * @category    Database
  3616.  * @author      Lukas Smith <smith@pooteeweet.org>
  3617.  */
  3618. class MDB2_Result
  3619. {
  3620. }
  3621.  
  3622. // }}}
  3623. // {{{ class MDB2_Result_Common extends MDB2_Result
  3624. /**
  3625.  * The common result class for MDB2 result objects
  3626.  *
  3627.  * @package     MDB2
  3628.  * @category    Database
  3629.  * @author      Lukas Smith <smith@pooteeweet.org>
  3630.  */
  3631. class MDB2_Result_Common extends MDB2_Result
  3632. {
  3633.     // {{{ Variables (Properties)
  3634.     public $db;
  3635.     public $result;
  3636.     public $rownum = -1;
  3637.     public $types = array();
  3638.     public $types_assoc = array();
  3639.     public $values = array();
  3640.     public $offset;
  3641.     public $offset_count = 0;
  3642.     public $limit;
  3643.     public $column_names;
  3644.  
  3645.     // }}}
  3646.     // {{{ constructor: function __construct($db, &$result, $limit = 0, $offset = 0)
  3647.     /**
  3648.      * Constructor
  3649.      */
  3650.     function __construct($db, &$result, $limit = 0, $offset = 0)
  3651.     {
  3652.         $this->db $db;
  3653.         $this->result $result;
  3654.         $this->offset = $offset;
  3655.         $this->limit = max(0$limit - 1);
  3656.     }
  3657.  
  3658.     // }}}
  3659.     // {{{ function setResultTypes($types)
  3660.     /**
  3661.      * Define the list of types to be associated with the columns of a given
  3662.      * result set.
  3663.      *
  3664.      * This function may be called before invoking fetchRow(), fetchOne(),
  3665.      * fetchCol() and fetchAll() so that the necessary data type
  3666.      * conversions are performed on the data to be retrieved by them. If this
  3667.      * function is not called, the type of all result set columns is assumed
  3668.      * to be text, thus leading to not perform any conversions.
  3669.      *
  3670.      * @param   array   variable that lists the
  3671.      *       data types to be expected in the result set columns. If this array
  3672.      *       contains less types than the number of columns that are returned
  3673.      *       in the result set, the remaining columns are assumed to be of the
  3674.      *       type text. Currently, the types clob and blob are not fully
  3675.      *       supported.
  3676.      *
  3677.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  3678.      *
  3679.      * @access  public
  3680.      */
  3681.     function setResultTypes($types)
  3682.     {
  3683.         $load = $this->db->loadModule('Datatype'nulltrue);
  3684.         if (MDB2::isError($load)) {
  3685.             return $load;
  3686.         }
  3687.         $types = $this->db->datatype->checkResultTypes($types);
  3688.         if (MDB2::isError($types)) {
  3689.             return $types;
  3690.         }
  3691.         foreach ($types as $key => $value) {
  3692.             if (is_numeric($key)) {
  3693.                 $this->types[$key$value;
  3694.             } else {
  3695.                 $this->types_assoc[$key$value;
  3696.             }
  3697.         }
  3698.         return MDB2_OK;
  3699.     }
  3700.  
  3701.     // }}}
  3702.     // {{{ function seek($rownum = 0)
  3703.     /**
  3704.      * Seek to a specific row in a result set
  3705.      *
  3706.      * @param   int     number of the row where the data can be found
  3707.      *
  3708.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  3709.      *
  3710.      * @access  public
  3711.      */
  3712.     function seek($rownum = 0)
  3713.     {
  3714.         $target_rownum = $rownum - 1;
  3715.         if ($this->rownum $target_rownum{
  3716.             return MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3717.                 'seeking to previous rows not implemented', __FUNCTION__);
  3718.         }
  3719.         while ($this->rownum $target_rownum{
  3720.             $this->fetchRow();
  3721.         }
  3722.         return MDB2_OK;
  3723.     }
  3724.  
  3725.     // }}}
  3726.     // {{{ function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
  3727.     /**
  3728.      * Fetch and return a row of data
  3729.      *
  3730.      * @param   int     how the array data should be indexed
  3731.      * @param   int     number of the row where the data can be found
  3732.      *
  3733.      * @return  int     data array on success, a MDB2 error on failure
  3734.      *
  3735.      * @access  public
  3736.      */
  3737.     function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
  3738.     {
  3739.         $err = MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3740.             'method not implemented', __FUNCTION__);
  3741.         return $err;
  3742.     }
  3743.  
  3744.     // }}}
  3745.     // {{{ function fetchOne($colnum = 0)
  3746.     /**
  3747.      * fetch single column from the next row from a result set
  3748.      *
  3749.      * @param int|string the column number (or name) to fetch
  3750.      * @param int        number of the row where the data can be found
  3751.      *
  3752.      * @return string data on success, a MDB2 error on failure
  3753.      * @access  public
  3754.      */
  3755.     function fetchOne($colnum = 0, $rownum = null)
  3756.     {
  3757.         $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
  3758.         $row = $this->fetchRow($fetchmode$rownum);
  3759.         if (!is_array($row|| MDB2::isError($row)) {
  3760.             return $row;
  3761.         }
  3762.         if (!array_key_exists($colnum, $row)) {
  3763.             return MDB2::raiseError(MDB2_ERROR_TRUNCATED, null, null,
  3764.                 'column is not defined in the result set: '.$colnum, __FUNCTION__);
  3765.         }
  3766.         return $row[$colnum];
  3767.     }
  3768.  
  3769.     // }}}
  3770.     // {{{ function fetchCol($colnum = 0)
  3771.     /**
  3772.      * Fetch and return a column from the current row pointer position
  3773.      *
  3774.      * @param int|string the column number (or name) to fetch
  3775.      *
  3776.      * @return  mixed data array on success, a MDB2 error on failure
  3777.      * @access  public
  3778.      */
  3779.     function fetchCol($colnum = 0)
  3780.     {
  3781.         $column = array();
  3782.         $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
  3783.         $row = $this->fetchRow($fetchmode);
  3784.         if (is_array($row)) {
  3785.             if (!array_key_exists($colnum, $row)) {
  3786.                 return MDB2::raiseError(MDB2_ERROR_TRUNCATED, null, null,
  3787.                     'column is not defined in the result set: '.$colnum, __FUNCTION__);
  3788.             }
  3789.             do {
  3790.                 $column[] = $row[$colnum];
  3791.             } while (is_array($row = $this->fetchRow($fetchmode)));
  3792.         }
  3793.         if (MDB2::isError($row)) {
  3794.             return $row;
  3795.         }
  3796.         return $column;
  3797.     }
  3798.  
  3799.     // }}}
  3800.     // {{{ function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)
  3801.     /**
  3802.      * Fetch and return all rows from the current row pointer position
  3803.      *
  3804.      * @param   int     $fetchmode  the fetch mode to use:
  3805.      *                            + MDB2_FETCHMODE_ORDERED
  3806.      *                            + MDB2_FETCHMODE_ASSOC
  3807.      *                            + MDB2_FETCHMODE_ORDERED | MDB2_FETCHMODE_FLIPPED
  3808.      *                            + MDB2_FETCHMODE_ASSOC | MDB2_FETCHMODE_FLIPPED
  3809.      * @param   bool    if set to true, the $all will have the first
  3810.      *       column as its first dimension
  3811.      * @param   bool    used only when the query returns exactly
  3812.      *       two columns. If true, the values of the returned array will be
  3813.      *       one-element arrays instead of scalars.
  3814.      * @param   bool    if true, the values of the returned array is
  3815.      *       wrapped in another array.  If the same key value (in the first
  3816.      *       column) repeats itself, the values will be appended to this array
  3817.      *       instead of overwriting the existing values.
  3818.      *
  3819.      * @return  mixed   data array on success, a MDB2 error on failure
  3820.      *
  3821.      * @access  public
  3822.      * @see     getAssoc()
  3823.      */
  3824.     function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false,
  3825.         $force_array = false, $group = false)
  3826.     {
  3827.         $all = array();
  3828.         $row = $this->fetchRow($fetchmode);
  3829.         if (MDB2::isError($row)) {
  3830.             return $row;
  3831.         } elseif (!$row) {
  3832.             return $all;
  3833.         }
  3834.  
  3835.         $shift_array = $rekey ? false : null;
  3836.         if (null !== $shift_array) {
  3837.             if (is_object($row)) {
  3838.                 $colnum = count(get_object_vars($row));
  3839.             } else {
  3840.                 $colnum = count($row);
  3841.             }
  3842.             if ($colnum < 2) {
  3843.                 return MDB2::raiseError(MDB2_ERROR_TRUNCATED, null, null,
  3844.                     'rekey feature requires atleast 2 column', __FUNCTION__);
  3845.             }
  3846.             $shift_array = (!$force_array && $colnum == 2);
  3847.         }
  3848.  
  3849.         if ($rekey) {
  3850.             do {
  3851.                 if (is_object($row)) {
  3852.                     $arr = get_object_vars($row);
  3853.                     $key = reset($arr);
  3854.                     unset($row->{$key});
  3855.                 } else {
  3856.                     if (   $fetchmode == MDB2_FETCHMODE_ASSOC
  3857.                         || $fetchmode == MDB2_FETCHMODE_OBJECT
  3858.                     ) {
  3859.                         $key = reset($row);
  3860.                         unset($row[key($row)]);
  3861.                     } else {
  3862.                         $key = array_shift($row);
  3863.                     }
  3864.                     if ($shift_array) {
  3865.                         $row = array_shift($row);
  3866.                     }
  3867.                 }
  3868.                 if ($group) {
  3869.                     $all[$key][] = $row;
  3870.                 } else {
  3871.                     $all[$key] = $row;
  3872.                 }
  3873.             } while (($row = $this->fetchRow($fetchmode)));
  3874.         } elseif ($fetchmode == MDB2_FETCHMODE_FLIPPED) {
  3875.             do {
  3876.                 foreach ($row as $key => $val) {
  3877.                     $all[$key][] = $val;
  3878.                 }
  3879.             } while (($row = $this->fetchRow($fetchmode)));
  3880.         } else {
  3881.             do {
  3882.                 $all[] = $row;
  3883.             } while (($row = $this->fetchRow($fetchmode)));
  3884.         }
  3885.  
  3886.         return $all;
  3887.     }
  3888.  
  3889.     // }}}
  3890.     // {{{ function rowCount()
  3891.     /**
  3892.      * Returns the actual row number that was last fetched (count from 0)
  3893.      * @return  int
  3894.      *
  3895.      * @access  public
  3896.      */
  3897.     function rowCount()
  3898.     {
  3899.         return $this->rownum + 1;
  3900.     }
  3901.  
  3902.     // }}}
  3903.     // {{{ function numRows()
  3904.     /**
  3905.      * Returns the number of rows in a result object
  3906.      *
  3907.      * @return  mixed   MDB2 Error Object or the number of rows
  3908.      *
  3909.      * @access  public
  3910.      */
  3911.     function numRows()
  3912.     {
  3913.         return MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3914.             'method not implemented', __FUNCTION__);
  3915.     }
  3916.  
  3917.     // }}}
  3918.     // {{{ function nextResult()
  3919.     /**
  3920.      * Move the internal result pointer to the next available result
  3921.      *
  3922.      * @return  true on success, false if there is no more result set or an error object on failure
  3923.      *
  3924.      * @access  public
  3925.      */
  3926.     function nextResult()
  3927.     {
  3928.         return MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3929.             'method not implemented', __FUNCTION__);
  3930.     }
  3931.  
  3932.     // }}}
  3933.     // {{{ function getColumnNames()
  3934.     /**
  3935.      * Retrieve the names of columns returned by the DBMS in a query result or
  3936.      * from the cache.
  3937.      *
  3938.      * @param   bool    If set to true the values are the column names,
  3939.      *                  otherwise the names of the columns are the keys.
  3940.      * @return  mixed   Array variable that holds the names of columns or an
  3941.      *                  MDB2 error on failure.
  3942.      *                  Some DBMS may not return any columns when the result set
  3943.      *                  does not contain any rows.
  3944.      *
  3945.      * @access  public
  3946.      */
  3947.     function getColumnNames($flip = false)
  3948.     {
  3949.         if (!isset($this->column_names)) {
  3950.             $result = $this->_getColumnNames();
  3951.             if (MDB2::isError($result)) {
  3952.                 return $result;
  3953.             }
  3954.             $this->column_names $result;
  3955.         }
  3956.         if ($flip) {
  3957.             return array_flip($this->column_names);
  3958.         }
  3959.         return $this->column_names;
  3960.     }
  3961.  
  3962.     // }}}
  3963.     // {{{ function _getColumnNames()
  3964.     /**
  3965.      * Retrieve the names of columns returned by the DBMS in a query result.
  3966.      *
  3967.      * @return  mixed   Array variable that holds the names of columns as keys
  3968.      *                  or an MDB2 error on failure.
  3969.      *                  Some DBMS may not return any columns when the result set
  3970.      *                  does not contain any rows.
  3971.      *
  3972.      * @access  private
  3973.      */
  3974.     function _getColumnNames()
  3975.     {
  3976.         return MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3977.             'method not implemented', __FUNCTION__);
  3978.     }
  3979.  
  3980.     // }}}
  3981.     // {{{ function numCols()
  3982.     /**
  3983.      * Count the number of columns returned by the DBMS in a query result.
  3984.      *
  3985.      * @return  mixed   integer value with the number of columns, a MDB2 error
  3986.      *       on failure
  3987.      *
  3988.      * @access  public
  3989.      */
  3990.     function numCols()
  3991.     {
  3992.         return MDB2::raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  3993.             'method not implemented', __FUNCTION__);
  3994.     }
  3995.  
  3996.     // }}}
  3997.     // {{{ function getResource()
  3998.     /**
  3999.      * return the resource associated with the result object
  4000.      *
  4001.      * @return  resource
  4002.      *
  4003.      * @access  public
  4004.      */
  4005.     function getResource()
  4006.     {
  4007.         return $this->result;
  4008.     }
  4009.  
  4010.     // }}}
  4011.     // {{{ function bindColumn($column, &$value, $type = null)
  4012.     /**
  4013.      * Set bind variable to a column.
  4014.      *
  4015.      * @param   int     column number or name
  4016.      * @param   mixed   variable reference
  4017.      * @param   string  specifies the type of the field
  4018.      *
  4019.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4020.      *
  4021.      * @access  public
  4022.      */
  4023.     function bindColumn($column, &$value, $type = null)
  4024.     {
  4025.         if (!is_numeric($column)) {
  4026.             $column_names = $this->getColumnNames();
  4027.             if ($this->db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  4028.                 if ($this->db->options['field_case'== CASE_LOWER{
  4029.                     $column = strtolower($column);
  4030.                 } else {
  4031.                     $column = strtoupper($column);
  4032.                 }
  4033.             }
  4034.             $column = $column_names[$column];
  4035.         }
  4036.         $this->values[$column=$value;
  4037.         if (null !== $type{
  4038.             $this->types[$column$type;
  4039.         }
  4040.         return MDB2_OK;
  4041.     }
  4042.  
  4043.     // }}}
  4044.     // {{{ function _assignBindColumns($row)
  4045.     /**
  4046.      * Bind a variable to a value in the result row.
  4047.      *
  4048.      * @param   array   row data
  4049.      *
  4050.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4051.      *
  4052.      * @access  private
  4053.      */
  4054.     function _assignBindColumns($row)
  4055.     {
  4056.         $row = array_values($row);
  4057.         foreach ($row as $column => $value) {
  4058.             if (array_key_exists($column, $this->values)) {
  4059.                 $this->values[$column$value;
  4060.             }
  4061.         }
  4062.         return MDB2_OK;
  4063.     }
  4064.  
  4065.     // }}}
  4066.     // {{{ function free()
  4067.     /**
  4068.      * Free the internal resources associated with result.
  4069.      *
  4070.      * @return  bool    true on success, false if result is invalid
  4071.      *
  4072.      * @access  public
  4073.      */
  4074.     function free()
  4075.     {
  4076.         $this->result = false;
  4077.         return MDB2_OK;
  4078.     }
  4079.  
  4080.     // }}}
  4081. }
  4082.  
  4083. // }}}
  4084. // {{{ class MDB2_Row
  4085. /**
  4086.  * The simple class that accepts row data as an array
  4087.  *
  4088.  * @package     MDB2
  4089.  * @category    Database
  4090.  * @author      Lukas Smith <smith@pooteeweet.org>
  4091.  */
  4092. class MDB2_Row
  4093. {
  4094.     // {{{ constructor: function __construct(&$row)
  4095.     /**
  4096.      * constructor
  4097.      *
  4098.      * @param   resource    row data as array
  4099.      */
  4100.     function __construct(&$row)
  4101.     {
  4102.         foreach ($row as $key => $value) {
  4103.             $this->$key &$row[$key];
  4104.         }
  4105.     }
  4106.  
  4107.     // }}}
  4108. }
  4109.  
  4110. // }}}
  4111. // {{{ class MDB2_Statement_Common
  4112. /**
  4113.  * The common statement class for MDB2 statement objects
  4114.  *
  4115.  * @package     MDB2
  4116.  * @category    Database
  4117.  * @author      Lukas Smith <smith@pooteeweet.org>
  4118.  */
  4119. class MDB2_Statement_Common
  4120. {
  4121.     // {{{ Variables (Properties)
  4122.     var $db;
  4123.     var $statement;
  4124.     var $query;
  4125.     var $result_types;
  4126.     var $types;
  4127.     var $values = array();
  4128.     var $limit;
  4129.     var $offset;
  4130.     var $is_manip;
  4131.  
  4132.     // }}}
  4133.     // {{{ constructor: function __construct($db, $statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
  4134.     /**
  4135.      * Constructor
  4136.      */
  4137.     function __construct($db, $statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
  4138.     {
  4139.         $this->db $db;
  4140.         $this->statement $statement;
  4141.         $this->positions $positions;
  4142.         $this->query $query;
  4143.         $this->types = (array)$types;
  4144.         $this->result_types = (array)$result_types;
  4145.         $this->limit = $limit;
  4146.         $this->is_manip $is_manip;
  4147.         $this->offset = $offset;
  4148.     }
  4149.  
  4150.     // }}}
  4151.     // {{{ function bindValue($parameter, &$value, $type = null)
  4152.     /**
  4153.      * Set the value of a parameter of a prepared query.
  4154.      *
  4155.      * @param   int     the order number of the parameter in the query
  4156.      *       statement. The order number of the first parameter is 1.
  4157.      * @param   mixed   value that is meant to be assigned to specified
  4158.      *       parameter. The type of the value depends on the $type argument.
  4159.      * @param   string  specifies the type of the field
  4160.      *
  4161.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4162.      *
  4163.      * @access  public
  4164.      */
  4165.     function bindValue($parameter, $value, $type = null)
  4166.     {
  4167.         if (!is_numeric($parameter)) {
  4168.             if (strpos($parameter, ':') === 0) {
  4169.                 $parameter = substr($parameter, 1);
  4170.             }
  4171.         }
  4172.         if (!in_array($parameter, $this->positions)) {
  4173.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  4174.                 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
  4175.         }
  4176.         $this->values[$parameter$value;
  4177.         if (null !== $type{
  4178.             $this->types[$parameter$type;
  4179.         }
  4180.         return MDB2_OK;
  4181.     }
  4182.  
  4183.     // }}}
  4184.     // {{{ function bindValueArray($values, $types = null)
  4185.     /**
  4186.      * Set the values of multiple a parameter of a prepared query in bulk.
  4187.      *
  4188.      * @param   array   specifies all necessary information
  4189.      *       for bindValue() the array elements must use keys corresponding to
  4190.      *       the number of the position of the parameter.
  4191.      * @param   array   specifies the types of the fields
  4192.      *
  4193.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4194.      *
  4195.      * @access  public
  4196.      * @see     bindParam()
  4197.      */
  4198.     function bindValueArray($values, $types = null)
  4199.     {
  4200.         $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
  4201.         $parameters = array_keys($values);
  4202.         $this->db->pushErrorHandling(PEAR_ERROR_RETURN);
  4203.         $this->db->expectError(MDB2_ERROR_NOT_FOUND);
  4204.         foreach ($parameters as $key => $parameter{
  4205.             $err = $this->bindValue($parameter$values[$parameter]$types[$key]);
  4206.             if (MDB2::isError($err)) {
  4207.                 if ($err->getCode(== MDB2_ERROR_NOT_FOUND{
  4208.                     //ignore (extra value for missing placeholder)
  4209.                     continue;
  4210.                 }
  4211.                 $this->db->popExpect();
  4212.                 $this->db->popErrorHandling();
  4213.                 return $err;
  4214.             }
  4215.         }
  4216.         $this->db->popExpect();
  4217.         $this->db->popErrorHandling();
  4218.         return MDB2_OK;
  4219.     }
  4220.  
  4221.     // }}}
  4222.     // {{{ function bindParam($parameter, &$value, $type = null)
  4223.     /**
  4224.      * Bind a variable to a parameter of a prepared query.
  4225.      *
  4226.      * @param   int     the order number of the parameter in the query
  4227.      *       statement. The order number of the first parameter is 1.
  4228.      * @param   mixed   variable that is meant to be bound to specified
  4229.      *       parameter. The type of the value depends on the $type argument.
  4230.      * @param   string  specifies the type of the field
  4231.      *
  4232.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4233.      *
  4234.      * @access  public
  4235.      */
  4236.     function bindParam($parameter, &$value, $type = null)
  4237.     {
  4238.         if (!is_numeric($parameter)) {
  4239.             if (strpos($parameter, ':') === 0) {
  4240.                 $parameter = substr($parameter, 1);
  4241.             }
  4242.         }
  4243.         if (!in_array($parameter, $this->positions)) {
  4244.             return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  4245.                 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
  4246.         }
  4247.         $this->values[$parameter=$value;
  4248.         if (null !== $type{
  4249.             $this->types[$parameter$type;
  4250.         }
  4251.         return MDB2_OK;
  4252.     }
  4253.  
  4254.     // }}}
  4255.     // {{{ function bindParamArray(&$values, $types = null)
  4256.     /**
  4257.      * Bind the variables of multiple a parameter of a prepared query in bulk.
  4258.      *
  4259.      * @param   array   specifies all necessary information
  4260.      *       for bindParam() the array elements must use keys corresponding to
  4261.      *       the number of the position of the parameter.
  4262.      * @param   array   specifies the types of the fields
  4263.      *
  4264.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4265.      *
  4266.      * @access  public
  4267.      * @see     bindParam()
  4268.      */
  4269.     function bindParamArray(&$values, $types = null)
  4270.     {
  4271.         $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
  4272.         $parameters = array_keys($values);
  4273.         foreach ($parameters as $key => $parameter) {
  4274.             $err = $this->bindParam($parameter$values[$parameter]$types[$key]);
  4275.             if (MDB2::isError($err)) {
  4276.                 return $err;
  4277.             }
  4278.         }
  4279.         return MDB2_OK;
  4280.     }
  4281.  
  4282.     // }}}
  4283.     // {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false)
  4284.     /**
  4285.      * Execute a prepared query statement.
  4286.      *
  4287.      * @param array specifies all necessary information
  4288.      *              for bindParam() the array elements must use keys corresponding
  4289.      *              to the number of the position of the parameter.
  4290.      * @param mixed specifies which result class to use
  4291.      * @param mixed specifies which class to wrap results in
  4292.      *
  4293.      * @return mixed MDB2_Result or integer (affected rows) on success,
  4294.      *               a MDB2 error on failure
  4295.      * @access public
  4296.      */
  4297.     function execute($values = null, $result_class = true, $result_wrap_class = false)
  4298.     {
  4299.         if (null === $this->positions{
  4300.             return MDB2::raiseError(MDB2_ERROR, null, null,
  4301.                 'Prepared statement has already been freed', __FUNCTION__);
  4302.         }
  4303.  
  4304.         $values = (array)$values;
  4305.         if (!empty($values)) {
  4306.             $err = $this->bindValueArray($values);
  4307.             if (MDB2::isError($err)) {
  4308.                 return MDB2::raiseError(MDB2_ERROR, null, null,
  4309.                                             'Binding Values failed with message: ' . $err->getMessage()__FUNCTION__);
  4310.             }
  4311.         }
  4312.         $result = $this->_execute($result_class$result_wrap_class);
  4313.         return $result;
  4314.     }
  4315.  
  4316.     // }}}
  4317.     // {{{ function _execute($result_class = true, $result_wrap_class = false)
  4318.     /**
  4319.      * Execute a prepared query statement helper method.
  4320.      *
  4321.      * @param   mixed   specifies which result class to use
  4322.      * @param   mixed   specifies which class to wrap results in
  4323.      *
  4324.      * @return mixed MDB2_Result or integer (affected rows) on success,
  4325.      *               a MDB2 error on failure
  4326.      * @access  private
  4327.      */
  4328.     function _execute($result_class = true, $result_wrap_class = false)
  4329.     {
  4330.         $this->last_query = $this->query;
  4331.         $query '';
  4332.         $last_position = 0;
  4333.         foreach ($this->positions as $current_position => $parameter{
  4334.             if (!array_key_exists($parameter, $this->values)) {
  4335.                 return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  4336.                     'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
  4337.             }
  4338.             $value = $this->values[$parameter];
  4339.             $query.= substr($this->query$last_position$current_position $last_position);
  4340.             if (!isset($value)) {
  4341.                 $value_quoted = 'NULL';
  4342.             } else {
  4343.                 $type = !empty($this->types[$parameter]$this->types[$parameter: null;
  4344.                 $value_quoted $this->db->quote($value$type);
  4345.                 if (MDB2::isError($value_quoted)) {
  4346.                     return $value_quoted;
  4347.                 }
  4348.             }
  4349.             $query.= $value_quoted;
  4350.             $last_position = $current_position + 1;
  4351.         }
  4352.         $query.= substr($this->query$last_position);
  4353.  
  4354.         $this->db->offset = $this->offset;
  4355.         $this->db->limit = $this->limit;
  4356.         if ($this->is_manip{
  4357.             $result = $this->db->exec($query);
  4358.         } else {
  4359.             $result = $this->db->query($query$this->result_types$result_class$result_wrap_class);
  4360.         }
  4361.         return $result;
  4362.     }
  4363.  
  4364.     // }}}
  4365.     // {{{ function free()
  4366.     /**
  4367.      * Release resources allocated for the specified prepared query.
  4368.      *
  4369.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  4370.      *
  4371.      * @access  public
  4372.      */
  4373.     function free()
  4374.     {
  4375.         if (null === $this->positions{
  4376.             return MDB2::raiseError(MDB2_ERROR, null, null,
  4377.                 'Prepared statement has already been freed', __FUNCTION__);
  4378.         }
  4379.  
  4380.         $this->statement = null;
  4381.         $this->positions = null;
  4382.         $this->query = null;
  4383.         $this->types = null;
  4384.         $this->result_types = null;
  4385.         $this->limit = null;
  4386.         $this->is_manip = null;
  4387.         $this->offset = null;
  4388.         $this->values = null;
  4389.  
  4390.         return MDB2_OK;
  4391.     }
  4392.  
  4393.     // }}}
  4394. }
  4395.  
  4396. // }}}
  4397. // {{{ class MDB2_Module_Common
  4398. /**
  4399.  * The common modules class for MDB2 module objects
  4400.  *
  4401.  * @package     MDB2
  4402.  * @category    Database
  4403.  * @author      Lukas Smith <smith@pooteeweet.org>
  4404.  */
  4405. class MDB2_Module_Common
  4406. {
  4407.     // {{{ Variables (Properties)
  4408.     /**
  4409.      * contains the key to the global MDB2 instance array of the associated
  4410.      * MDB2 instance
  4411.      *
  4412.      * @var     int
  4413.      * @access  protected
  4414.      */
  4415.     protected $db_index;
  4416.  
  4417.     // }}}
  4418.     // {{{ constructor: function __construct($db_index)
  4419.     /**
  4420.      * Constructor
  4421.      */
  4422.     function __construct($db_index)
  4423.     {
  4424.         $this->db_index = $db_index;
  4425.     }
  4426.  
  4427.     // }}}
  4428.     // {{{ function getDBInstance()
  4429.     /**
  4430.      * Get the instance of MDB2 associated with the module instance
  4431.      *
  4432.      * @return  object  MDB2 instance or a MDB2 error on failure
  4433.      *
  4434.      * @access  public
  4435.      */
  4436.     function getDBInstance()
  4437.     {
  4438.         if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
  4439.             $result = $GLOBALS['_MDB2_databases'][$this->db_index];
  4440.         } else {
  4441.             $result = MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  4442.                 'could not find MDB2 instance');
  4443.         }
  4444.         return $result;
  4445.     }
  4446.  
  4447.     // }}}
  4448. }
  4449.  
  4450. // }}}
  4451. // {{{ function MDB2_closeOpenTransactions()
  4452. /**
  4453.  * Close any open transactions form persistent connections
  4454.  *
  4455.  * @return  void
  4456.  *
  4457.  * @access  public
  4458.  */
  4459.  
  4460. function MDB2_closeOpenTransactions()
  4461. {
  4462.     reset($GLOBALS['_MDB2_databases']);
  4463.     while (next($GLOBALS['_MDB2_databases'])) {
  4464.         $key = key($GLOBALS['_MDB2_databases']);
  4465.         if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent
  4466.             && $GLOBALS['_MDB2_databases'][$key]->in_transaction
  4467.         {
  4468.             $GLOBALS['_MDB2_databases'][$key]->rollback();
  4469.         }
  4470.     }
  4471. }
  4472.  
  4473. // }}}
  4474. // {{{ function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null)
  4475. /**
  4476.  * default debug output handler
  4477.  *
  4478.  * @param   object  reference to an MDB2 database object
  4479.  * @param   string  usually the method name that triggered the debug call:
  4480.  *                  for example 'query', 'prepare', 'execute', 'parameters',
  4481.  *                  'beginTransaction', 'commit', 'rollback'
  4482.  * @param   string  message that should be appended to the debug variable
  4483.  * @param   array   contains context information about the debug() call
  4484.  *                  common keys are: is_manip, time, result etc.
  4485.  *
  4486.  * @return  void|string optionally return a modified message, this allows
  4487.  *                      rewriting a query before being issued or prepared
  4488.  *
  4489.  * @access  public
  4490.  */
  4491. function MDB2_defaultDebugOutput(&$db, $scope, $message, $context = array())
  4492. {
  4493.     $db->debug_output.= $scope.'('.$db->db_index.'): ';
  4494.     $db->debug_output.= $message.$db->getOption('log_line_break');
  4495.     return $message;
  4496. }
  4497.  
  4498. // }}}

Documentation generated on Mon, 29 Oct 2012 16:00:16 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.