PageRenderTime 213ms CodeModel.GetById 165ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/tags/1.3b/includes/pear/MDB2.php

http://kfm.googlecode.com/
PHP | 4271 lines | 1844 code | 373 blank | 2054 comment | 300 complexity | 0d4093f6d7db5ec64434116b700e9a82 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2// vim: set et ts=4 sw=4 fdm=marker:
   3// +----------------------------------------------------------------------+
   4// | PHP versions 4 and 5                                                 |
   5// +----------------------------------------------------------------------+
   6// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
   7// | Stig. S. Bakken, Lukas Smith                                         |
   8// | All rights reserved.                                                 |
   9// +----------------------------------------------------------------------+
  10// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
  11// | API as well as database abstraction for PHP applications.            |
  12// | This LICENSE is in the BSD license style.                            |
  13// |                                                                      |
  14// | Redistribution and use in source and binary forms, with or without   |
  15// | modification, are permitted provided that the following conditions   |
  16// | are met:                                                             |
  17// |                                                                      |
  18// | Redistributions of source code must retain the above copyright       |
  19// | notice, this list of conditions and the following disclaimer.        |
  20// |                                                                      |
  21// | Redistributions in binary form must reproduce the above copyright    |
  22// | notice, this list of conditions and the following disclaimer in the  |
  23// | documentation and/or other materials provided with the distribution. |
  24// |                                                                      |
  25// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  26// | Lukas Smith nor the names of his contributors may be used to endorse |
  27// | or promote products derived from this software without specific prior|
  28// | written permission.                                                  |
  29// |                                                                      |
  30// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  31// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  32// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  33// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  34// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  35// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  38// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  39// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  41// | POSSIBILITY OF SUCH DAMAGE.                                          |
  42// +----------------------------------------------------------------------+
  43// | Author: Lukas Smith <smith@pooteeweet.org>                           |
  44// +----------------------------------------------------------------------+
  45//
  46// $Id: MDB2.php,v 1.292 2007/04/25 09:31:01 quipo Exp $
  47//
  48
  49/**
  50 * @package     MDB2
  51 * @category    Database
  52 * @author      Lukas Smith <smith@pooteeweet.org>
  53 */
  54
  55require_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
  67define('MDB2_OK',                      true);
  68define('MDB2_ERROR',                     -1);
  69define('MDB2_ERROR_SYNTAX',              -2);
  70define('MDB2_ERROR_CONSTRAINT',          -3);
  71define('MDB2_ERROR_NOT_FOUND',           -4);
  72define('MDB2_ERROR_ALREADY_EXISTS',      -5);
  73define('MDB2_ERROR_UNSUPPORTED',         -6);
  74define('MDB2_ERROR_MISMATCH',            -7);
  75define('MDB2_ERROR_INVALID',             -8);
  76define('MDB2_ERROR_NOT_CAPABLE',         -9);
  77define('MDB2_ERROR_TRUNCATED',          -10);
  78define('MDB2_ERROR_INVALID_NUMBER',     -11);
  79define('MDB2_ERROR_INVALID_DATE',       -12);
  80define('MDB2_ERROR_DIVZERO',            -13);
  81define('MDB2_ERROR_NODBSELECTED',       -14);
  82define('MDB2_ERROR_CANNOT_CREATE',      -15);
  83define('MDB2_ERROR_CANNOT_DELETE',      -16);
  84define('MDB2_ERROR_CANNOT_DROP',        -17);
  85define('MDB2_ERROR_NOSUCHTABLE',        -18);
  86define('MDB2_ERROR_NOSUCHFIELD',        -19);
  87define('MDB2_ERROR_NEED_MORE_DATA',     -20);
  88define('MDB2_ERROR_NOT_LOCKED',         -21);
  89define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22);
  90define('MDB2_ERROR_INVALID_DSN',        -23);
  91define('MDB2_ERROR_CONNECT_FAILED',     -24);
  92define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25);
  93define('MDB2_ERROR_NOSUCHDB',           -26);
  94define('MDB2_ERROR_ACCESS_VIOLATION',   -27);
  95define('MDB2_ERROR_CANNOT_REPLACE',     -28);
  96define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29);
  97define('MDB2_ERROR_DEADLOCK',           -30);
  98define('MDB2_ERROR_CANNOT_ALTER',       -31);
  99define('MDB2_ERROR_MANAGER',            -32);
 100define('MDB2_ERROR_MANAGER_PARSE',      -33);
 101define('MDB2_ERROR_LOADMODULE',         -34);
 102define('MDB2_ERROR_INSUFFICIENT_DATA',  -35);
 103// }}}
 104// {{{ Verbose constants
 105/**
 106 * These are just helper constants to more verbosely express parameters to prepare()
 107 */
 108
 109define('MDB2_PREPARE_MANIP', false);
 110define('MDB2_PREPARE_RESULT', null);
 111
 112// }}}
 113// {{{ Fetchmode constants
 114
 115/**
 116 * This is a special constant that tells MDB2 the user hasn't specified
 117 * any particular get mode, so the default should be used.
 118 */
 119define('MDB2_FETCHMODE_DEFAULT', 0);
 120
 121/**
 122 * Column data indexed by numbers, ordered from 0 and up
 123 */
 124define('MDB2_FETCHMODE_ORDERED', 1);
 125
 126/**
 127 * Column data indexed by column names
 128 */
 129define('MDB2_FETCHMODE_ASSOC', 2);
 130
 131/**
 132 * Column data as object properties
 133 */
 134define('MDB2_FETCHMODE_OBJECT', 3);
 135
 136/**
 137 * For multi-dimensional results: normally the first level of arrays
 138 * is the row number, and the second level indexed by column number or name.
 139 * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays
 140 * is the column name, and the second level the row number.
 141 */
 142define('MDB2_FETCHMODE_FLIPPED', 4);
 143
 144// }}}
 145// {{{ Portability mode constants
 146
 147/**
 148 * Portability: turn off all portability features.
 149 * @see MDB2_Driver_Common::setOption()
 150 */
 151define('MDB2_PORTABILITY_NONE', 0);
 152
 153/**
 154 * Portability: convert names of tables and fields to case defined in the
 155 * "field_case" option when using the query*(), fetch*() and tableInfo() methods.
 156 * @see MDB2_Driver_Common::setOption()
 157 */
 158define('MDB2_PORTABILITY_FIX_CASE', 1);
 159
 160/**
 161 * Portability: right trim the data output by query*() and fetch*().
 162 * @see MDB2_Driver_Common::setOption()
 163 */
 164define('MDB2_PORTABILITY_RTRIM', 2);
 165
 166/**
 167 * Portability: force reporting the number of rows deleted.
 168 * @see MDB2_Driver_Common::setOption()
 169 */
 170define('MDB2_PORTABILITY_DELETE_COUNT', 4);
 171
 172/**
 173 * Portability: not needed in MDB2 (just left here for compatibility to DB)
 174 * @see MDB2_Driver_Common::setOption()
 175 */
 176define('MDB2_PORTABILITY_NUMROWS', 8);
 177
 178/**
 179 * Portability: makes certain error messages in certain drivers compatible
 180 * with those from other DBMS's.
 181 *
 182 * + mysql, mysqli:  change unique/primary key constraints
 183 *   MDB2_ERROR_ALREADY_EXISTS -> MDB2_ERROR_CONSTRAINT
 184 *
 185 * + odbc(access):  MS's ODBC driver reports 'no such field' as code
 186 *   07001, which means 'too few parameters.'  When this option is on
 187 *   that code gets mapped to MDB2_ERROR_NOSUCHFIELD.
 188 *
 189 * @see MDB2_Driver_Common::setOption()
 190 */
 191define('MDB2_PORTABILITY_ERRORS', 16);
 192
 193/**
 194 * Portability: convert empty values to null strings in data output by
 195 * query*() and fetch*().
 196 * @see MDB2_Driver_Common::setOption()
 197 */
 198define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32);
 199
 200/**
 201 * Portability: removes database/table qualifiers from associative indexes
 202 * @see MDB2_Driver_Common::setOption()
 203 */
 204define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64);
 205
 206/**
 207 * Portability: turn on all portability features.
 208 * @see MDB2_Driver_Common::setOption()
 209 */
 210define('MDB2_PORTABILITY_ALL', 127);
 211
 212// }}}
 213// {{{ Globals for class instance tracking
 214
 215/**
 216 * These are global variables that are used to track the various class instances
 217 */
 218
 219$GLOBALS['_MDB2_databases'] = array();
 220$GLOBALS['_MDB2_dsninfo_default'] = array(
 221    'phptype'  => false,
 222    'dbsyntax' => false,
 223    'username' => false,
 224    'password' => false,
 225    'protocol' => false,
 226    'hostspec' => false,
 227    'port'     => false,
 228    'socket'   => false,
 229    'database' => false,
 230    'mode'     => false,
 231);
 232
 233// }}}
 234// {{{ class MDB2
 235
 236/**
 237 * The main 'MDB2' class is simply a container class with some static
 238 * methods for creating DB objects as well as some utility functions
 239 * common to all parts of DB.
 240 *
 241 * The object model of MDB2 is as follows (indentation means inheritance):
 242 *
 243 * MDB2          The main MDB2 class.  This is simply a utility class
 244 *              with some 'static' methods for creating MDB2 objects as
 245 *              well as common utility functions for other MDB2 classes.
 246 *
 247 * MDB2_Driver_Common   The base for each MDB2 implementation.  Provides default
 248 * |            implementations (in OO lingo virtual methods) for
 249 * |            the actual DB implementations as well as a bunch of
 250 * |            query utility functions.
 251 * |
 252 * +-MDB2_Driver_mysql  The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common.
 253 *              When calling MDB2::factory or MDB2::connect for MySQL
 254 *              connections, the object returned is an instance of this
 255 *              class.
 256 * +-MDB2_Driver_pgsql  The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common.
 257 *              When calling MDB2::factory or MDB2::connect for PostGreSQL
 258 *              connections, the object returned is an instance of this
 259 *              class.
 260 *
 261 * @package     MDB2
 262 * @category    Database
 263 * @author      Lukas Smith <smith@pooteeweet.org>
 264 */
 265class MDB2
 266{
 267    // {{{ function setOptions(&$db, $options)
 268
 269    /**
 270     * set option array   in an exiting database object
 271     *
 272     * @param   MDB2_Driver_Common  MDB2 object
 273     * @param   array   An associative array of option names and their values.
 274     *
 275     * @return mixed   MDB2_OK or a PEAR Error object
 276     *
 277     * @access  public
 278     */
 279    function setOptions(&$db, $options)
 280    {
 281        if (is_array($options)) {
 282            foreach ($options as $option => $value) {
 283                $test = $db->setOption($option, $value);
 284                if (PEAR::isError($test)) {
 285                    return $test;
 286                }
 287            }
 288        }
 289        return MDB2_OK;
 290    }
 291
 292    // }}}
 293    // {{{ function classExists($classname)
 294
 295    /**
 296     * Checks if a class exists without triggering __autoload
 297     *
 298     * @param   string  classname
 299     *
 300     * @return  bool    true success and false on error
 301     * @static
 302     * @access  public
 303     */
 304    function classExists($classname)
 305    {
 306        if (version_compare(phpversion(), "5.0", ">=")) {
 307            return class_exists($classname, false);
 308        }
 309        return class_exists($classname);
 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    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_FOUND, null, null, $msg);
 341                return $err;
 342            }
 343        }
 344        return MDB2_OK;
 345    }
 346
 347    // }}}
 348    // {{{ function &factory($dsn, $options = false)
 349
 350    /**
 351     * Create a new MDB2 object for the specified database type
 352     *
 353     * IMPORTANT: In order for MDB2 to work properly it is necessary that
 354     * you make sure that you work with a reference of the original
 355     * object instead of a copy (this is a PHP4 quirk).
 356     *
 357     * For example:
 358     *     $db =& MDB2::factory($dsn);
 359     *          ^^
 360     * And not:
 361     *     $db = MDB2::factory($dsn);
 362     *
 363     * @param   mixed   'data source name', see the MDB2::parseDSN
 364     *                      method for a description of the dsn format.
 365     *                      Can also be specified as an array of the
 366     *                      format returned by MDB2::parseDSN.
 367     * @param   array   An associative array of option names and
 368     *                            their values.
 369     *
 370     * @return  mixed   a newly created MDB2 object, or false on error
 371     *
 372     * @access  public
 373     */
 374    function &factory($dsn, $options = false)
 375    {
 376        $dsninfo = MDB2::parseDSN($dsn);
 377        if (empty($dsninfo['phptype'])) {
 378            $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND,
 379                null, null, 'no RDBMS driver specified');
 380            return $err;
 381        }
 382        $class_name = 'MDB2_Driver_'.$dsninfo['phptype'];
 383
 384        $debug = (!empty($options['debug']));
 385        $err = MDB2::loadClass($class_name, $debug);
 386        if (PEAR::isError($err)) {
 387            return $err;
 388        }
 389
 390        $db =& new $class_name();
 391        $db->setDSN($dsninfo);
 392        $err = MDB2::setOptions($db, $options);
 393        if (PEAR::isError($err)) {
 394            return $err;
 395        }
 396
 397        return $db;
 398    }
 399
 400    // }}}
 401    // {{{ function &connect($dsn, $options = false)
 402
 403    /**
 404     * Create a new MDB2 connection object and connect to the specified
 405     * database
 406     *
 407     * IMPORTANT: In order for MDB2 to work properly it is necessary that
 408     * you make sure that you work with a reference of the original
 409     * object instead of a copy (this is a PHP4 quirk).
 410     *
 411     * For example:
 412     *     $db =& MDB2::connect($dsn);
 413     *          ^^
 414     * And not:
 415     *     $db = MDB2::connect($dsn);
 416     *          ^^
 417     *
 418     * @param   mixed   'data source name', see the MDB2::parseDSN
 419     *                            method for a description of the dsn format.
 420     *                            Can also be specified as an array of the
 421     *                            format returned by MDB2::parseDSN.
 422     * @param   array   An associative array of option names and
 423     *                            their values.
 424     *
 425     * @return  mixed   a newly created MDB2 connection object, or a MDB2
 426     *                  error object on error
 427     *
 428     * @access  public
 429     * @see     MDB2::parseDSN
 430     */
 431    function &connect($dsn, $options = false)
 432    {
 433        $db =& MDB2::factory($dsn, $options);
 434        if (PEAR::isError($db)) {
 435            return $db;
 436        }
 437
 438        $err = $db->connect();
 439        if (PEAR::isError($err)) {
 440            $dsn = $db->getDSN('string', 'xxx');
 441            $db->disconnect();
 442            $err->addUserInfo($dsn);
 443            return $err;
 444        }
 445
 446        return $db;
 447    }
 448
 449    // }}}
 450    // {{{ function &singleton($dsn = null, $options = false)
 451
 452    /**
 453     * Returns a MDB2 connection with the requested DSN.
 454     * A new MDB2 connection object is only created if no object with the
 455     * requested DSN exists yet.
 456     *
 457     * IMPORTANT: In order for MDB2 to work properly it is necessary that
 458     * you make sure that you work with a reference of the original
 459     * object instead of a copy (this is a PHP4 quirk).
 460     *
 461     * For example:
 462     *     $db =& MDB2::singleton($dsn);
 463     *          ^^
 464     * And not:
 465     *     $db = MDB2::singleton($dsn);
 466     *          ^^
 467     *
 468     * @param   mixed   'data source name', see the MDB2::parseDSN
 469     *                            method for a description of the dsn format.
 470     *                            Can also be specified as an array of the
 471     *                            format returned by MDB2::parseDSN.
 472     * @param   array   An associative array of option names and
 473     *                            their values.
 474     *
 475     * @return  mixed   a newly created MDB2 connection object, or a MDB2
 476     *                  error object on error
 477     *
 478     * @access  public
 479     * @see     MDB2::parseDSN
 480     */
 481    function &singleton($dsn = null, $options = false)
 482    {
 483        if ($dsn) {
 484            $dsninfo = MDB2::parseDSN($dsn);
 485            $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo);
 486            $keys = array_keys($GLOBALS['_MDB2_databases']);
 487            for ($i=0, $j=count($keys); $i<$j; ++$i) {
 488                if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) {
 489                    $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array');
 490                    if (count(array_diff_assoc($tmp_dsn, $dsninfo)) == 0) {
 491                        MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options);
 492                        return $GLOBALS['_MDB2_databases'][$keys[$i]];
 493                    }
 494                }
 495            }
 496        } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) {
 497            $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])];
 498            return $db;
 499        }
 500        $db =& MDB2::factory($dsn, $options);
 501        return $db;
 502    }
 503
 504    // }}}
 505    // {{{ function loadFile($file)
 506
 507    /**
 508     * load a file (like 'Date')
 509     *
 510     * @param   string  name of the file in the MDB2 directory (without '.php')
 511     *
 512     * @return  string  name of the file that was included
 513     *
 514     * @access  public
 515     */
 516    function loadFile($file)
 517    {
 518        $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php';
 519        if (!MDB2::fileExists($file_name)) {
 520            return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
 521                'unable to find: '.$file_name);
 522        }
 523        if (!include_once($file_name)) {
 524            return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
 525                'unable to load driver class: '.$file_name);
 526        }
 527        return $file_name;
 528    }
 529
 530    // }}}
 531    // {{{ function apiVersion()
 532
 533    /**
 534     * Return the MDB2 API version
 535     *
 536     * @return  string  the MDB2 API version number
 537     *
 538     * @access  public
 539     */
 540    function apiVersion()
 541    {
 542        return '2.4.1';
 543    }
 544
 545    // }}}
 546    // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
 547
 548    /**
 549     * This method is used to communicate an error and invoke error
 550     * callbacks etc.  Basically a wrapper for PEAR::raiseError
 551     * without the message string.
 552     *
 553     * @param   mixed  int error code
 554     *
 555     * @param   int    error mode, see PEAR_Error docs
 556     *
 557     * @param   mixed  If error mode is PEAR_ERROR_TRIGGER, this is the
 558     *                 error level (E_USER_NOTICE etc).  If error mode is
 559     *                 PEAR_ERROR_CALLBACK, this is the callback function,
 560     *                 either as a function name, or as an array of an
 561     *                 object and method name.  For other error modes this
 562     *                 parameter is ignored.
 563     *
 564     * @param   string Extra debug information.  Defaults to the last
 565     *                 query and native error code.
 566     *
 567     * @return PEAR_Error instance of a PEAR Error object
 568     *
 569     * @access  private
 570     * @see     PEAR_Error
 571     */
 572    function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
 573    {
 574        $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
 575        return $err;
 576    }
 577
 578    // }}}
 579    // {{{ function isError($data, $code = null)
 580
 581    /**
 582     * Tell whether a value is a MDB2 error.
 583     *
 584     * @param   mixed   the value to test
 585     * @param   int     if is an error object, return true
 586     *                        only if $code is a string and
 587     *                        $db->getMessage() == $code or
 588     *                        $code is an integer and $db->getCode() == $code
 589     *
 590     * @return  bool    true if parameter is an error
 591     *
 592     * @access  public
 593     */
 594    function isError($data, $code = null)
 595    {
 596        if (is_a($data, 'MDB2_Error')) {
 597            if (is_null($code)) {
 598                return true;
 599            } elseif (is_string($code)) {
 600                return $data->getMessage() === $code;
 601            } else {
 602                $code = (array)$code;
 603                return in_array($data->getCode(), $code);
 604            }
 605        }
 606        return false;
 607    }
 608
 609    // }}}
 610    // {{{ function isConnection($value)
 611
 612    /**
 613     * Tell whether a value is a MDB2 connection
 614     *
 615     * @param   mixed   value to test
 616     *
 617     * @return  bool    whether $value is a MDB2 connection
 618     *
 619     * @access  public
 620     */
 621    function isConnection($value)
 622    {
 623        return is_a($value, 'MDB2_Driver_Common');
 624    }
 625
 626    // }}}
 627    // {{{ function isResult($value)
 628
 629    /**
 630     * Tell whether a value is a MDB2 result
 631     *
 632     * @param   mixed   value to test
 633     *
 634     * @return  bool    whether $value is a MDB2 result
 635     *
 636     * @access  public
 637     */
 638    function isResult($value)
 639    {
 640        return is_a($value, 'MDB2_Result');
 641    }
 642
 643    // }}}
 644    // {{{ function isResultCommon($value)
 645
 646    /**
 647     * Tell whether a value is a MDB2 result implementing the common interface
 648     *
 649     * @param   mixed   value to test
 650     *
 651     * @return  bool    whether $value is a MDB2 result implementing the common interface
 652     *
 653     * @access  public
 654     */
 655    function isResultCommon($value)
 656    {
 657        return is_a($value, 'MDB2_Result_Common');
 658    }
 659
 660    // }}}
 661    // {{{ function isStatement($value)
 662
 663    /**
 664     * Tell whether a value is a MDB2 statement interface
 665     *
 666     * @param   mixed   value to test
 667     *
 668     * @return  bool    whether $value is a MDB2 statement interface
 669     *
 670     * @access  public
 671     */
 672    function isStatement($value)
 673    {
 674        return is_a($value, 'MDB2_Statement');
 675    }
 676
 677    // }}}
 678    // {{{ function errorMessage($value = null)
 679
 680    /**
 681     * Return a textual error message for a MDB2 error code
 682     *
 683     * @param   int|array   integer error code,
 684                                null to get the current error code-message map,
 685                                or an array with a new error code-message map
 686     *
 687     * @return  string  error message, or false if the error code was
 688     *                  not recognized
 689     *
 690     * @access  public
 691     */
 692    function errorMessage($value = null)
 693    {
 694        static $errorMessages;
 695
 696        if (is_array($value)) {
 697            $errorMessages = $value;
 698            return MDB2_OK;
 699        }
 700
 701        if (!isset($errorMessages)) {
 702            $errorMessages = array(
 703                MDB2_OK                       => 'no error',
 704                MDB2_ERROR                    => 'unknown error',
 705                MDB2_ERROR_ALREADY_EXISTS     => 'already exists',
 706                MDB2_ERROR_CANNOT_CREATE      => 'can not create',
 707                MDB2_ERROR_CANNOT_ALTER       => 'can not alter',
 708                MDB2_ERROR_CANNOT_REPLACE     => 'can not replace',
 709                MDB2_ERROR_CANNOT_DELETE      => 'can not delete',
 710                MDB2_ERROR_CANNOT_DROP        => 'can not drop',
 711                MDB2_ERROR_CONSTRAINT         => 'constraint violation',
 712                MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
 713                MDB2_ERROR_DIVZERO            => 'division by zero',
 714                MDB2_ERROR_INVALID            => 'invalid',
 715                MDB2_ERROR_INVALID_DATE       => 'invalid date or time',
 716                MDB2_ERROR_INVALID_NUMBER     => 'invalid number',
 717                MDB2_ERROR_MISMATCH           => 'mismatch',
 718                MDB2_ERROR_NODBSELECTED       => 'no database selected',
 719                MDB2_ERROR_NOSUCHFIELD        => 'no such field',
 720                MDB2_ERROR_NOSUCHTABLE        => 'no such table',
 721                MDB2_ERROR_NOT_CAPABLE        => 'MDB2 backend not capable',
 722                MDB2_ERROR_NOT_FOUND          => 'not found',
 723                MDB2_ERROR_NOT_LOCKED         => 'not locked',
 724                MDB2_ERROR_SYNTAX             => 'syntax error',
 725                MDB2_ERROR_UNSUPPORTED        => 'not supported',
 726                MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
 727                MDB2_ERROR_INVALID_DSN        => 'invalid DSN',
 728                MDB2_ERROR_CONNECT_FAILED     => 'connect failed',
 729                MDB2_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
 730                MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
 731                MDB2_ERROR_NOSUCHDB           => 'no such database',
 732                MDB2_ERROR_ACCESS_VIOLATION   => 'insufficient permissions',
 733                MDB2_ERROR_LOADMODULE         => 'error while including on demand module',
 734                MDB2_ERROR_TRUNCATED          => 'truncated',
 735                MDB2_ERROR_DEADLOCK           => 'deadlock detected',
 736            );
 737        }
 738
 739        if (is_null($value)) {
 740            return $errorMessages;
 741        }
 742
 743        if (PEAR::isError($value)) {
 744            $value = $value->getCode();
 745        }
 746
 747        return isset($errorMessages[$value]) ?
 748           $errorMessages[$value] : $errorMessages[MDB2_ERROR];
 749    }
 750
 751    // }}}
 752    // {{{ function parseDSN($dsn)
 753
 754    /**
 755     * Parse a data source name.
 756     *
 757     * Additional keys can be added by appending a URI query string to the
 758     * end of the DSN.
 759     *
 760     * The format of the supplied DSN is in its fullest form:
 761     * <code>
 762     *  phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
 763     * </code>
 764     *
 765     * Most variations are allowed:
 766     * <code>
 767     *  phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
 768     *  phptype://username:password@hostspec/database_name
 769     *  phptype://username:password@hostspec
 770     *  phptype://username@hostspec
 771     *  phptype://hostspec/database
 772     *  phptype://hostspec
 773     *  phptype(dbsyntax)
 774     *  phptype
 775     * </code>
 776     *
 777     * @param   string  Data Source Name to be parsed
 778     *
 779     * @return  array   an associative array with the following keys:
 780     *  + phptype:  Database backend used in PHP (mysql, odbc etc.)
 781     *  + dbsyntax: Database used with regards to SQL syntax etc.
 782     *  + protocol: Communication protocol to use (tcp, unix etc.)
 783     *  + hostspec: Host specification (hostname[:port])
 784     *  + database: Database to use on the DBMS server
 785     *  + username: User name for login
 786     *  + password: Password for login
 787     *
 788     * @access  public
 789     * @author  Tomas V.V.Cox <cox@idecnet.com>
 790     */
 791    function parseDSN($dsn)
 792    {
 793        $parsed = $GLOBALS['_MDB2_dsninfo_default'];
 794
 795        if (is_array($dsn)) {
 796            $dsn = array_merge($parsed, $dsn);
 797            if (!$dsn['dbsyntax']) {
 798                $dsn['dbsyntax'] = $dsn['phptype'];
 799            }
 800            return $dsn;
 801        }
 802
 803        // Find phptype and dbsyntax
 804        if (($pos = strpos($dsn, '://')) !== false) {
 805            $str = substr($dsn, 0, $pos);
 806            $dsn = substr($dsn, $pos + 3);
 807        } else {
 808            $str = $dsn;
 809            $dsn = null;
 810        }
 811
 812        // Get phptype and dbsyntax
 813        // $str => phptype(dbsyntax)
 814        if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
 815            $parsed['phptype']  = $arr[1];
 816            $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
 817        } else {
 818            $parsed['phptype']  = $str;
 819            $parsed['dbsyntax'] = $str;
 820        }
 821
 822        if (!count($dsn)) {
 823            return $parsed;
 824        }
 825
 826        // Get (if found): username and password
 827        // $dsn => username:password@protocol+hostspec/database
 828        if (($at = strrpos($dsn,'@')) !== false) {
 829            $str = substr($dsn, 0, $at);
 830            $dsn = substr($dsn, $at + 1);
 831            if (($pos = strpos($str, ':')) !== false) {
 832                $parsed['username'] = rawurldecode(substr($str, 0, $pos));
 833                $parsed['password'] = rawurldecode(substr($str, $pos + 1));
 834            } else {
 835                $parsed['username'] = rawurldecode($str);
 836            }
 837        }
 838
 839        // Find protocol and hostspec
 840
 841        // $dsn => proto(proto_opts)/database
 842        if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
 843            $proto       = $match[1];
 844            $proto_opts  = $match[2] ? $match[2] : false;
 845            $dsn         = $match[3];
 846
 847        // $dsn => protocol+hostspec/database (old format)
 848        } else {
 849            if (strpos($dsn, '+') !== false) {
 850                list($proto, $dsn) = explode('+', $dsn, 2);
 851            }
 852            if (   strpos($dsn, '//') === 0
 853                && strpos($dsn, '/', 2) !== false
 854                && $parsed['phptype'] == 'oci8'
 855            ) {
 856                //oracle's "Easy Connect" syntax:
 857                //"username/password@[//]host[:port][/service_name]"
 858                //e.g. "scott/tiger@//mymachine:1521/oracle"
 859                $proto_opts = $dsn;
 860                $dsn = null;
 861            } elseif (strpos($dsn, '/') !== false) {
 862                list($proto_opts, $dsn) = explode('/', $dsn, 2);
 863            } else {
 864                $proto_opts = $dsn;
 865                $dsn = null;
 866            }
 867        }
 868
 869        // process the different protocol options
 870        $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
 871        $proto_opts = rawurldecode($proto_opts);
 872        if (strpos($proto_opts, ':') !== false) {
 873            list($proto_opts, $parsed['port']) = explode(':', $proto_opts);
 874        }
 875        if ($parsed['protocol'] == 'tcp') {
 876            $parsed['hostspec'] = $proto_opts;
 877        } elseif ($parsed['protocol'] == 'unix') {
 878            $parsed['socket'] = $proto_opts;
 879        }
 880
 881        // Get dabase if any
 882        // $dsn => database
 883        if ($dsn) {
 884            // /database
 885            if (($pos = strpos($dsn, '?')) === false) {
 886                $parsed['database'] = $dsn;
 887            // /database?param1=value1&param2=value2
 888            } else {
 889                $parsed['database'] = substr($dsn, 0, $pos);
 890                $dsn = substr($dsn, $pos + 1);
 891                if (strpos($dsn, '&') !== false) {
 892                    $opts = explode('&', $dsn);
 893                } else { // database?param1=value1
 894                    $opts = array($dsn);
 895                }
 896                foreach ($opts as $opt) {
 897                    list($key, $value) = explode('=', $opt);
 898                    if (!isset($parsed[$key])) {
 899                        // don't allow params overwrite
 900                        $parsed[$key] = rawurldecode($value);
 901                    }
 902                }
 903            }
 904        }
 905
 906        return $parsed;
 907    }
 908
 909    // }}}
 910    // {{{ function fileExists($file)
 911
 912    /**
 913     * Checks if a file exists in the include path
 914     *
 915     * @param   string  filename
 916     *
 917     * @return  bool    true success and false on error
 918     *
 919     * @access  public
 920     */
 921    function fileExists($file)
 922    {
 923        // safe_mode does notwork with is_readable()
 924        if (!@ini_get('safe_mode')) {
 925             $dirs = explode(PATH_SEPARATOR, ini_get('include_path'));
 926             foreach ($dirs as $dir) {
 927                 if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
 928                     return true;
 929                 }
 930            }
 931        } else {
 932            $fp = @fopen($file, 'r', true);
 933            if (is_resource($fp)) {
 934                @fclose($fp);
 935                return true;
 936            }
 937        }
 938        return false;
 939    }
 940    // }}}
 941}
 942
 943// }}}
 944// {{{ class MDB2_Error extends PEAR_Error
 945
 946/**
 947 * MDB2_Error implements a class for reporting portable database error
 948 * messages.
 949 *
 950 * @package     MDB2
 951 * @category    Database
 952 * @author Stig Bakken <ssb@fast.no>
 953 */
 954class MDB2_Error extends PEAR_Error
 955{
 956    // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null)
 957
 958    /**
 959     * MDB2_Error constructor.
 960     *
 961     * @param   mixed   MDB2 error code, or string with error message.
 962     * @param   int     what 'error mode' to operate in
 963     * @param   int     what error level to use for $mode & PEAR_ERROR_TRIGGER
 964     * @param   smixed   additional debug info, such as the last query
 965     */
 966    function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN,
 967              $level = E_USER_NOTICE, $debuginfo = null)
 968    {
 969        if (is_null($code)) {
 970            $code = MDB2_ERROR;
 971        }
 972        $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code,
 973            $mode, $level, $debuginfo);
 974    }
 975
 976    // }}}
 977}
 978
 979// }}}
 980// {{{ class MDB2_Driver_Common extends PEAR
 981
 982/**
 983 * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
 984 *
 985 * @package     MDB2
 986 * @category    Database
 987 * @author      Lukas Smith <smith@pooteeweet.org>
 988 */
 989class MDB2_Driver_Common extends PEAR
 990{
 991    // {{{ Variables (Properties)
 992
 993    /**
 994     * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array
 995     * @var     int
 996     * @access  public
 997     */
 998    var $db_index = 0;
 999
1000    /**
1001     * DSN used for the next query
1002     * @var     array
1003     * @access  protected
1004     */
1005    var $dsn = array();
1006
1007    /**
1008     * DSN that was used to create the current connection
1009     * @var     array
1010     * @access  protected
1011     */
1012    var $connected_dsn = array();
1013
1014    /**
1015     * connection resource
1016     * @var     mixed
1017     * @access  protected
1018     */
1019    var $connection = 0;
1020
1021    /**
1022     * if the current opened connection is a persistent connection
1023     * @var     bool
1024     * @access  protected
1025     */
1026    var $opened_persistent;
1027
1028    /**
1029     * the name of the database for the next query
1030     * @var     string
1031     * @access  protected
1032     */
1033    var $database_name = '';
1034
1035    /**
1036     * the name of the database currently selected
1037     * @var     string
1038     * @access  protected
1039     */
1040    var $connected_database_name = '';
1041
1042    /**
1043     * server version information
1044     * @var     string
1045     * @access  protected
1046     */
1047    var $connected_server_info = '';
1048
1049    /**
1050     * list of all supported features of the given driver
1051     * @var     array
1052     * @access  public
1053     */
1054    var $supported = array(
1055        'sequences' => false,
1056        'indexes' => false,
1057        'affected_rows' => false,
1058        'summary_functions' => false,
1059        'order_by_text' => false,
1060        'transactions' => false,
1061        'savepoints' => false,
1062        'current_id' => false,
1063        'limit_queries' => false,
1064        'LOBs' => false,
1065        'replace' => false,
1066        'sub_selects' => false,
1067        'auto_increment' => false,
1068        'primary_key' => false,
1069        'result_introspection' => false,
1070        'prepared_statements' => false,
1071        'identifier_quoting' => false,
1072        'pattern_escaping' => false,
1073        'new_link' => false,
1074    );
1075
1076    /**
1077     * Array of supported options that can be passed to the MDB2 instance.
1078     * 
1079     * The options can be set during object creation, using
1080     * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can 
1081     * also be set after the object is created, using MDB2::setOptions() or 
1082     * MDB2_Driver_Common::setOption().
1083     * The list of available option includes:
1084     * <ul>
1085     *  <li>$options['ssl'] -> boolean: determines if ssl should be used for connections</li>
1086     *  <li>$options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names</li>
1087     *  <li>$options['disable_query'] -> boolean: determines if queries should be executed</li>
1088     *  <li>$options['result_class'] -> string: class used for result sets</li>
1089     *  <li>$options['buffered_result_class'] -> string: class used for buffered result sets</li>
1090     *  <li>$options['result_wrap_class'] -> string: class used to wrap result sets into</li>
1091     *  <li>$options['result_buffering'] -> boolean should results be buffered or not?</li>
1092     *  <li>$options['fetch_class'] -> string: class to use when fetch mode object is used</li>
1093     *  <li>$options['persistent'] -> boolean: persistent connection?</li>
1094     *  <li>$options['debug'] -> integer: numeric debug level</li>
1095     *  <li>$options['debug_handler'] -> string: function/method that captures debug messages</li>
1096     *  <li>$options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler</li>
1097     *  <li>$options['default_text_field_length'] -> integer: default text field length to use</li>
1098     *  <li>$options['lob_buffer_length'] -> integer: LOB buffer length</li>
1099     *  <li>$options['log_line_break'] -> string: line-break format</li>
1100     *  <li>$options['idxname_format'] -> string: pattern for index name</li>
1101     *  <li>$options['seqname_format'] -> string: pattern for sequence name</li>
1102     *  <li>$options['savepoint_format'] -> string: pattern for auto generated savepoint names</li>
1103     *  <li>$options['statement_format'] -> string: pattern for prepared statement names</li>
1104     *  <li>$options['seqcol_name'] -> string: sequence column name</li>
1105     *  <li>$options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used</li>
1106     *  <li>$options['use_transactions'] -> boolean: if transaction use should be enabled</li>
1107     *  <li>$options['decimal_places'] -> integer: number of decimal places to handle</li>
1108     *  <li>$options['portability'] -> integer: portability constant</li>
1109     *  <li>$options['modules'] -> array: short to long module name mapping for __call()</li>
1110     *  <li>$options['emulate_prepared'] -> boolean: force prepared statements to be emulated</li>
1111     *  <li>$options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes</li>
1112     *  <li>$options['datatype_map_callback'] -> array: callback function/method that should be called</li>
1113     * </ul>
1114     *
1115     * @var     array
1116     * @access  public
1117     * @see     MDB2::connect()
1118     * @see     MDB2::factory()
1119     * @see     MDB2::singleton()
1120     * @see     MDB2_Driver_Common::setOption()
1121     */
1122    var $options = array(
1123        'ssl' => false,
1124        'field_case' => CASE_LOWER,
1125        'disable_query' => false,
1126        'result_class' => 'MDB2_Result_%s',
1127        'buffered_result_class' => 'MDB2_BufferedResult_%s',
1128        'result_wrap_class' => false,
1129        'result_buffering' => true,
1130        'fetch_class' => 'stdClass',
1131        'persistent' => false,
1132        'debug' => 0,
1133        'debug_handler' => 'MDB2_defaultDebugOutput',
1134        'debug_expanded_output' => false,
1135        'default_text_field_length' => 4096,
1136        'lob_buffer_length' => 8192,
1137        'log_line_break' => "\n",
1138        'idxname_format' => '%s_idx',
1139        'seqname_format' => '%s_seq',
1140        'savepoint_format' => 'MDB2_SAVEPOINT_%s',
1141        'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s',
1142        'seqcol_name' => 'sequence',
1143        'quote_identifier' => false,
1144        'use_transactions' => true,
1145        'decimal_places' => 2,
1146        'portability' => MDB2_PORTABILITY_ALL,
1147        'modules' => array(
1148            'ex' => 'Extended',
1149            'dt' => 'Datatype',
1150            'mg' => 'Manager',
1151            'rv' => 'Reverse',
1152            'na' => 'Native',
1153            'fc' => 'Function',
1154        ),
1155        'emulate_prepared' => false,
1156        'datatype_map' => array(),
1157        'datatype_map_callback' => array(),
1158        'nativetype_map_callback' => array(),
1159    );
1160
1161    /**
1162     * string array
1163     * @var     string
1164     * @access  protected
1165     */
1166    var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => false, 'escape_pattern' => false);
1167
1168    /**
1169     * identifier quoting
1170     * @var     array
1171     * @access  protected
1172     */
1173    var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');
1174
1175    /**
1176     * sql comments
1177     * @var     array
1178     * @access  protected
1179     */
1180    var $sql_comments = array(
1181        array('start' => '--', 'end' => "\n", 'escape' => false),
1182        array('start' => '/*', 'end' => '*/', 'escape' => false),
1183    );
1184
1185    /**
1186     * comparision wildcards
1187     * @var     array
1188     * @access  protected
1189     */
1190    var $wildcards = array('%', '_');
1191
1192    /**
1193     * column alias keyword
1194     * @var     string
1195     * @access  protected
1196     */
1197    var $as_keyword = ' AS ';
1198
1199    /**
1200     * warnings
1201     * @var     array
1202     * @access  protected
1203     */
1204    var $warnings = array();
1205
1206    /**
1207     * string with the debugging information
1208     * @var     string
1209     * @access  public
1210     */
1211    var $debug_output = '';
1212
1213    /**
1214     * determine if there is an open transaction
1215     * @var     bool
1216     * @access  protected
1217     */
1218    var $in_transaction = false;
1219
1220    /**
1221     * the smart transaction nesting depth
1222     * @var     int
1223     * @access  protected
1224     */
1225    var $nested_transaction_counter = null;
1226
1227    /**
1228     * the first error that occured inside a nested transaction
1229     * @var     MDB2_Error|bool
1230     * @access  protected
1231     */
1232    var $has_transaction_error = false;
1233
1234    /**
1235     * result offset used in the next query
1236     * @var     int
1237     * @access  protected
1238     */
1239    var $offset = 0;
1240
1241    /**
1242     * result limit used in the next query
1243     * @var     int
1244     * @access  protected
1245     */
1246    var $limit = 0;
1247
1248    /**
1249     * Database backend used in PHP (mysql, odbc etc.)
1250     * @var     string
1251     * @access  public
1252     */
1253    var $phptype;
1254
1255    /**
1256     * Database used with regards to SQL syntax etc.
1257     * @var     string
1258     * @access  public
1259     */
1260    var $dbsyntax;
1261
1262    /**
1263     * the last query sent to the driver
1264     * @var     string
1265     * @access  public
1266     */
1267    var $last_query;
1268
1269    /**
1270     * the default fetchmode used
1271     * @var     int
1272     * @access  protected
1273     */
1274    var $fetchmode = MDB2_FETCHMODE_ORDERED;
1275
1276    /**
1277     * array of module instances
1278     * @var     array
1279     * @access  protected
1280     */
1281    var $modules = array();
1282
1283    /**
1284     * determines of the PHP4 destructor emulation has been enabled yet
1285     * @var     array
1286     * @access  protected
1287     */
1288    var $destructor_registered = true;
1289
1290    // }}}
1291    // {{{ constructor: function __construct()
1292
1293    /**
1294     * Constructor
1295     */
1296    function __construct()
1297    {
1298        end($GLOBALS['_MDB2_databases']);
1299        $db_index = key($GLOBALS['_MDB2_databases']) + 1;
1300        $GLOBALS['_MDB2_databases'][$db_index] = &$this;
1301        $this->db_index = $db_index;
1302    }
1303
1304    // }}}
1305    // {{{ function MDB2_Driver_Common()
1306
1307    /**
1308     * PHP 4 Constructor
1309     */
1310    function MDB2_Driver_Common()
1311    {
1312        $this->destructor_registered = false;
1313        $this->__construct();
1314    }
1315
1316    // }}}
1317    // {{{ destructor: function __destruct()
1318
1319    /**
1320     *  Destructor
1321     */
1322    function __destruct()
1323    {
1324        $this->disconnect(false);
1325    }
1326
1327    // }}}
1328    // {{{ function free()
1329
1330    /**
1331     * Free the internal references so that the instance can be destroyed
1332     *
1333     * @return  bool    true on success, false if result is invalid
1334     *
1335     * @access  public
1336     */
1337    function free()
1338    {
1339        unset($GLOBALS['_MDB2_databases'][$this->db_index]);
1340        unset($this->db_index);
1341        return MDB2_OK;
1342    }
1343
1344    // }}}
1345    // {{{ function __toString()
1346
1347    /**
1348     * String conversation
1349     *
1350     * @return  string representation of the object
1351     *
1352     * @access  public
1353     */
1354    function __toString()
1355    {
1356        $info = get_class($this);
1357        $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')';
1358        if ($this->connection) {
1359            $info.= ' [connected]';
1360        }
1361        return $info;
1362    }
1363
1364    // }}}
1365    // {{{ function errorInfo($error = null)
1366
1367    /**
1368     * This method is used to collect information about an error
1369     *
1370     * @param   mixed   error code or resource
1371     *
1372     * @return  array   with MDB2 errorcode, native error code, native message
1373     *
1374     * @access  public
1375     */
1376    function errorInfo($error = null)
1377    {
1378        return array($error, null, null);
1379    }
1380
1381    // }}}
1382    // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
1383
1384    /**
1385     * This method is used to communicate an error and invoke error
1386     * callbacks etc.  Basically a wrapper for PEAR::raiseError
1387     * without the message string.
1388     *
1389     * @param   mixed   integer error code, or a PEAR error object (all other
1390     *                  parameters are ignored if this parameter is an object
1391     * @param   int     error mode, see PEAR_Error docs
1392     * @param   mixed   If error mode is PEAR_ERROR_TRIGGER, this is the
1393         *              error level (E_USER_NOTICE etc).  If error mode is
1394     *                  PEAR_ERROR_CALLBACK, this is the callback function,
1395     *                  either as a function name, or as an array of an
1396     *                  object and method name.  For other error modes this
1397     *                  parameter is ignored.
1398     * @param   string  Extra debug information.  Defaults to the last
1399     *                  query and native error code.
1400     * @param   string  name of the method that triggered the error
1401     *
1402     * @return PEAR_Error   instance of a PEAR Error object
1403     *
1404     * @access  public
1405     * @see     PEAR_Error
1406     */
1407    function &raiseError($code = null, $mode = null, $options = null, $userinfo = null, $method = null)
1408    {
1409        $userinfo = "[Error message: $userinfo]\n";
1410        // The error is yet a MDB2 error object
1411        if (PEAR::isError($code)) {
1412            // because we use the static PEAR::raiseError, our global
1413            // handler should be used if it is set
1414            if (is_null($mode) && !empty($this->_default_error_mode)) {
1415                $mode    = $this->_default_error_mode;
1416                $options = $this->_default_error_options;
1417            }
1418            if (is_null($userinfo)) {
1419                $userinfo = $code->getUserinfo();
1420            }
1421            $code = $code->getCode();
1422        } elseif ($code == MDB2_ERROR_NOT_FOUND) {
1423            // extension not loaded: don't call $this->errorInfo() or the script
1424            // will die
1425        } elseif (isset($this->connection)) {
1426            if (!empty($this->last_query)) {
1427                $userinfo.= "[Last executed query: {$this->last_query}]\n";
1428            }
1429            $native_errno = $native_msg = null;
1430            list($code, $native_errno, $native_msg) = $this->errorInfo($code);
1431            if (!is_null($native_errno) && $native_errno !== '') {
1432                $userinfo.= "[Native code: $native_errno]\n";
1433            }
1434            if (!is_null($native_msg) && $native_msg !== '') {
1435                $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n";
1436            }
1437            if (!is_null($method)) {
1438                $userinfo = $method.': '.$userinfo;
1439            }
1440        }
1441
1442        $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
1443        if ($err->getMode() !== PEAR_ERROR_RETURN
1444            && isset($this->nested_transaction_counter) && !$this->has_transaction_error) {
1445            $this->has_transaction_error =& $err;
1446        }
1447        return $err;
1448    }
1449
1450    // }}}
1451    // {{{ function resetWarnings()
1452
1453    /**
1454     * reset the warning array
1455     *
1456     * @return void
1457     *
1458     * @access  public
1459     */
1460    function resetWarnings()
1461    {
1462        $this->warnings = array();
1463    }
1464
1465    // }}}
1466    // {{{ function getWarnings()
1467
1468    /**
1469     * Get all warnings in reverse order.
1470     * This means that the last warning is the first element in the array
1471     *
1472     * @return  array   with warnings
1473     *
1474     * @access  public
1475     * @see     resetWarnings()
1476     */
1477    function getWarnings()
1478    {
1479        return array_reverse($this->warnings);
1480    }
1481
1482    // }}}
1483    // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass')
1484
1485    /**
1486     * Sets which fetch mode should be used by default on queries
1487     * on this connection
1488     *
1489     * @param   int     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC
1490     *                               or MDB2_FETCHMODE_OBJECT
1491     * @param   string  the class name of the object to be returned
1492     *                               by the fetch methods when the
1493     *                               MDB2_FETCHMODE_OBJECT mode is selected.
1494     *                               If no class is specified by default a cast
1495     *                               to object from the assoc array row will be
1496     *                               done.  There is also the possibility to use
1497     *                               and extend the 'MDB2_row' class.
1498     *
1499     * @return  mixed   MDB2_OK or MDB2 Error Object
1500     *
1501     * @access  public
1502     * @see     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT
1503     */
1504    function setFetchMode($fetchmode, $object_class = 'stdClass')
1505    {
1506        switch ($fetchmode) {
1507        case MDB2_FETCHMODE_OBJECT:
1508            $this->options['fetch_class'] = $object_class;
1509        case MDB2_FETCHMODE_ORDERED:
1510        case MDB2_FETCHMODE_ASS…

Large files files are truncated, but you can click here to view the full file