DB memo Pear MDB2 


###**Pear MDB2 install**

```php:
c:
cd \xampp\php
pear install MDB2_Driver_mysqli
```

```php:windows７にインストール
takahashi@TAKAHASHI-HP c:\users\takahashi\desktop\pleiades\xampp
# cd php

takahashi@TAKAHASHI-HP c:\Users\takahashi\Desktop\pleiades\xampp\php
# pear install MDB2_Driver_mysqli
WARNING: channel "pear.php.net" has updated its protocols, use "pear channel-upd
ate pear.php.net" to update
downloading MDB2_Driver_mysqli-1.4.1.tgz ...
Starting to download MDB2_Driver_mysqli-1.4.1.tgz (38,385 bytes)
..........done: 38,385 bytes
install ok: channel://pear.php.net/MDB2_Driver_mysqli-1.4.1
```

[Pear MDB2インストール](https://codezine.jp/article/detail/2480)

---

###**MDB2.phpの中身**

```php:
<?php
// vim: set et ts=4 sw=4 fdm=marker:
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
// | API as well as database abstraction for PHP applications.            |
// | This LICENSE is in the BSD license style.                            |
// |                                                                      |
// | Redistribution and use in source and binary forms, with or without   |
// | modification, are permitted provided that the following conditions   |
// | are met:                                                             |
// |                                                                      |
// | Redistributions of source code must retain the above copyright       |
// | notice, this list of conditions and the following disclaimer.        |
// |                                                                      |
// | Redistributions in binary form must reproduce the above copyright    |
// | notice, this list of conditions and the following disclaimer in the  |
// | documentation and/or other materials provided with the distribution. |
// |                                                                      |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission.                                                  |
// |                                                                      |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
// | POSSIBILITY OF SUCH DAMAGE.                                          |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: MDB2.php,v 1.292 2007/04/25 09:31:01 quipo Exp $
//

/**
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */

require_once 'PEAR.php';

// {{{ Error constants

/**
 * The method mapErrorCode in each MDB2_dbtype implementation maps
 * native error codes to one of these.
 *
 * If you add an error code here, make sure you also add a textual
 * version of it in MDB2::errorMessage().
 */

define('MDB2_OK',                      true);
define('MDB2_ERROR',                     -1);
define('MDB2_ERROR_SYNTAX',              -2);
define('MDB2_ERROR_CONSTRAINT',          -3);
define('MDB2_ERROR_NOT_FOUND',           -4);
define('MDB2_ERROR_ALREADY_EXISTS',      -5);
define('MDB2_ERROR_UNSUPPORTED',         -6);
define('MDB2_ERROR_MISMATCH',            -7);
define('MDB2_ERROR_INVALID',             -8);
define('MDB2_ERROR_NOT_CAPABLE',         -9);
define('MDB2_ERROR_TRUNCATED',          -10);
define('MDB2_ERROR_INVALID_NUMBER',     -11);
define('MDB2_ERROR_INVALID_DATE',       -12);
define('MDB2_ERROR_DIVZERO',            -13);
define('MDB2_ERROR_NODBSELECTED',       -14);
define('MDB2_ERROR_CANNOT_CREATE',      -15);
define('MDB2_ERROR_CANNOT_DELETE',      -16);
define('MDB2_ERROR_CANNOT_DROP',        -17);
define('MDB2_ERROR_NOSUCHTABLE',        -18);
define('MDB2_ERROR_NOSUCHFIELD',        -19);
define('MDB2_ERROR_NEED_MORE_DATA',     -20);
define('MDB2_ERROR_NOT_LOCKED',         -21);
define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22);
define('MDB2_ERROR_INVALID_DSN',        -23);
define('MDB2_ERROR_CONNECT_FAILED',     -24);
define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25);
define('MDB2_ERROR_NOSUCHDB',           -26);
define('MDB2_ERROR_ACCESS_VIOLATION',   -27);
define('MDB2_ERROR_CANNOT_REPLACE',     -28);
define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29);
define('MDB2_ERROR_DEADLOCK',           -30);
define('MDB2_ERROR_CANNOT_ALTER',       -31);
define('MDB2_ERROR_MANAGER',            -32);
define('MDB2_ERROR_MANAGER_PARSE',      -33);
define('MDB2_ERROR_LOADMODULE',         -34);
define('MDB2_ERROR_INSUFFICIENT_DATA',  -35);
// }}}
// {{{ Verbose constants
/**
 * These are just helper constants to more verbosely express parameters to prepare()
 */

define('MDB2_PREPARE_MANIP', false);
define('MDB2_PREPARE_RESULT', null);

// }}}
// {{{ Fetchmode constants

/**
 * This is a special constant that tells MDB2 the user hasn't specified
 * any particular get mode, so the default should be used.
 */
define('MDB2_FETCHMODE_DEFAULT', 0);

/**
 * Column data indexed by numbers, ordered from 0 and up
 */
define('MDB2_FETCHMODE_ORDERED', 1);

/**
 * Column data indexed by column names
 */
define('MDB2_FETCHMODE_ASSOC', 2);

/**
 * Column data as object properties
 */
define('MDB2_FETCHMODE_OBJECT', 3);

/**
 * For multi-dimensional results: normally the first level of arrays
 * is the row number, and the second level indexed by column number or name.
 * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays
 * is the column name, and the second level the row number.
 */
define('MDB2_FETCHMODE_FLIPPED', 4);

// }}}
// {{{ Portability mode constants

/**
 * Portability: turn off all portability features.
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_NONE', 0);

/**
 * Portability: convert names of tables and fields to case defined in the
 * "field_case" option when using the query*(), fetch*() and tableInfo() methods.
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_FIX_CASE', 1);

/**
 * Portability: right trim the data output by query*() and fetch*().
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_RTRIM', 2);

/**
 * Portability: force reporting the number of rows deleted.
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_DELETE_COUNT', 4);

/**
 * Portability: not needed in MDB2 (just left here for compatibility to DB)
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_NUMROWS', 8);

/**
 * Portability: makes certain error messages in certain drivers compatible
 * with those from other DBMS's.
 *
 * + mysql, mysqli:  change unique/primary key constraints
 *   MDB2_ERROR_ALREADY_EXISTS -> MDB2_ERROR_CONSTRAINT
 *
 * + odbc(access):  MS's ODBC driver reports 'no such field' as code
 *   07001, which means 'too few parameters.'  When this option is on
 *   that code gets mapped to MDB2_ERROR_NOSUCHFIELD.
 *
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_ERRORS', 16);

/**
 * Portability: convert empty values to null strings in data output by
 * query*() and fetch*().
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32);

/**
 * Portability: removes database/table qualifiers from associative indexes
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64);

/**
 * Portability: turn on all portability features.
 * @see MDB2_Driver_Common::setOption()
 */
define('MDB2_PORTABILITY_ALL', 127);

// }}}
// {{{ Globals for class instance tracking

/**
 * These are global variables that are used to track the various class instances
 */

$GLOBALS['_MDB2_databases'] = array();
$GLOBALS['_MDB2_dsninfo_default'] = array(
    'phptype'  => false,
    'dbsyntax' => false,
    'username' => false,
    'password' => false,
    'protocol' => false,
    'hostspec' => false,
    'port'     => false,
    'socket'   => false,
    'database' => false,
    'mode'     => false,
);

// }}}
// {{{ class MDB2

/**
 * The main 'MDB2' class is simply a container class with some static
 * methods for creating DB objects as well as some utility functions
 * common to all parts of DB.
 *
 * The object model of MDB2 is as follows (indentation means inheritance):
 *
 * MDB2          The main MDB2 class.  This is simply a utility class
 *              with some 'static' methods for creating MDB2 objects as
 *              well as common utility functions for other MDB2 classes.
 *
 * MDB2_Driver_Common   The base for each MDB2 implementation.  Provides default
 * |            implementations (in OO lingo virtual methods) for
 * |            the actual DB implementations as well as a bunch of
 * |            query utility functions.
 * |
 * +-MDB2_Driver_mysql  The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common.
 *              When calling MDB2::factory or MDB2::connect for MySQL
 *              connections, the object returned is an instance of this
 *              class.
 * +-MDB2_Driver_pgsql  The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common.
 *              When calling MDB2::factory or MDB2::connect for PostGreSQL
 *              connections, the object returned is an instance of this
 *              class.
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2
{
    // {{{ function setOptions(&$db, $options)

    /**
     * set option array   in an exiting database object
     *
     * @param   MDB2_Driver_Common  MDB2 object
     * @param   array   An associative array of option names and their values.
     *
     * @return mixed   MDB2_OK or a PEAR Error object
     *
     * @access  public
     */
    function setOptions(&$db, $options)
    {
        if (is_array($options)) {
            foreach ($options as $option => $value) {
                $test = $db->setOption($option, $value);
                if (PEAR::isError($test)) {
                    return $test;
                }
            }
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function classExists($classname)

    /**
     * Checks if a class exists without triggering __autoload
     *
     * @param   string  classname
     *
     * @return  bool    true success and false on error
     * @static
     * @access  public
     */
    function classExists($classname)
    {
        if (version_compare(phpversion(), "5.0", ">=")) {
            return class_exists($classname, false);
        }
        return class_exists($classname);
    }

    // }}}
    // {{{ function loadClass($class_name, $debug)

    /**
     * Loads a PEAR class.
     *
     * @param   string  classname to load
     * @param   bool    if errors should be suppressed
     *
     * @return  mixed   true success or PEAR_Error on failure
     *
     * @access  public
     */
    function loadClass($class_name, $debug)
    {
        if (!MDB2::classExists($class_name)) {
            $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
            if ($debug) {
                $include = include_once($file_name);
            } else {
                $include = @include_once($file_name);
            }
            if (!$include) {
                if (!MDB2::fileExists($file_name)) {
                    $msg = "unable to find package '$class_name' file '$file_name'";
                } else {
                    $msg = "unable to load class '$class_name' from file '$file_name'";
                }
                $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, $msg);
                return $err;
            }
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function &factory($dsn, $options = false)

    /**
     * Create a new MDB2 object for the specified database type
     *
     * IMPORTANT: In order for MDB2 to work properly it is necessary that
     * you make sure that you work with a reference of the original
     * object instead of a copy (this is a PHP4 quirk).
     *
     * For example:
     *     $db =& MDB2::factory($dsn);
     *          ^^
     * And not:
     *     $db = MDB2::factory($dsn);
     *
     * @param   mixed   'data source name', see the MDB2::parseDSN
     *                      method for a description of the dsn format.
     *                      Can also be specified as an array of the
     *                      format returned by MDB2::parseDSN.
     * @param   array   An associative array of option names and
     *                            their values.
     *
     * @return  mixed   a newly created MDB2 object, or false on error
     *
     * @access  public
     */
    function &factory($dsn, $options = false)
    {
        $dsninfo = MDB2::parseDSN($dsn);
        if (empty($dsninfo['phptype'])) {
            $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND,
                null, null, 'no RDBMS driver specified');
            return $err;
        }
        $class_name = 'MDB2_Driver_'.$dsninfo['phptype'];

        $debug = (!empty($options['debug']));
        $err = MDB2::loadClass($class_name, $debug);
        if (PEAR::isError($err)) {
            return $err;
        }

        $db =& new $class_name();
        $db->setDSN($dsninfo);
        $err = MDB2::setOptions($db, $options);
        if (PEAR::isError($err)) {
            return $err;
        }

        return $db;
    }

    // }}}
    // {{{ function &connect($dsn, $options = false)

    /**
     * Create a new MDB2 connection object and connect to the specified
     * database
     *
     * IMPORTANT: In order for MDB2 to work properly it is necessary that
     * you make sure that you work with a reference of the original
     * object instead of a copy (this is a PHP4 quirk).
     *
     * For example:
     *     $db =& MDB2::connect($dsn);
     *          ^^
     * And not:
     *     $db = MDB2::connect($dsn);
     *          ^^
     *
     * @param   mixed   'data source name', see the MDB2::parseDSN
     *                            method for a description of the dsn format.
     *                            Can also be specified as an array of the
     *                            format returned by MDB2::parseDSN.
     * @param   array   An associative array of option names and
     *                            their values.
     *
     * @return  mixed   a newly created MDB2 connection object, or a MDB2
     *                  error object on error
     *
     * @access  public
     * @see     MDB2::parseDSN
     */
    function &connect($dsn, $options = false)
    {
        $db =& MDB2::factory($dsn, $options);
        if (PEAR::isError($db)) {
            return $db;
        }

        $err = $db->connect();
        if (PEAR::isError($err)) {
            $dsn = $db->getDSN('string', 'xxx');
            $db->disconnect();
            $err->addUserInfo($dsn);
            return $err;
        }

        return $db;
    }

    // }}}
    // {{{ function &singleton($dsn = null, $options = false)

    /**
     * Returns a MDB2 connection with the requested DSN.
     * A new MDB2 connection object is only created if no object with the
     * requested DSN exists yet.
     *
     * IMPORTANT: In order for MDB2 to work properly it is necessary that
     * you make sure that you work with a reference of the original
     * object instead of a copy (this is a PHP4 quirk).
     *
     * For example:
     *     $db =& MDB2::singleton($dsn);
     *          ^^
     * And not:
     *     $db = MDB2::singleton($dsn);
     *          ^^
     *
     * @param   mixed   'data source name', see the MDB2::parseDSN
     *                            method for a description of the dsn format.
     *                            Can also be specified as an array of the
     *                            format returned by MDB2::parseDSN.
     * @param   array   An associative array of option names and
     *                            their values.
     *
     * @return  mixed   a newly created MDB2 connection object, or a MDB2
     *                  error object on error
     *
     * @access  public
     * @see     MDB2::parseDSN
     */
    function &singleton($dsn = null, $options = false)
    {
        if ($dsn) {
            $dsninfo = MDB2::parseDSN($dsn);
            $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo);
            $keys = array_keys($GLOBALS['_MDB2_databases']);
            for ($i=0, $j=count($keys); $i<$j; ++$i) {
                if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) {
                    $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array');
                    if (count(array_diff_assoc($tmp_dsn, $dsninfo)) == 0) {
                        MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options);
                        return $GLOBALS['_MDB2_databases'][$keys[$i]];
                    }
                }
            }
        } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) {
            $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])];
            return $db;
        }
        $db =& MDB2::factory($dsn, $options);
        return $db;
    }

    // }}}
    // {{{ function loadFile($file)

    /**
     * load a file (like 'Date')
     *
     * @param   string  name of the file in the MDB2 directory (without '.php')
     *
     * @return  string  name of the file that was included
     *
     * @access  public
     */
    function loadFile($file)
    {
        $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php';
        if (!MDB2::fileExists($file_name)) {
            return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'unable to find: '.$file_name);
        }
        if (!include_once($file_name)) {
            return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'unable to load driver class: '.$file_name);
        }
        return $file_name;
    }

    // }}}
    // {{{ function apiVersion()

    /**
     * Return the MDB2 API version
     *
     * @return  string  the MDB2 API version number
     *
     * @access  public
     */
    function apiVersion()
    {
        return '2.4.1';
    }

    // }}}
    // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)

    /**
     * This method is used to communicate an error and invoke error
     * callbacks etc.  Basically a wrapper for PEAR::raiseError
     * without the message string.
     *
     * @param   mixed  int error code
     *
     * @param   int    error mode, see PEAR_Error docs
     *
     * @param   mixed  If error mode is PEAR_ERROR_TRIGGER, this is the
     *                 error level (E_USER_NOTICE etc).  If error mode is
     *                 PEAR_ERROR_CALLBACK, this is the callback function,
     *                 either as a function name, or as an array of an
     *                 object and method name.  For other error modes this
     *                 parameter is ignored.
     *
     * @param   string Extra debug information.  Defaults to the last
     *                 query and native error code.
     *
     * @return PEAR_Error instance of a PEAR Error object
     *
     * @access  private
     * @see     PEAR_Error
     */
    function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
    {
        $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
        return $err;
    }

    // }}}
    // {{{ function isError($data, $code = null)

    /**
     * Tell whether a value is a MDB2 error.
     *
     * @param   mixed   the value to test
     * @param   int     if is an error object, return true
     *                        only if $code is a string and
     *                        $db->getMessage() == $code or
     *                        $code is an integer and $db->getCode() == $code
     *
     * @return  bool    true if parameter is an error
     *
     * @access  public
     */
    function isError($data, $code = null)
    {
        if (is_a($data, 'MDB2_Error')) {
            if (is_null($code)) {
                return true;
            } elseif (is_string($code)) {
                return $data->getMessage() === $code;
            } else {
                $code = (array)$code;
                return in_array($data->getCode(), $code);
            }
        }
        return false;
    }

    // }}}
    // {{{ function isConnection($value)

    /**
     * Tell whether a value is a MDB2 connection
     *
     * @param   mixed   value to test
     *
     * @return  bool    whether $value is a MDB2 connection
     *
     * @access  public
     */
    function isConnection($value)
    {
        return is_a($value, 'MDB2_Driver_Common');
    }

    // }}}
    // {{{ function isResult($value)

    /**
     * Tell whether a value is a MDB2 result
     *
     * @param   mixed   value to test
     *
     * @return  bool    whether $value is a MDB2 result
     *
     * @access  public
     */
    function isResult($value)
    {
        return is_a($value, 'MDB2_Result');
    }

    // }}}
    // {{{ function isResultCommon($value)

    /**
     * Tell whether a value is a MDB2 result implementing the common interface
     *
     * @param   mixed   value to test
     *
     * @return  bool    whether $value is a MDB2 result implementing the common interface
     *
     * @access  public
     */
    function isResultCommon($value)
    {
        return is_a($value, 'MDB2_Result_Common');
    }

    // }}}
    // {{{ function isStatement($value)

    /**
     * Tell whether a value is a MDB2 statement interface
     *
     * @param   mixed   value to test
     *
     * @return  bool    whether $value is a MDB2 statement interface
     *
     * @access  public
     */
    function isStatement($value)
    {
        return is_a($value, 'MDB2_Statement');
    }

    // }}}
    // {{{ function errorMessage($value = null)

    /**
     * Return a textual error message for a MDB2 error code
     *
     * @param   int|array   integer error code,
                                null to get the current error code-message map,
                                or an array with a new error code-message map
     *
     * @return  string  error message, or false if the error code was
     *                  not recognized
     *
     * @access  public
     */
    function errorMessage($value = null)
    {
        static $errorMessages;

        if (is_array($value)) {
            $errorMessages = $value;
            return MDB2_OK;
        }

        if (!isset($errorMessages)) {
            $errorMessages = array(
                MDB2_OK                       => 'no error',
                MDB2_ERROR                    => 'unknown error',
                MDB2_ERROR_ALREADY_EXISTS     => 'already exists',
                MDB2_ERROR_CANNOT_CREATE      => 'can not create',
                MDB2_ERROR_CANNOT_ALTER       => 'can not alter',
                MDB2_ERROR_CANNOT_REPLACE     => 'can not replace',
                MDB2_ERROR_CANNOT_DELETE      => 'can not delete',
                MDB2_ERROR_CANNOT_DROP        => 'can not drop',
                MDB2_ERROR_CONSTRAINT         => 'constraint violation',
                MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
                MDB2_ERROR_DIVZERO            => 'division by zero',
                MDB2_ERROR_INVALID            => 'invalid',
                MDB2_ERROR_INVALID_DATE       => 'invalid date or time',
                MDB2_ERROR_INVALID_NUMBER     => 'invalid number',
                MDB2_ERROR_MISMATCH           => 'mismatch',
                MDB2_ERROR_NODBSELECTED       => 'no database selected',
                MDB2_ERROR_NOSUCHFIELD        => 'no such field',
                MDB2_ERROR_NOSUCHTABLE        => 'no such table',
                MDB2_ERROR_NOT_CAPABLE        => 'MDB2 backend not capable',
                MDB2_ERROR_NOT_FOUND          => 'not found',
                MDB2_ERROR_NOT_LOCKED         => 'not locked',
                MDB2_ERROR_SYNTAX             => 'syntax error',
                MDB2_ERROR_UNSUPPORTED        => 'not supported',
                MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
                MDB2_ERROR_INVALID_DSN        => 'invalid DSN',
                MDB2_ERROR_CONNECT_FAILED     => 'connect failed',
                MDB2_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
                MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
                MDB2_ERROR_NOSUCHDB           => 'no such database',
                MDB2_ERROR_ACCESS_VIOLATION   => 'insufficient permissions',
                MDB2_ERROR_LOADMODULE         => 'error while including on demand module',
                MDB2_ERROR_TRUNCATED          => 'truncated',
                MDB2_ERROR_DEADLOCK           => 'deadlock detected',
            );
        }

        if (is_null($value)) {
            return $errorMessages;
        }

        if (PEAR::isError($value)) {
            $value = $value->getCode();
        }

        return isset($errorMessages[$value]) ?
           $errorMessages[$value] : $errorMessages[MDB2_ERROR];
    }

    // }}}
    // {{{ function parseDSN($dsn)

    /**
     * Parse a data source name.
     *
     * Additional keys can be added by appending a URI query string to the
     * end of the DSN.
     *
     * The format of the supplied DSN is in its fullest form:
     * <code>
     *  phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
     * </code>
     *
     * Most variations are allowed:
     * <code>
     *  phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
     *  phptype://username:password@hostspec/database_name
     *  phptype://username:password@hostspec
     *  phptype://username@hostspec
     *  phptype://hostspec/database
     *  phptype://hostspec
     *  phptype(dbsyntax)
     *  phptype
     * </code>
     *
     * @param   string  Data Source Name to be parsed
     *
     * @return  array   an associative array with the following keys:
     *  + phptype:  Database backend used in PHP (mysql, odbc etc.)
     *  + dbsyntax: Database used with regards to SQL syntax etc.
     *  + protocol: Communication protocol to use (tcp, unix etc.)
     *  + hostspec: Host specification (hostname[:port])
     *  + database: Database to use on the DBMS server
     *  + username: User name for login
     *  + password: Password for login
     *
     * @access  public
     * @author  Tomas V.V.Cox <cox@idecnet.com>
     */
    function parseDSN($dsn)
    {
        $parsed = $GLOBALS['_MDB2_dsninfo_default'];

        if (is_array($dsn)) {
            $dsn = array_merge($parsed, $dsn);
            if (!$dsn['dbsyntax']) {
                $dsn['dbsyntax'] = $dsn['phptype'];
            }
            return $dsn;
        }

        // Find phptype and dbsyntax
        if (($pos = strpos($dsn, '://')) !== false) {
            $str = substr($dsn, 0, $pos);
            $dsn = substr($dsn, $pos + 3);
        } else {
            $str = $dsn;
            $dsn = null;
        }

        // Get phptype and dbsyntax
        // $str => phptype(dbsyntax)
        if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
            $parsed['phptype']  = $arr[1];
            $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
        } else {
            $parsed['phptype']  = $str;
            $parsed['dbsyntax'] = $str;
        }

        if (!count($dsn)) {
            return $parsed;
        }

        // Get (if found): username and password
        // $dsn => username:password@protocol+hostspec/database
        if (($at = strrpos($dsn,'@')) !== false) {
            $str = substr($dsn, 0, $at);
            $dsn = substr($dsn, $at + 1);
            if (($pos = strpos($str, ':')) !== false) {
                $parsed['username'] = rawurldecode(substr($str, 0, $pos));
                $parsed['password'] = rawurldecode(substr($str, $pos + 1));
            } else {
                $parsed['username'] = rawurldecode($str);
            }
        }

        // Find protocol and hostspec

        // $dsn => proto(proto_opts)/database
        if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
            $proto       = $match[1];
            $proto_opts  = $match[2] ? $match[2] : false;
            $dsn         = $match[3];

        // $dsn => protocol+hostspec/database (old format)
        } else {
            if (strpos($dsn, '+') !== false) {
                list($proto, $dsn) = explode('+', $dsn, 2);
            }
            if (   strpos($dsn, '//') === 0
                && strpos($dsn, '/', 2) !== false
                && $parsed['phptype'] == 'oci8'
            ) {
                //oracle's "Easy Connect" syntax:
                //"username/password@[//]host[:port][/service_name]"
                //e.g. "scott/tiger@//mymachine:1521/oracle"
                $proto_opts = $dsn;
                $dsn = null;
            } elseif (strpos($dsn, '/') !== false) {
                list($proto_opts, $dsn) = explode('/', $dsn, 2);
            } else {
                $proto_opts = $dsn;
                $dsn = null;
            }
        }

        // process the different protocol options
        $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
        $proto_opts = rawurldecode($proto_opts);
        if (strpos($proto_opts, ':') !== false) {
            list($proto_opts, $parsed['port']) = explode(':', $proto_opts);
        }
        if ($parsed['protocol'] == 'tcp') {
            $parsed['hostspec'] = $proto_opts;
        } elseif ($parsed['protocol'] == 'unix') {
            $parsed['socket'] = $proto_opts;
        }

        // Get dabase if any
        // $dsn => database
        if ($dsn) {
            // /database
            if (($pos = strpos($dsn, '?')) === false) {
                $parsed['database'] = $dsn;
            // /database?param1=value1&param2=value2
            } else {
                $parsed['database'] = substr($dsn, 0, $pos);
                $dsn = substr($dsn, $pos + 1);
                if (strpos($dsn, '&') !== false) {
                    $opts = explode('&', $dsn);
                } else { // database?param1=value1
                    $opts = array($dsn);
                }
                foreach ($opts as $opt) {
                    list($key, $value) = explode('=', $opt);
                    if (!isset($parsed[$key])) {
                        // don't allow params overwrite
                        $parsed[$key] = rawurldecode($value);
                    }
                }
            }
        }

        return $parsed;
    }

    // }}}
    // {{{ function fileExists($file)

    /**
     * Checks if a file exists in the include path
     *
     * @param   string  filename
     *
     * @return  bool    true success and false on error
     *
     * @access  public
     */
    function fileExists($file)
    {
        // safe_mode does notwork with is_readable()
        if (!@ini_get('safe_mode')) {
             $dirs = explode(PATH_SEPARATOR, ini_get('include_path'));
             foreach ($dirs as $dir) {
                 if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
                     return true;
                 }
            }
        } else {
            $fp = @fopen($file, 'r', true);
            if (is_resource($fp)) {
                @fclose($fp);
                return true;
            }
        }
        return false;
    }
    // }}}
}

// }}}
// {{{ class MDB2_Error extends PEAR_Error

/**
 * MDB2_Error implements a class for reporting portable database error
 * messages.
 *
 * @package     MDB2
 * @category    Database
 * @author Stig Bakken <ssb@fast.no>
 */
class MDB2_Error extends PEAR_Error
{
    // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null)

    /**
     * MDB2_Error constructor.
     *
     * @param   mixed   MDB2 error code, or string with error message.
     * @param   int     what 'error mode' to operate in
     * @param   int     what error level to use for $mode & PEAR_ERROR_TRIGGER
     * @param   smixed   additional debug info, such as the last query
     */
    function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN,
              $level = E_USER_NOTICE, $debuginfo = null)
    {
        if (is_null($code)) {
            $code = MDB2_ERROR;
        }
        $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code,
            $mode, $level, $debuginfo);
    }

    // }}}
}

// }}}
// {{{ class MDB2_Driver_Common extends PEAR

/**
 * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Driver_Common extends PEAR
{
    // {{{ Variables (Properties)

    /**
     * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array
     * @var     int
     * @access  public
     */
    var $db_index = 0;

    /**
     * DSN used for the next query
     * @var     array
     * @access  protected
     */
    var $dsn = array();

    /**
     * DSN that was used to create the current connection
     * @var     array
     * @access  protected
     */
    var $connected_dsn = array();

    /**
     * connection resource
     * @var     mixed
     * @access  protected
     */
    var $connection = 0;

    /**
     * if the current opened connection is a persistent connection
     * @var     bool
     * @access  protected
     */
    var $opened_persistent;

    /**
     * the name of the database for the next query
     * @var     string
     * @access  protected
     */
    var $database_name = '';

    /**
     * the name of the database currently selected
     * @var     string
     * @access  protected
     */
    var $connected_database_name = '';

    /**
     * server version information
     * @var     string
     * @access  protected
     */
    var $connected_server_info = '';

    /**
     * list of all supported features of the given driver
     * @var     array
     * @access  public
     */
    var $supported = array(
        'sequences' => false,
        'indexes' => false,
        'affected_rows' => false,
        'summary_functions' => false,
        'order_by_text' => false,
        'transactions' => false,
        'savepoints' => false,
        'current_id' => false,
        'limit_queries' => false,
        'LOBs' => false,
        'replace' => false,
        'sub_selects' => false,
        'auto_increment' => false,
        'primary_key' => false,
        'result_introspection' => false,
        'prepared_statements' => false,
        'identifier_quoting' => false,
        'pattern_escaping' => false,
        'new_link' => false,
    );

    /**
     * Array of supported options that can be passed to the MDB2 instance.
     * 
     * The options can be set during object creation, using
     * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can 
     * also be set after the object is created, using MDB2::setOptions() or 
     * MDB2_Driver_Common::setOption().
     * The list of available option includes:
     * <ul>
     *  <li>$options['ssl'] -> boolean: determines if ssl should be used for connections</li>
     *  <li>$options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names</li>
     *  <li>$options['disable_query'] -> boolean: determines if queries should be executed</li>
     *  <li>$options['result_class'] -> string: class used for result sets</li>
     *  <li>$options['buffered_result_class'] -> string: class used for buffered result sets</li>
     *  <li>$options['result_wrap_class'] -> string: class used to wrap result sets into</li>
     *  <li>$options['result_buffering'] -> boolean should results be buffered or not?</li>
     *  <li>$options['fetch_class'] -> string: class to use when fetch mode object is used</li>
     *  <li>$options['persistent'] -> boolean: persistent connection?</li>
     *  <li>$options['debug'] -> integer: numeric debug level</li>
     *  <li>$options['debug_handler'] -> string: function/method that captures debug messages</li>
     *  <li>$options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler</li>
     *  <li>$options['default_text_field_length'] -> integer: default text field length to use</li>
     *  <li>$options['lob_buffer_length'] -> integer: LOB buffer length</li>
     *  <li>$options['log_line_break'] -> string: line-break format</li>
     *  <li>$options['idxname_format'] -> string: pattern for index name</li>
     *  <li>$options['seqname_format'] -> string: pattern for sequence name</li>
     *  <li>$options['savepoint_format'] -> string: pattern for auto generated savepoint names</li>
     *  <li>$options['statement_format'] -> string: pattern for prepared statement names</li>
     *  <li>$options['seqcol_name'] -> string: sequence column name</li>
     *  <li>$options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used</li>
     *  <li>$options['use_transactions'] -> boolean: if transaction use should be enabled</li>
     *  <li>$options['decimal_places'] -> integer: number of decimal places to handle</li>
     *  <li>$options['portability'] -> integer: portability constant</li>
     *  <li>$options['modules'] -> array: short to long module name mapping for __call()</li>
     *  <li>$options['emulate_prepared'] -> boolean: force prepared statements to be emulated</li>
     *  <li>$options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes</li>
     *  <li>$options['datatype_map_callback'] -> array: callback function/method that should be called</li>
     * </ul>
     *
     * @var     array
     * @access  public
     * @see     MDB2::connect()
     * @see     MDB2::factory()
     * @see     MDB2::singleton()
     * @see     MDB2_Driver_Common::setOption()
     */
    var $options = array(
        'ssl' => false,
        'field_case' => CASE_LOWER,
        'disable_query' => false,
        'result_class' => 'MDB2_Result_%s',
        'buffered_result_class' => 'MDB2_BufferedResult_%s',
        'result_wrap_class' => false,
        'result_buffering' => true,
        'fetch_class' => 'stdClass',
        'persistent' => false,
        'debug' => 0,
        'debug_handler' => 'MDB2_defaultDebugOutput',
        'debug_expanded_output' => false,
        'default_text_field_length' => 4096,
        'lob_buffer_length' => 8192,
        'log_line_break' => "\n",
        'idxname_format' => '%s_idx',
        'seqname_format' => '%s_seq',
        'savepoint_format' => 'MDB2_SAVEPOINT_%s',
        'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s',
        'seqcol_name' => 'sequence',
        'quote_identifier' => false,
        'use_transactions' => true,
        'decimal_places' => 2,
        'portability' => MDB2_PORTABILITY_ALL,
        'modules' => array(
            'ex' => 'Extended',
            'dt' => 'Datatype',
            'mg' => 'Manager',
            'rv' => 'Reverse',
            'na' => 'Native',
            'fc' => 'Function',
        ),
        'emulate_prepared' => false,
        'datatype_map' => array(),
        'datatype_map_callback' => array(),
        'nativetype_map_callback' => array(),
    );

    /**
     * string array
     * @var     string
     * @access  protected
     */
    var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => false, 'escape_pattern' => false);

    /**
     * identifier quoting
     * @var     array
     * @access  protected
     */
    var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');

    /**
     * sql comments
     * @var     array
     * @access  protected
     */
    var $sql_comments = array(
        array('start' => '--', 'end' => "\n", 'escape' => false),
        array('start' => '/*', 'end' => '*/', 'escape' => false),
    );

    /**
     * comparision wildcards
     * @var     array
     * @access  protected
     */
    var $wildcards = array('%', '_');

    /**
     * column alias keyword
     * @var     string
     * @access  protected
     */
    var $as_keyword = ' AS ';

    /**
     * warnings
     * @var     array
     * @access  protected
     */
    var $warnings = array();

    /**
     * string with the debugging information
     * @var     string
     * @access  public
     */
    var $debug_output = '';

    /**
     * determine if there is an open transaction
     * @var     bool
     * @access  protected
     */
    var $in_transaction = false;

    /**
     * the smart transaction nesting depth
     * @var     int
     * @access  protected
     */
    var $nested_transaction_counter = null;

    /**
     * the first error that occured inside a nested transaction
     * @var     MDB2_Error|bool
     * @access  protected
     */
    var $has_transaction_error = false;

    /**
     * result offset used in the next query
     * @var     int
     * @access  protected
     */
    var $offset = 0;

    /**
     * result limit used in the next query
     * @var     int
     * @access  protected
     */
    var $limit = 0;

    /**
     * Database backend used in PHP (mysql, odbc etc.)
     * @var     string
     * @access  public
     */
    var $phptype;

    /**
     * Database used with regards to SQL syntax etc.
     * @var     string
     * @access  public
     */
    var $dbsyntax;

    /**
     * the last query sent to the driver
     * @var     string
     * @access  public
     */
    var $last_query;

    /**
     * the default fetchmode used
     * @var     int
     * @access  protected
     */
    var $fetchmode = MDB2_FETCHMODE_ORDERED;

    /**
     * array of module instances
     * @var     array
     * @access  protected
     */
    var $modules = array();

    /**
     * determines of the PHP4 destructor emulation has been enabled yet
     * @var     array
     * @access  protected
     */
    var $destructor_registered = true;

    // }}}
    // {{{ constructor: function __construct()

    /**
     * Constructor
     */
    function __construct()
    {
        end($GLOBALS['_MDB2_databases']);
        $db_index = key($GLOBALS['_MDB2_databases']) + 1;
        $GLOBALS['_MDB2_databases'][$db_index] = &$this;
        $this->db_index = $db_index;
    }

    // }}}
    // {{{ function MDB2_Driver_Common()

    /**
     * PHP 4 Constructor
     */
    function MDB2_Driver_Common()
    {
        $this->destructor_registered = false;
        $this->__construct();
    }

    // }}}
    // {{{ destructor: function __destruct()

    /**
     *  Destructor
     */
    function __destruct()
    {
        $this->disconnect(false);
    }

    // }}}
    // {{{ function free()

    /**
     * Free the internal references so that the instance can be destroyed
     *
     * @return  bool    true on success, false if result is invalid
     *
     * @access  public
     */
    function free()
    {
        unset($GLOBALS['_MDB2_databases'][$this->db_index]);
        unset($this->db_index);
        return MDB2_OK;
    }

    // }}}
    // {{{ function __toString()

    /**
     * String conversation
     *
     * @return  string representation of the object
     *
     * @access  public
     */
    function __toString()
    {
        $info = get_class($this);
        $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')';
        if ($this->connection) {
            $info.= ' [connected]';
        }
        return $info;
    }

    // }}}
    // {{{ function errorInfo($error = null)

    /**
     * This method is used to collect information about an error
     *
     * @param   mixed   error code or resource
     *
     * @return  array   with MDB2 errorcode, native error code, native message
     *
     * @access  public
     */
    function errorInfo($error = null)
    {
        return array($error, null, null);
    }

    // }}}
    // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)

    /**
     * This method is used to communicate an error and invoke error
     * callbacks etc.  Basically a wrapper for PEAR::raiseError
     * without the message string.
     *
     * @param   mixed   integer error code, or a PEAR error object (all other
     *                  parameters are ignored if this parameter is an object
     * @param   int     error mode, see PEAR_Error docs
     * @param   mixed   If error mode is PEAR_ERROR_TRIGGER, this is the
         *              error level (E_USER_NOTICE etc).  If error mode is
     *                  PEAR_ERROR_CALLBACK, this is the callback function,
     *                  either as a function name, or as an array of an
     *                  object and method name.  For other error modes this
     *                  parameter is ignored.
     * @param   string  Extra debug information.  Defaults to the last
     *                  query and native error code.
     * @param   string  name of the method that triggered the error
     *
     * @return PEAR_Error   instance of a PEAR Error object
     *
     * @access  public
     * @see     PEAR_Error
     */
    function &raiseError($code = null, $mode = null, $options = null, $userinfo = null, $method = null)
    {
        $userinfo = "[Error message: $userinfo]\n";
        // The error is yet a MDB2 error object
        if (PEAR::isError($code)) {
            // because we use the static PEAR::raiseError, our global
            // handler should be used if it is set
            if (is_null($mode) && !empty($this->_default_error_mode)) {
                $mode    = $this->_default_error_mode;
                $options = $this->_default_error_options;
            }
            if (is_null($userinfo)) {
                $userinfo = $code->getUserinfo();
            }
            $code = $code->getCode();
        } elseif ($code == MDB2_ERROR_NOT_FOUND) {
            // extension not loaded: don't call $this->errorInfo() or the script
            // will die
        } elseif (isset($this->connection)) {
            if (!empty($this->last_query)) {
                $userinfo.= "[Last executed query: {$this->last_query}]\n";
            }
            $native_errno = $native_msg = null;
            list($code, $native_errno, $native_msg) = $this->errorInfo($code);
            if (!is_null($native_errno) && $native_errno !== '') {
                $userinfo.= "[Native code: $native_errno]\n";
            }
            if (!is_null($native_msg) && $native_msg !== '') {
                $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n";
            }
            if (!is_null($method)) {
                $userinfo = $method.': '.$userinfo;
            }
        }

        $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true);
        if ($err->getMode() !== PEAR_ERROR_RETURN
            && isset($this->nested_transaction_counter) && !$this->has_transaction_error) {
            $this->has_transaction_error =& $err;
        }
        return $err;
    }

    // }}}
    // {{{ function resetWarnings()

    /**
     * reset the warning array
     *
     * @return void
     *
     * @access  public
     */
    function resetWarnings()
    {
        $this->warnings = array();
    }

    // }}}
    // {{{ function getWarnings()

    /**
     * Get all warnings in reverse order.
     * This means that the last warning is the first element in the array
     *
     * @return  array   with warnings
     *
     * @access  public
     * @see     resetWarnings()
     */
    function getWarnings()
    {
        return array_reverse($this->warnings);
    }

    // }}}
    // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass')

    /**
     * Sets which fetch mode should be used by default on queries
     * on this connection
     *
     * @param   int     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC
     *                               or MDB2_FETCHMODE_OBJECT
     * @param   string  the class name of the object to be returned
     *                               by the fetch methods when the
     *                               MDB2_FETCHMODE_OBJECT mode is selected.
     *                               If no class is specified by default a cast
     *                               to object from the assoc array row will be
     *                               done.  There is also the possibility to use
     *                               and extend the 'MDB2_row' class.
     *
     * @return  mixed   MDB2_OK or MDB2 Error Object
     *
     * @access  public
     * @see     MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT
     */
    function setFetchMode($fetchmode, $object_class = 'stdClass')
    {
        switch ($fetchmode) {
        case MDB2_FETCHMODE_OBJECT:
            $this->options['fetch_class'] = $object_class;
        case MDB2_FETCHMODE_ORDERED:
        case MDB2_FETCHMODE_ASSOC:
            $this->fetchmode = $fetchmode;
            break;
        default:
            return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'invalid fetchmode mode', __FUNCTION__);
        }

        return MDB2_OK;
    }

    // }}}
    // {{{ function setOption($option, $value)

    /**
     * set the option for the db class
     *
     * @param   string  option name
     * @param   mixed   value for the option
     *
     * @return  mixed   MDB2_OK or MDB2 Error Object
     *
     * @access  public
     */
    function setOption($option, $value)
    {
        if (array_key_exists($option, $this->options)) {
            $this->options[$option] = $value;
            return MDB2_OK;
        }
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            "unknown option $option", __FUNCTION__);
    }

    // }}}
    // {{{ function getOption($option)

    /**
     * Returns the value of an option
     *
     * @param   string  option name
     *
     * @return  mixed   the option value or error object
     *
     * @access  public
     */
    function getOption($option)
    {
        if (array_key_exists($option, $this->options)) {
            return $this->options[$option];
        }
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            "unknown option $option", __FUNCTION__);
    }

    // }}}
    // {{{ function debug($message, $scope = '', $is_manip = null)

    /**
     * set a debug message
     *
     * @param   string  message that should be appended to the debug variable
     * @param   string  usually the method name that triggered the debug call:
     *                  for example 'query', 'prepare', 'execute', 'parameters',
     *                  'beginTransaction', 'commit', 'rollback'
     * @param   array   contains context information about the debug() call
     *                  common keys are: is_manip, time, result etc.
     *
     * @return void
     *
     * @access  public
     */
    function debug($message, $scope = '', $context = array())
    {
        if ($this->options['debug'] && $this->options['debug_handler']) {
            if (!$this->options['debug_expanded_output']) {
                if (!empty($context['when']) && $context['when'] !== 'pre') {
                    return null;
                }
                $context = empty($context['is_manip']) ? false : $context['is_manip'];
            }
            return call_user_func_array($this->options['debug_handler'], array(&$this, $scope, $message, $context));
        }
        return null;
    }

    // }}}
    // {{{ function getDebugOutput()

    /**
     * output debug info
     *
     * @return  string  content of the debug_output class variable
     *
     * @access  public
     */
    function getDebugOutput()
    {
        return $this->debug_output;
    }

    // }}}
    // {{{ function escape($text)

    /**
     * Quotes a string so it can be safely used in a query. It will quote
     * the text so it can safely be used within a query.
     *
     * @param   string  the input string to quote
     * @param   bool    escape wildcards
     *
     * @return  string  quoted string
     *
     * @access  public
     */
    function escape($text, $escape_wildcards = false)
    {
        if ($escape_wildcards) {
            $text = $this->escapePattern($text);
        }

        $text = str_replace($this->string_quoting['end'], $this->string_quoting['escape'] . $this->string_quoting['end'], $text);
        return $text;
    }

    // }}}
    // {{{ function escapePattern($text)

    /**
     * Quotes pattern (% and _) characters in a string)
     *
     * EXPERIMENTAL
     *
     * WARNING: this function is experimental and may change signature at
     * any time until labelled as non-experimental
     *
     * @param   string  the input string to quote
     *
     * @return  string  quoted string
     *
     * @access  public
     */
    function escapePattern($text)
    {
        if ($this->string_quoting['escape_pattern']) {
            $text = str_replace($this->string_quoting['escape_pattern'], $this->string_quoting['escape_pattern'] . $this->string_quoting['escape_pattern'], $text);
            foreach ($this->wildcards as $wildcard) {
                $text = str_replace($wildcard, $this->string_quoting['escape_pattern'] . $wildcard, $text);
            }
        }
        return $text;
    }

    // }}}
    // {{{ function quoteIdentifier($str, $check_option = false)

    /**
     * Quote a string so it can be safely used as a table or column name
     *
     * Delimiting style depends on which database driver is being used.
     *
     * NOTE: just because you CAN use delimited identifiers doesn't mean
     * you SHOULD use them.  In general, they end up causing way more
     * problems than they solve.
     *
     * Portability is broken by using the following characters inside
     * delimited identifiers:
     *   + backtick (<kbd>`</kbd>) -- due to MySQL
     *   + double quote (<kbd>"</kbd>) -- due to Oracle
     *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
     *
     * Delimited identifiers are known to generally work correctly under
     * the following drivers:
     *   + mssql
     *   + mysql
     *   + mysqli
     *   + oci8
     *   + pgsql
     *   + sqlite
     *
     * InterBase doesn't seem to be able to use delimited identifiers
     * via PHP 4.  They work fine under PHP 5.
     *
     * @param   string  identifier name to be quoted
     * @param   bool    check the 'quote_identifier' option
     *
     * @return  string  quoted identifier string
     *
     * @access  public
     */
    function quoteIdentifier($str, $check_option = false)
    {
        if ($check_option && !$this->options['quote_identifier']) {
            return $str;
        }
        $str = str_replace($this->identifier_quoting['end'], $this->identifier_quoting['escape'] . $this->identifier_quoting['end'], $str);
        return $this->identifier_quoting['start'] . $str . $this->identifier_quoting['end'];
    }

    // }}}
    // {{{ function getAsKeyword()

    /**
     * Gets the string to alias column
     *
     * @return string to use when aliasing a column
     */
    function getAsKeyword()
    {
        return $this->as_keyword;
    }

    // }}}
    // {{{ function getConnection()

    /**
     * Returns a native connection
     *
     * @return  mixed   a valid MDB2 connection object,
     *                  or a MDB2 error object on error
     *
     * @access  public
     */
    function getConnection()
    {
        $result = $this->connect();
        if (PEAR::isError($result)) {
            return $result;
        }
        return $this->connection;
    }

     // }}}
    // {{{ function _fixResultArrayValues(&$row, $mode)

    /**
     * Do all necessary conversions on result arrays to fix DBMS quirks
     *
     * @param   array   the array to be fixed (passed by reference)
     * @param   array   bit-wise addition of the required portability modes
     *
     * @return  void
     *
     * @access  protected
     */
    function _fixResultArrayValues(&$row, $mode)
    {
        switch ($mode) {
        case MDB2_PORTABILITY_EMPTY_TO_NULL:
            foreach ($row as $key => $value) {
                if ($value === '') {
                    $row[$key] = null;
                }
            }
            break;
        case MDB2_PORTABILITY_RTRIM:
            foreach ($row as $key => $value) {
                if (is_string($value)) {
                    $row[$key] = rtrim($value);
                }
            }
            break;
        case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES:
            $tmp_row = array();
            foreach ($row as $key => $value) {
                $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
            }
            $row = $tmp_row;
            break;
        case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL):
            foreach ($row as $key => $value) {
                if ($value === '') {
                    $row[$key] = null;
                } elseif (is_string($value)) {
                    $row[$key] = rtrim($value);
                }
            }
            break;
        case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
            $tmp_row = array();
            foreach ($row as $key => $value) {
                if (is_string($value)) {
                    $value = rtrim($value);
                }
                $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
            }
            $row = $tmp_row;
            break;
        case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
            $tmp_row = array();
            foreach ($row as $key => $value) {
                if ($value === '') {
                    $value = null;
                }
                $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
            }
            $row = $tmp_row;
            break;
        case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES):
            $tmp_row = array();
            foreach ($row as $key => $value) {
                if ($value === '') {
                    $value = null;
                } elseif (is_string($value)) {
                    $value = rtrim($value);
                }
                $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value;
            }
            $row = $tmp_row;
            break;
        }
    }

    // }}}
    // {{{ function &loadModule($module, $property = null, $phptype_specific = null)

    /**
     * loads a module
     *
     * @param   string  name of the module that should be loaded
     *                  (only used for error messages)
     * @param   string  name of the property into which the class will be loaded
     * @param   bool    if the class to load for the module is specific to the
     *                  phptype
     *
     * @return  object  on success a reference to the given module is returned
     *                  and on failure a PEAR error
     *
     * @access  public
     */
    function &loadModule($module, $property = null, $phptype_specific = null)
    {
        if (!$property) {
            $property = strtolower($module);
        }

        if (!isset($this->{$property})) {
            $version = $phptype_specific;
            if ($phptype_specific !== false) {
                $version = true;
                $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype;
                $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
            }
            if ($phptype_specific === false
                || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name))
            ) {
                $version = false;
                $class_name = 'MDB2_'.$module;
                $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php';
            }

            $err = MDB2::loadClass($class_name, $this->getOption('debug'));
            if (PEAR::isError($err)) {
                return $err;
            }

            // load modul in a specific version
            if ($version) {
                if (method_exists($class_name, 'getClassName')) {
                    $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index);
                    if ($class_name != $class_name_new) {
                        $class_name = $class_name_new;
                        $err = MDB2::loadClass($class_name, $this->getOption('debug'));
                        if (PEAR::isError($err)) {
                            return $err;
                        }
                    }
                }
            }

            if (!MDB2::classExists($class_name)) {
                $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null,
                    "unable to load module '$module' into property '$property'", __FUNCTION__);
                return $err;
            }
            $this->{$property} =& new $class_name($this->db_index);
            $this->modules[$module] =& $this->{$property};
            if ($version) {
                // this will be used in the connect method to determine if the module
                // needs to be loaded with a different version if the server
                // version changed in between connects
                $this->loaded_version_modules[] = $property;
            }
        }

        return $this->{$property};
    }

    // }}}
    // {{{ function __call($method, $params)

    /**
     * Calls a module method using the __call magic method
     *
     * @param   string  Method name.
     * @param   array   Arguments.
     *
     * @return  mixed   Returned value.
     */
    function __call($method, $params)
    {
        $module = null;
        if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match)
            && isset($this->options['modules'][$match[1]])
        ) {
            $module = $this->options['modules'][$match[1]];
            $method = strtolower($match[2]).$match[3];
            if (!isset($this->modules[$module]) || !is_object($this->modules[$module])) {
                $result =& $this->loadModule($module);
                if (PEAR::isError($result)) {
                    return $result;
                }
            }
        } else {
            foreach ($this->modules as $key => $foo) {
                if (is_object($this->modules[$key])
                    && method_exists($this->modules[$key], $method)
                ) {
                    $module = $key;
                    break;
                }
            }
        }
        if (!is_null($module)) {
            return call_user_func_array(array(&$this->modules[$module], $method), $params);
        }
        trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR);
    }

    // }}}
    // {{{ function beginTransaction($savepoint = null)

    /**
     * Start a transaction or set a savepoint.
     *
     * @param   string  name of a savepoint to set
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function beginTransaction($savepoint = null)
    {
        $this->debug('Starting transaction', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'transactions are not supported', __FUNCTION__);
    }

    // }}}
    // {{{ function commit($savepoint = null)

    /**
     * Commit the database changes done during a transaction that is in
     * progress or release a savepoint. This function may only be called when
     * auto-committing is disabled, otherwise it will fail. Therefore, a new
     * transaction is implicitly started after committing the pending changes.
     *
     * @param   string  name of a savepoint to release
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function commit($savepoint = null)
    {
        $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'commiting transactions is not supported', __FUNCTION__);
    }

    // }}}
    // {{{ function rollback($savepoint = null)

    /**
     * Cancel any database changes done during a transaction or since a specific
     * savepoint that is in progress. This function may only be called when
     * auto-committing is disabled, otherwise it will fail. Therefore, a new
     * transaction is implicitly started after canceling the pending changes.
     *
     * @param   string  name of a savepoint to rollback to
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function rollback($savepoint = null)
    {
        $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'rolling back transactions is not supported', __FUNCTION__);
    }

    // }}}
    // {{{ function inTransaction($ignore_nested = false)

    /**
     * If a transaction is currently open.
     *
     * @param   bool    if the nested transaction count should be ignored
     * @return  int|bool    - an integer with the nesting depth is returned if a
     *                      nested transaction is open
     *                      - true is returned for a normal open transaction
     *                      - false is returned if no transaction is open
     *
     * @access  public
     */
    function inTransaction($ignore_nested = false)
    {
        if (!$ignore_nested && isset($this->nested_transaction_counter)) {
            return $this->nested_transaction_counter;
        }
        return $this->in_transaction;
    }

    // }}}
    // {{{ function setTransactionIsolation($isolation)

    /**
     * Set the transacton isolation level.
     *
     * @param   string  standard isolation level
     *                  READ UNCOMMITTED (allows dirty reads)
     *                  READ COMMITTED (prevents dirty reads)
     *                  REPEATABLE READ (prevents nonrepeatable reads)
     *                  SERIALIZABLE (prevents phantom reads)
     * @param   array some transaction options:
     *                  'wait' => 'WAIT' | 'NO WAIT'
     *                  'rw'   => 'READ WRITE' | 'READ ONLY'
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     * @since   2.1.1
     */
    function setTransactionIsolation($isolation, $options = array())
    {
        $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'isolation level setting is not supported', __FUNCTION__);
    }

    // }}}
    // {{{ function beginNestedTransaction($savepoint = false)

    /**
     * Start a nested transaction.
     *
     * EXPERIMENTAL
     *
     * WARNING: this function is experimental and may change signature at
     * any time until labelled as non-experimental
     *
     * @return  mixed   MDB2_OK on success/savepoint name, a MDB2 error on failure
     *
     * @access  public
     * @since   2.1.1
     */
    function beginNestedTransaction()
    {
        if ($this->in_transaction) {
            ++$this->nested_transaction_counter;
            $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter);
            if ($this->supports('savepoints') && $savepoint) {
                return $this->beginTransaction($savepoint);
            }
            return MDB2_OK;
        }
        $this->has_transaction_error = false;
        $result = $this->beginTransaction();
        $this->nested_transaction_counter = 1;
        return $result;
    }

    // }}}
    // {{{ function completeNestedTransaction($force_rollback = false, $release = false)

    /**
     * Finish a nested transaction by rolling back if an error occured or
     * committing otherwise.
     *
     * EXPERIMENTAL
     *
     * WARNING: this function is experimental and may change signature at
     * any time until labelled as non-experimental
     *
     * @param   bool    if the transaction should be rolled back regardless
     *                  even if no error was set within the nested transaction
     * @return  mixed   MDB_OK on commit/counter decrementing, false on rollback
     *                  and a MDB2 error on failure
     *
     * @access  public
     * @since   2.1.1
     */
    function completeNestedTransaction($force_rollback = false)
    {
        if ($this->nested_transaction_counter > 1) {
            $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter);
            if ($this->supports('savepoints') && $savepoint) {
                if ($force_rollback || $this->has_transaction_error) {
                    $result = $this->rollback($savepoint);
                    if (!PEAR::isError($result)) {
                        $result = false;
                        $this->has_transaction_error = false;
                    }
                } else {
                    $result = $this->commit($savepoint);
                }
            } else {
                $result = MDB2_OK;
            }
            --$this->nested_transaction_counter;
            return $result;
        }

        $this->nested_transaction_counter = null;
        $result = MDB2_OK;

        // transaction has not yet been rolled back
        if ($this->in_transaction) {
            if ($force_rollback || $this->has_transaction_error) {
                $result = $this->rollback();
                if (!PEAR::isError($result)) {
                    $result = false;
                }
            } else {
                $result = $this->commit();
            }
        }
        $this->has_transaction_error = false;
        return $result;
    }

    // }}}
    // {{{ function failNestedTransaction($error = null, $immediately = false)

    /**
     * Force setting nested transaction to failed.
     *
     * EXPERIMENTAL
     *
     * WARNING: this function is experimental and may change signature at
     * any time until labelled as non-experimental
     *
     * @param   mixed   value to return in getNestededTransactionError()
     * @param   bool    if the transaction should be rolled back immediately
     * @return  bool    MDB2_OK
     *
     * @access  public
     * @since   2.1.1
     */
    function failNestedTransaction($error = null, $immediately = false)
    {
        if (is_null($error)) {
            $error = $this->has_transaction_error ? $this->has_transaction_error : true;
        } elseif (!$error) {
            $error = true;
        }
        $this->has_transaction_error = $error;
        if (!$immediately) {
            return MDB2_OK;
        }
        return $this->rollback();
    }

    // }}}
    // {{{ function getNestedTransactionError()

    /**
     * The first error that occured since the transaction start.
     *
     * EXPERIMENTAL
     *
     * WARNING: this function is experimental and may change signature at
     * any time until labelled as non-experimental
     *
     * @return  MDB2_Error|bool     MDB2 error object if an error occured or false.
     *
     * @access  public
     * @since   2.1.1
     */
    function getNestedTransactionError()
    {
        return $this->has_transaction_error;
    }

    // }}}
    // {{{ connect()

    /**
     * Connect to the database
     *
     * @return true on success, MDB2 Error Object on failure
     */
    function connect()
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ setCharset($charset, $connection = null)

    /**
     * Set the charset on the current connection
     *
     * @param string    charset
     * @param resource  connection handle
     *
     * @return true on success, MDB2 Error Object on failure
     */
    function setCharset($charset, $connection = null)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function disconnect($force = true)

    /**
     * Log out and disconnect from the database.
     *
     * @param   bool    if the disconnect should be forced even if the
     *                  connection is opened persistently
     *
     * @return  mixed   true on success, false if not connected and error
     *                  object on error
     *
     * @access  public
     */
    function disconnect($force = true)
    {
        $this->connection = 0;
        $this->connected_dsn = array();
        $this->connected_database_name = '';
        $this->opened_persistent = null;
        $this->connected_server_info = '';
        $this->in_transaction = null;
        $this->nested_transaction_counter = null;
        return MDB2_OK;
    }

    // }}}
    // {{{ function setDatabase($name)

    /**
     * Select a different database
     *
     * @param   string  name of the database that should be selected
     *
     * @return  string  name of the database previously connected to
     *
     * @access  public
     */
    function setDatabase($name)
    {
        $previous_database_name = (isset($this->database_name)) ? $this->database_name : '';
        $this->database_name = $name;
        $this->disconnect(false);
        return $previous_database_name;
    }

    // }}}
    // {{{ function getDatabase()

    /**
     * Get the current database
     *
     * @return  string  name of the database
     *
     * @access  public
     */
    function getDatabase()
    {
        return $this->database_name;
    }

    // }}}
    // {{{ function setDSN($dsn)

    /**
     * set the DSN
     *
     * @param   mixed   DSN string or array
     *
     * @return  MDB2_OK
     *
     * @access  public
     */
    function setDSN($dsn)
    {
        $dsn_default = $GLOBALS['_MDB2_dsninfo_default'];
        $dsn = MDB2::parseDSN($dsn);
        if (array_key_exists('database', $dsn)) {
            $this->database_name = $dsn['database'];
            unset($dsn['database']);
        }
        $this->dsn = array_merge($dsn_default, $dsn);
        return $this->disconnect(false);
    }

    // }}}
    // {{{ function getDSN($type = 'string', $hidepw = false)

    /**
     * return the DSN as a string
     *
     * @param   string  format to return ("array", "string")
     * @param   string  string to hide the password with
     *
     * @return  mixed   DSN in the chosen type
     *
     * @access  public
     */
    function getDSN($type = 'string', $hidepw = false)
    {
        $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn);
        $dsn['phptype'] = $this->phptype;
        $dsn['database'] = $this->database_name;
        if ($hidepw) {
            $dsn['password'] = $hidepw;
        }
        switch ($type) {
        // expand to include all possible options
        case 'string':
           $dsn = $dsn['phptype'].
               ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : '').
               '://'.$dsn['username'].':'.
                $dsn['password'].'@'.$dsn['hostspec'].
                ($dsn['port'] ? (':'.$dsn['port']) : '').
                '/'.$dsn['database'];
            break;
        case 'array':
        default:
            break;
        }
        return $dsn;
    }

    // }}}
    // {{{ function &standaloneQuery($query, $types = null, $is_manip = false)

   /**
     * execute a query as database administrator
     *
     * @param   string  the SQL query
     * @param   mixed   array that contains the types of the columns in
     *                        the result set
     * @param   bool    if the query is a manipulation query
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function &standaloneQuery($query, $types = null, $is_manip = false)
    {
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);

        $connection = $this->getConnection();
        if (PEAR::isError($connection)) {
            return $connection;
        }

        $result =& $this->_doQuery($query, $is_manip, $connection, false);
        if (PEAR::isError($result)) {
            return $result;
        }

        if ($is_manip) {
            $affected_rows =  $this->_affectedRows($connection, $result);
            return $affected_rows;
        }
        $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset);
        return $result;
    }

    // }}}
    // {{{ function _modifyQuery($query, $is_manip, $limit, $offset)

    /**
     * Changes a query string for various DBMS specific reasons
     *
     * @param   string  query to modify
     * @param   bool    if it is a DML query
     * @param   int  limit the number of rows
     * @param   int  start reading from given offset
     *
     * @return  string  modified query
     *
     * @access  protected
     */
    function _modifyQuery($query, $is_manip, $limit, $offset)
    {
        return $query;
    }

    // }}}
    // {{{ function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)

    /**
     * Execute a query
     * @param   string  query
     * @param   bool    if the query is a manipulation query
     * @param   resource connection handle
     * @param   string  database name
     *
     * @return  result or error object
     *
     * @access  protected
     */
    function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)
    {
        $this->last_query = $query;
        $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
        if ($result) {
            if (PEAR::isError($result)) {
                return $result;
            }
            $query = $result;
        }
        $err =& $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
        return $err;
    }

    // }}}
    // {{{ function _affectedRows($connection, $result = null)

    /**
     * Returns the number of rows affected
     *
     * @param   resource result handle
     * @param   resource connection handle
     *
     * @return  mixed   MDB2 Error Object or the number of rows affected
     *
     * @access  private
     */
    function _affectedRows($connection, $result = null)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function &exec($query)

    /**
     * Execute a manipulation query to the database and return the number of affected rows
     *
     * @param   string  the SQL query
     *
     * @return  mixed   number of affected rows on success, a MDB2 error on failure
     *
     * @access  public
     */
    function &exec($query)
    {
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, true, $limit, $offset);

        $connection = $this->getConnection();
        if (PEAR::isError($connection)) {
            return $connection;
        }

        $result =& $this->_doQuery($query, true, $connection, $this->database_name);
        if (PEAR::isError($result)) {
            return $result;
        }

        $affectedRows = $this->_affectedRows($connection, $result);
        return $affectedRows;
    }

    // }}}
    // {{{ function &query($query, $types = null, $result_class = true, $result_wrap_class = false)

    /**
     * Send a query to the database and return any results
     *
     * @param   string  the SQL query
     * @param   mixed   array that contains the types of the columns in
     *                        the result set
     * @param   mixed   string which specifies which result class to use
     * @param   mixed   string which specifies which class to wrap results in
     *
     * @return mixed   an MDB2_Result handle on success, a MDB2 error on failure
     *
     * @access  public
     */
    function &query($query, $types = null, $result_class = true, $result_wrap_class = false)
    {
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, false, $limit, $offset);

        $connection = $this->getConnection();
        if (PEAR::isError($connection)) {
            return $connection;
        }

        $result =& $this->_doQuery($query, false, $connection, $this->database_name);
        if (PEAR::isError($result)) {
            return $result;
        }

        $result =& $this->_wrapResult($result, $types, $result_class, $result_wrap_class, $limit, $offset);
        return $result;
    }

    // }}}
    // {{{ function &_wrapResult($result, $types = array(), $result_class = true, $result_wrap_class = false, $limit = null, $offset = null)

    /**
     * wrap a result set into the correct class
     *
     * @param   resource result handle
     * @param   mixed   array that contains the types of the columns in
     *                        the result set
     * @param   mixed   string which specifies which result class to use
     * @param   mixed   string which specifies which class to wrap results in
     * @param   string  number of rows to select
     * @param   string  first row to select
     *
     * @return mixed   an MDB2_Result, a MDB2 error on failure
     *
     * @access  protected
     */
    function &_wrapResult($result, $types = array(), $result_class = true,
        $result_wrap_class = false, $limit = null, $offset = null)
    {
        if ($types === true) {
            if ($this->supports('result_introspection')) {
                $this->loadModule('Reverse', null, true);
                $tableInfo = $this->reverse->tableInfo($result);
                if (PEAR::isError($tableInfo)) {
                    return $tableInfo;
                }
                $types = array();
                foreach ($tableInfo as $field) {
                    $types[] = $field['mdb2type'];
                }
            } else {
                $types = null;
            }
        }

        if ($result_class === true) {
            $result_class = $this->options['result_buffering']
                ? $this->options['buffered_result_class'] : $this->options['result_class'];
        }

        if ($result_class) {
            $class_name = sprintf($result_class, $this->phptype);
            if (!MDB2::classExists($class_name)) {
                $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                    'result class does not exist '.$class_name, __FUNCTION__);
                return $err;
            }
            $result =& new $class_name($this, $result, $limit, $offset);
            if (!MDB2::isResultCommon($result)) {
                $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                    'result class is not extended from MDB2_Result_Common', __FUNCTION__);
                return $err;
            }
            if (!empty($types)) {
                $err = $result->setResultTypes($types);
                if (PEAR::isError($err)) {
                    $result->free();
                    return $err;
                }
            }
        }
        if ($result_wrap_class === true) {
            $result_wrap_class = $this->options['result_wrap_class'];
        }
        if ($result_wrap_class) {
            if (!MDB2::classExists($result_wrap_class)) {
                $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                    'result wrap class does not exist '.$result_wrap_class, __FUNCTION__);
                return $err;
            }
            $result =& new $result_wrap_class($result, $this->fetchmode);
        }
        return $result;
    }

    // }}}
    // {{{ function getServerVersion($native = false)

    /**
     * return version information about the server
     *
     * @param   bool    determines if the raw version string should be returned
     *
     * @return  mixed   array with version information or row string
     *
     * @access  public
     */
    function getServerVersion($native = false)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function setLimit($limit, $offset = null)

    /**
     * set the range of the next query
     *
     * @param   string  number of rows to select
     * @param   string  first row to select
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function setLimit($limit, $offset = null)
    {
        if (!$this->supports('limit_queries')) {
            return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'limit is not supported by this driver', __FUNCTION__);
        }
        $limit = (int)$limit;
        if ($limit < 0) {
            return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
                'it was not specified a valid selected range row limit', __FUNCTION__);
        }
        $this->limit = $limit;
        if (!is_null($offset)) {
            $offset = (int)$offset;
            if ($offset < 0) {
                return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
                    'it was not specified a valid first selected range row', __FUNCTION__);
            }
            $this->offset = $offset;
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function subSelect($query, $type = false)

    /**
     * simple subselect emulation: leaves the query untouched for all RDBMS
     * that support subselects
     *
     * @param   string  the SQL query for the subselect that may only
     *                      return a column
     * @param   string  determines type of the field
     *
     * @return  string  the query
     *
     * @access  public
     */
    function subSelect($query, $type = false)
    {
        if ($this->supports('sub_selects') === true) {
            return $query;
        }

        if (!$this->supports('sub_selects')) {
            return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'method not implemented', __FUNCTION__);
        }

        $col = $this->queryCol($query, $type);
        if (PEAR::isError($col)) {
            return $col;
        }
        if (!is_array($col) || count($col) == 0) {
            return 'NULL';
        }
        if ($type) {
            $this->loadModule('Datatype', null, true);
            return $this->datatype->implodeArray($col, $type);
        }
        return implode(', ', $col);
    }

    // }}}
    // {{{ function replace($table, $fields)

    /**
     * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
     * query, except that if there is already a row in the table with the same
     * key field values, the REPLACE query just updates its values instead of
     * inserting a new row.
     *
     * The REPLACE type of query does not make part of the SQL standards. Since
     * practically only MySQL and SQLite implement it natively, this type of
     * query isemulated through this method for other DBMS using standard types
     * of queries inside a transaction to assure the atomicity of the operation.
     *
     * @param   string  name of the table on which the REPLACE query will
     *       be executed.
     * @param   array   associative array   that describes the fields and the
     *       values that will be inserted or updated in the specified table. The
     *       indexes of the array are the names of all the fields of the table.
     *       The values of the array are also associative arrays that describe
     *       the values and other properties of the table fields.
     *
     *       Here follows a list of field properties that need to be specified:
     *
     *       value
     *           Value to be assigned to the specified field. This value may be
     *           of specified in database independent type format as this
     *           function can perform the necessary datatype conversions.
     *
     *           Default: this property is required unless the Null property is
     *           set to 1.
     *
     *       type
     *           Name of the type of the field. Currently, all types MDB2
     *           are supported except for clob and blob.
     *
     *           Default: no type conversion
     *
     *       null
     *           bool    property that indicates that the value for this field
     *           should be set to null.
     *
     *           The default value for fields missing in INSERT queries may be
     *           specified the definition of a table. Often, the default value
     *           is already null, but since the REPLACE may be emulated using
     *           an UPDATE query, make sure that all fields of the table are
     *           listed in this function argument array.
     *
     *           Default: 0
     *
     *       key
     *           bool    property that indicates that this field should be
     *           handled as a primary key or at least as part of the compound
     *           unique index of the table that will determine the row that will
     *           updated if it exists or inserted a new row otherwise.
     *
     *           This function will fail if no key field is specified or if the
     *           value of a key field is set to null because fields that are
     *           part of unique index they may not be null.
     *
     *           Default: 0
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function replace($table, $fields)
    {
        if (!$this->supports('replace')) {
            return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'replace query is not supported', __FUNCTION__);
        }
        $count = count($fields);
        $condition = $values = array();
        for ($colnum = 0, reset($fields); $colnum < $count; next($fields), $colnum++) {
            $name = key($fields);
            if (isset($fields[$name]['null']) && $fields[$name]['null']) {
                $value = 'NULL';
            } else {
                $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
                $value = $this->quote($fields[$name]['value'], $type);
            }
            $values[$name] = $value;
            if (isset($fields[$name]['key']) && $fields[$name]['key']) {
                if ($value === 'NULL') {
                    return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
                        'key value '.$name.' may not be NULL', __FUNCTION__);
                }
                $condition[] = $name . '=' . $value;
            }
        }
        if (empty($condition)) {
            return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
                'not specified which fields are keys', __FUNCTION__);
        }

        $result = null;
        $in_transaction = $this->in_transaction;
        if (!$in_transaction && PEAR::isError($result = $this->beginTransaction())) {
            return $result;
        }

        $connection = $this->getConnection();
        if (PEAR::isError($connection)) {
            return $connection;
        }

        $condition = ' WHERE '.implode(' AND ', $condition);
        $query = "DELETE FROM $table$condition";
        $result =& $this->_doQuery($query, true, $connection);
        if (!PEAR::isError($result)) {
            $affected_rows = $this->_affectedRows($connection, $result);
            $insert = implode(', ', array_keys($values));
            $values = implode(', ', $values);
            $query = "INSERT INTO $table ($insert) VALUES ($values)";
            $result =& $this->_doQuery($query, true, $connection);
            if (!PEAR::isError($result)) {
                $affected_rows += $this->_affectedRows($connection, $result);;
            }
        }

        if (!$in_transaction) {
            if (PEAR::isError($result)) {
                $this->rollback();
            } else {
                $result = $this->commit();
            }
        }

        if (PEAR::isError($result)) {
            return $result;
        }

        return $affected_rows;
    }

    // }}}
    // {{{ function &prepare($query, $types = null, $result_types = null, $lobs = array())

    /**
     * Prepares a query for multiple execution with execute().
     * With some database backends, this is emulated.
     * prepare() requires a generic query as string like
     * 'INSERT INTO numbers VALUES(?,?)' or
     * 'INSERT INTO numbers VALUES(:foo,:bar)'.
     * The ? and :[a-zA-Z] and  are placeholders which can be set using
     * bindParam() and the query can be send off using the execute() method.
     *
     * @param   string  the query to prepare
     * @param   mixed   array that contains the types of the placeholders
     * @param   mixed   array that contains the types of the columns in
     *                        the result set or MDB2_PREPARE_RESULT, if set to
     *                        MDB2_PREPARE_MANIP the query is handled as a manipulation query
     * @param   mixed   key (field) value (parameter) pair for all lob placeholders
     *
     * @return  mixed   resource handle for the prepared query on success, 
     *                  a MDB2 error on failure
     *
     * @access  public
     * @see     bindParam, execute
     */
    function &prepare($query, $types = null, $result_types = null, $lobs = array())
    {
        $is_manip = ($result_types === MDB2_PREPARE_MANIP);
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
        if ($result) {
            if (PEAR::isError($result)) {
                return $result;
            }
            $query = $result;
        }
        $placeholder_type_guess = $placeholder_type = null;
        $question = '?';
        $colon = ':';
        $positions = array();
        $position = 0;
        $ignores = $this->sql_comments;
        $ignores[] = $this->string_quoting;
        $ignores[] = $this->identifier_quoting;
        while ($position < strlen($query)) {
            $q_position = strpos($query, $question, $position);
            $c_position = strpos($query, $colon, $position);
            if ($q_position && $c_position) {
                $p_position = min($q_position, $c_position);
            } elseif ($q_position) {
                $p_position = $q_position;
            } elseif ($c_position) {
                $p_position = $c_position;
            } else {
                break;
            }
            if (is_null($placeholder_type)) {
                $placeholder_type_guess = $query[$p_position];
            }

            $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
            if (PEAR::isError($new_pos)) {
                return $new_pos;
            }
            if ($new_pos != $position) {
                $position = $new_pos;
                continue; //evaluate again starting from the new position
            }

            if ($query[$position] == $placeholder_type_guess) {
                if (is_null($placeholder_type)) {
                    $placeholder_type = $query[$p_position];
                    $question = $colon = $placeholder_type;
                    if (!empty($types) && is_array($types)) {
                        if ($placeholder_type == ':') {
                            if (is_int(key($types))) {
                                $types_tmp = $types;
                                $types = array();
                                $count = -1;
                            }
                        } else {
                            $types = array_values($types);
                        }
                    }
                }
                if ($placeholder_type == ':') {
                    $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query);
                    if ($parameter === '') {
                        $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
                            'named parameter with an empty name', __FUNCTION__);
                        return $err;
                    }
                    $positions[$p_position] = $parameter;
                    $query = substr_replace($query, '?', $position, strlen($parameter)+1);
                    // use parameter name in type array
                    if (isset($count) && isset($types_tmp[++$count])) {
                        $types[$parameter] = $types_tmp[$count];
                    }
                } else {
                    $positions[$p_position] = count($positions);
                }
                $position = $p_position + 1;
            } else {
                $position = $p_position;
            }
        }
        $class_name = 'MDB2_Statement_'.$this->phptype;
        $statement = null;
        $obj =& new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
        $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
        return $obj;
    }

    // }}}
    // {{{ function _skipDelimitedStrings($query, $position, $p_position)
    
    /**
     * Utility method, used by prepare() to avoid replacing placeholders within delimited strings.
     * Check if the placeholder is contained within a delimited string.
     * If so, skip it and advance the position, otherwise return the current position,
     * which is valid
     *
     * @param string $query
     * @param integer $position current string cursor position
     * @param integer $p_position placeholder position
     *
     * @return mixed integer $new_position on success
     *               MDB2_Error on failure
     *
     * @access  protected
     */
    function _skipDelimitedStrings($query, $position, $p_position)
    {
        $ignores = $this->sql_comments;
        $ignores[] = $this->string_quoting;
        $ignores[] = $this->identifier_quoting;
        
        foreach ($ignores as $ignore) {
            if (!empty($ignore['start'])) {
                if (is_int($start_quote = strpos($query, $ignore['start'], $position)) && $start_quote < $p_position) {
                    $end_quote = $start_quote;
                    do {
                        if (!is_int($end_quote = strpos($query, $ignore['end'], $end_quote + 1))) {
                            if ($ignore['end'] === "\n") {
                                $end_quote = strlen($query) - 1;
                            } else {
                                $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
                                    'query with an unterminated text string specified', __FUNCTION__);
                                return $err;
                            }
                        }
                    } while ($ignore['escape'] && $query[($end_quote - 1)] == $ignore['escape']);
                    $position = $end_quote + 1;
                    return $position;
                }
            }
        }
        return $position;
    }
    
    // }}}
    // {{{ function quote($value, $type = null, $quote = true)

    /**
     * Convert a text value into a DBMS specific format that is suitable to
     * compose query statements.
     *
     * @param   string  text string value that is intended to be converted.
     * @param   string  type to which the value should be converted to
     * @param   bool    quote
     * @param   bool    escape wildcards
     *
     * @return  string  text string that represents the given argument value in
     *       a DBMS specific format.
     *
     * @access  public
     */
    function quote($value, $type = null, $quote = true, $escape_wildcards = false)
    {
        $result = $this->loadModule('Datatype', null, true);
        if (PEAR::isError($result)) {
            return $result;
        }

        return $this->datatype->quote($value, $type, $quote, $escape_wildcards);
    }

    // }}}
    // {{{ function getDeclaration($type, $name, $field)

    /**
     * Obtain DBMS specific SQL code portion needed to declare
     * of the given type
     *
     * @param   string  type to which the value should be converted to
     * @param   string  name the field to be declared.
     * @param   string  definition of the field
     *
     * @return  string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     *
     * @access  public
     */
    function getDeclaration($type, $name, $field)
    {
        $result = $this->loadModule('Datatype', null, true);
        if (PEAR::isError($result)) {
            return $result;
        }
        return $this->datatype->getDeclaration($type, $name, $field);
    }

    // }}}
    // {{{ function compareDefinition($current, $previous)

    /**
     * Obtain an array of changes that may need to applied
     *
     * @param   array   new definition
     * @param   array   old definition
     *
     * @return  array   containing all changes that will need to be applied
     *
     * @access  public
     */
    function compareDefinition($current, $previous)
    {
        $result = $this->loadModule('Datatype', null, true);
        if (PEAR::isError($result)) {
            return $result;
        }
        return $this->datatype->compareDefinition($current, $previous);
    }

    // }}}
    // {{{ function supports($feature)

    /**
     * Tell whether a DB implementation or its backend extension
     * supports a given feature.
     *
     * @param   string  name of the feature (see the MDB2 class doc)
     *
     * @return  bool|string if this DB implementation supports a given feature
     *                      false means no, true means native,
     *                      'emulated' means emulated
     *
     * @access  public
     */
    function supports($feature)
    {
        if (array_key_exists($feature, $this->supported)) {
            return $this->supported[$feature];
        }
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            "unknown support feature $feature", __FUNCTION__);
    }

    // }}}
    // {{{ function getSequenceName($sqn)

    /**
     * adds sequence name formatting to a sequence name
     *
     * @param   string  name of the sequence
     *
     * @return  string  formatted sequence name
     *
     * @access  public
     */
    function getSequenceName($sqn)
    {
        return sprintf($this->options['seqname_format'],
            preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn));
    }

    // }}}
    // {{{ function getIndexName($idx)

    /**
     * adds index name formatting to a index name
     *
     * @param   string  name of the index
     *
     * @return  string  formatted index name
     *
     * @access  public
     */
    function getIndexName($idx)
    {
        return sprintf($this->options['idxname_format'],
            preg_replace('/[^a-z0-9_\$]/i', '_', $idx));
    }

    // }}}
    // {{{ function nextID($seq_name, $ondemand = true)

    /**
     * Returns the next free id of a sequence
     *
     * @param   string  name of the sequence
     * @param   bool    when true missing sequences are automatic created
     *
     * @return  mixed   MDB2 Error Object or id
     *
     * @access  public
     */
    function nextID($seq_name, $ondemand = true)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function lastInsertID($table = null, $field = null)

    /**
     * Returns the autoincrement ID if supported or $id or fetches the current
     * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
     *
     * @param   string  name of the table into which a new row was inserted
     * @param   string  name of the field into which a new row was inserted
     *
     * @return  mixed   MDB2 Error Object or id
     *
     * @access  public
     */
    function lastInsertID($table = null, $field = null)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function currID($seq_name)

    /**
     * Returns the current id of a sequence
     *
     * @param   string  name of the sequence
     *
     * @return  mixed   MDB2 Error Object or id
     *
     * @access  public
     */
    function currID($seq_name)
    {
        $this->warnings[] = 'database does not support getting current
            sequence value, the sequence value was incremented';
        return $this->nextID($seq_name);
    }

    // }}}
    // {{{ function queryOne($query, $type = null, $colnum = 0)

    /**
     * Execute the specified query, fetch the value from the first column of
     * the first row of the result set and then frees
     * the result set.
     *
     * @param   string  the SELECT query statement to be executed.
     * @param   string  optional argument that specifies the expected
     *       datatype of the result set field, so that an eventual conversion
     *       may be performed. The default datatype is text, meaning that no
     *       conversion is performed
     * @param   int     the column number to fetch
     *
     * @return  mixed   MDB2_OK or field value on success, a MDB2 error on failure
     *
     * @access  public
     */
    function queryOne($query, $type = null, $colnum = 0)
    {
        $result = $this->query($query, $type);
        if (!MDB2::isResultCommon($result)) {
            return $result;
        }

        $one = $result->fetchOne($colnum);
        $result->free();
        return $one;
    }

    // }}}
    // {{{ function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)

    /**
     * Execute the specified query, fetch the values from the first
     * row of the result set into an array and then frees
     * the result set.
     *
     * @param   string  the SELECT query statement to be executed.
     * @param   array   optional array argument that specifies a list of
     *       expected datatypes of the result set columns, so that the eventual
     *       conversions may be performed. The default list of datatypes is
     *       empty, meaning that no conversion is performed.
     * @param   int     how the array data should be indexed
     *
     * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
     *
     * @access  public
     */
    function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
    {
        $result = $this->query($query, $types);
        if (!MDB2::isResultCommon($result)) {
            return $result;
        }

        $row = $result->fetchRow($fetchmode);
        $result->free();
        return $row;
    }

    // }}}
    // {{{ function queryCol($query, $type = null, $colnum = 0)

    /**
     * Execute the specified query, fetch the value from the first column of
     * each row of the result set into an array and then frees the result set.
     *
     * @param   string  the SELECT query statement to be executed.
     * @param   string  optional argument that specifies the expected
     *       datatype of the result set field, so that an eventual conversion
     *       may be performed. The default datatype is text, meaning that no
     *       conversion is performed
     * @param   int     the row number to fetch
     *
     * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
     *
     * @access  public
     */
    function queryCol($query, $type = null, $colnum = 0)
    {
        $result = $this->query($query, $type);
        if (!MDB2::isResultCommon($result)) {
            return $result;
        }

        $col = $result->fetchCol($colnum);
        $result->free();
        return $col;
    }

    // }}}
    // {{{ function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)

    /**
     * Execute the specified query, fetch all the rows of the result set into
     * a two dimensional array and then frees the result set.
     *
     * @param   string  the SELECT query statement to be executed.
     * @param   array   optional array argument that specifies a list of
     *       expected datatypes of the result set columns, so that the eventual
     *       conversions may be performed. The default list of datatypes is
     *       empty, meaning that no conversion is performed.
     * @param   int     how the array data should be indexed
     * @param   bool    if set to true, the $all will have the first
     *       column as its first dimension
     * @param   bool    used only when the query returns exactly
     *       two columns. If true, the values of the returned array will be
     *       one-element arrays instead of scalars.
     * @param   bool    if true, the values of the returned array is
     *       wrapped in another array.  If the same key value (in the first
     *       column) repeats itself, the values will be appended to this array
     *       instead of overwriting the existing values.
     *
     * @return  mixed   MDB2_OK or data array on success, a MDB2 error on failure
     *
     * @access  public
     */
    function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT,
        $rekey = false, $force_array = false, $group = false)
    {
        $result = $this->query($query, $types);
        if (!MDB2::isResultCommon($result)) {
            return $result;
        }

        $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group);
        $result->free();
        return $all;
    }

    // }}}
}

// }}}
// {{{ class MDB2_Result

/**
 * The dummy class that all user space result classes should extend from
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Result
{
}

// }}}
// {{{ class MDB2_Result_Common extends MDB2_Result

/**
 * The common result class for MDB2 result objects
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Result_Common extends MDB2_Result
{
    // {{{ Variables (Properties)

    var $db;
    var $result;
    var $rownum = -1;
    var $types = array();
    var $values = array();
    var $offset;
    var $offset_count = 0;
    var $limit;
    var $column_names;

    // }}}
    // {{{ constructor: function __construct(&$db, &$result, $limit = 0, $offset = 0)

    /**
     * Constructor
     */
    function __construct(&$db, &$result, $limit = 0, $offset = 0)
    {
        $this->db =& $db;
        $this->result =& $result;
        $this->offset = $offset;
        $this->limit = max(0, $limit - 1);
    }

    // }}}
    // {{{ function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0)

    /**
     * PHP 4 Constructor
     */
    function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0)
    {
        $this->__construct($db, $result, $limit, $offset);
    }

    // }}}
    // {{{ function setResultTypes($types)

    /**
     * Define the list of types to be associated with the columns of a given
     * result set.
     *
     * This function may be called before invoking fetchRow(), fetchOne(),
     * fetchCol() and fetchAll() so that the necessary data type
     * conversions are performed on the data to be retrieved by them. If this
     * function is not called, the type of all result set columns is assumed
     * to be text, thus leading to not perform any conversions.
     *
     * @param   array   variable that lists the
     *       data types to be expected in the result set columns. If this array
     *       contains less types than the number of columns that are returned
     *       in the result set, the remaining columns are assumed to be of the
     *       type text. Currently, the types clob and blob are not fully
     *       supported.
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function setResultTypes($types)
    {
        $load = $this->db->loadModule('Datatype', null, true);
        if (PEAR::isError($load)) {
            return $load;
        }
        $types = $this->db->datatype->checkResultTypes($types);
        if (PEAR::isError($types)) {
            return $types;
        }
        $this->types = $types;
        return MDB2_OK;
    }

    // }}}
    // {{{ function seek($rownum = 0)

    /**
     * Seek to a specific row in a result set
     *
     * @param   int     number of the row where the data can be found
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function seek($rownum = 0)
    {
        $target_rownum = $rownum - 1;
        if ($this->rownum > $target_rownum) {
            return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'seeking to previous rows not implemented', __FUNCTION__);
        }
        while ($this->rownum < $target_rownum) {
            $this->fetchRow();
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)

    /**
     * Fetch and return a row of data
     *
     * @param   int     how the array data should be indexed
     * @param   int     number of the row where the data can be found
     *
     * @return  int     data array on success, a MDB2 error on failure
     *
     * @access  public
     */
    function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
    {
        $err =& $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
        return $err;
    }

    // }}}
    // {{{ function fetchOne($colnum = 0)

    /**
     * fetch single column from the next row from a result set
     *
     * @param   int     the column number to fetch
     * @param   int     number of the row where the data can be found
     *
     * @return  string  data on success, a MDB2 error on failure
     *
     * @access  public
     */
    function fetchOne($colnum = 0, $rownum = null)
    {
        $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
        $row = $this->fetchRow($fetchmode, $rownum);
        if (!is_array($row) || PEAR::isError($row)) {
            return $row;
        }
        if (!array_key_exists($colnum, $row)) {
            return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
                'column is not defined in the result set: '.$colnum, __FUNCTION__);
        }
        return $row[$colnum];
    }

    // }}}
    // {{{ function fetchCol($colnum = 0)

    /**
     * Fetch and return a column from the current row pointer position
     *
     * @param   int     the column number to fetch
     *
     * @return  mixed   data array on success, a MDB2 error on failure
     *
     * @access  public
     */
    function fetchCol($colnum = 0)
    {
        $column = array();
        $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
        $row = $this->fetchRow($fetchmode);
        if (is_array($row)) {
            if (!array_key_exists($colnum, $row)) {
                return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
                    'column is not defined in the result set: '.$colnum, __FUNCTION__);
            }
            do {
                $column[] = $row[$colnum];
            } while (is_array($row = $this->fetchRow($fetchmode)));
        }
        if (PEAR::isError($row)) {
            return $row;
        }
        return $column;
    }

    // }}}
    // {{{ function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false)

    /**
     * Fetch and return all rows from the current row pointer position
     *
     * @param   int     $fetchmode  the fetch mode to use:
     *                            + MDB2_FETCHMODE_ORDERED
     *                            + MDB2_FETCHMODE_ASSOC
     *                            + MDB2_FETCHMODE_ORDERED | MDB2_FETCHMODE_FLIPPED
     *                            + MDB2_FETCHMODE_ASSOC | MDB2_FETCHMODE_FLIPPED
     * @param   bool    if set to true, the $all will have the first
     *       column as its first dimension
     * @param   bool    used only when the query returns exactly
     *       two columns. If true, the values of the returned array will be
     *       one-element arrays instead of scalars.
     * @param   bool    if true, the values of the returned array is
     *       wrapped in another array.  If the same key value (in the first
     *       column) repeats itself, the values will be appended to this array
     *       instead of overwriting the existing values.
     *
     * @return  mixed   data array on success, a MDB2 error on failure
     *
     * @access  public
     * @see     getAssoc()
     */
    function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false,
        $force_array = false, $group = false)
    {
        $all = array();
        $row = $this->fetchRow($fetchmode);
        if (PEAR::isError($row)) {
            return $row;
        } elseif (!$row) {
            return $all;
        }

        $shift_array = $rekey ? false : null;
        if (!is_null($shift_array)) {
            if (is_object($row)) {
                $colnum = count(get_object_vars($row));
            } else {
                $colnum = count($row);
            }
            if ($colnum < 2) {
                return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null,
                    'rekey feature requires atleast 2 column', __FUNCTION__);
            }
            $shift_array = (!$force_array && $colnum == 2);
        }

        if ($rekey) {
            do {
                if (is_object($row)) {
                    $arr = get_object_vars($row);
                    $key = reset($arr);
                    unset($row->{$key});
                } else {
                    if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
                        $key = reset($row);
                        unset($row[key($row)]);
                    } else {
                        $key = array_shift($row);
                    }
                    if ($shift_array) {
                        $row = array_shift($row);
                    }
                }
                if ($group) {
                    $all[$key][] = $row;
                } else {
                    $all[$key] = $row;
                }
            } while (($row = $this->fetchRow($fetchmode)));
        } elseif ($fetchmode & MDB2_FETCHMODE_FLIPPED) {
            do {
                foreach ($row as $key => $val) {
                    $all[$key][] = $val;
                }
            } while (($row = $this->fetchRow($fetchmode)));
        } else {
            do {
                $all[] = $row;
            } while (($row = $this->fetchRow($fetchmode)));
        }

        return $all;
    }

    // }}}
    // {{{ function rowCount()
    /**
     * Returns the actual row number that was last fetched (count from 0)
     * @return  int
     *
     * @access  public
     */
    function rowCount()
    {
        return $this->rownum + 1;
    }

    // }}}
    // {{{ function numRows()

    /**
     * Returns the number of rows in a result object
     *
     * @return  mixed   MDB2 Error Object or the number of rows
     *
     * @access  public
     */
    function numRows()
    {
        return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function nextResult()

    /**
     * Move the internal result pointer to the next available result
     *
     * @return  true on success, false if there is no more result set or an error object on failure
     *
     * @access  public
     */
    function nextResult()
    {
        return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function getColumnNames()

    /**
     * Retrieve the names of columns returned by the DBMS in a query result or
     * from the cache.
     *
     * @param   bool    If set to true the values are the column names,
     *                  otherwise the names of the columns are the keys.
     * @return  mixed   Array variable that holds the names of columns or an
     *                  MDB2 error on failure.
     *                  Some DBMS may not return any columns when the result set
     *                  does not contain any rows.
     *
     * @access  public
     */
    function getColumnNames($flip = false)
    {
        if (!isset($this->column_names)) {
            $result = $this->_getColumnNames();
            if (PEAR::isError($result)) {
                return $result;
            }
            $this->column_names = $result;
        }
        if ($flip) {
            return array_flip($this->column_names);
        }
        return $this->column_names;
    }

    // }}}
    // {{{ function _getColumnNames()

    /**
     * Retrieve the names of columns returned by the DBMS in a query result.
     *
     * @return  mixed   Array variable that holds the names of columns as keys
     *                  or an MDB2 error on failure.
     *                  Some DBMS may not return any columns when the result set
     *                  does not contain any rows.
     *
     * @access  private
     */
    function _getColumnNames()
    {
        return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function numCols()

    /**
     * Count the number of columns returned by the DBMS in a query result.
     *
     * @return  mixed   integer value with the number of columns, a MDB2 error
     *       on failure
     *
     * @access  public
     */
    function numCols()
    {
        return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }

    // }}}
    // {{{ function getResource()

    /**
     * return the resource associated with the result object
     *
     * @return  resource
     *
     * @access  public
     */
    function getResource()
    {
        return $this->result;
    }

    // }}}
    // {{{ function bindColumn($column, &$value, $type = null)

    /**
     * Set bind variable to a column.
     *
     * @param   int     column number or name
     * @param   mixed   variable reference
     * @param   string  specifies the type of the field
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function bindColumn($column, &$value, $type = null)
    {
        if (!is_numeric($column)) {
            $column_names = $this->getColumnNames();
            if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
                if ($this->db->options['field_case'] == CASE_LOWER) {
                    $column = strtolower($column);
                } else {
                    $column = strtoupper($column);
                }
            }
            $column = $column_names[$column];
        }
        $this->values[$column] =& $value;
        if (!is_null($type)) {
            $this->types[$column] = $type;
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function _assignBindColumns($row)

    /**
     * Bind a variable to a value in the result row.
     *
     * @param   array   row data
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  private
     */
    function _assignBindColumns($row)
    {
        $row = array_values($row);
        foreach ($row as $column => $value) {
            if (array_key_exists($column, $this->values)) {
                $this->values[$column] = $value;
            }
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function free()

    /**
     * Free the internal resources associated with result.
     *
     * @return  bool    true on success, false if result is invalid
     *
     * @access  public
     */
    function free()
    {
        $this->result = false;
        return MDB2_OK;
    }

    // }}}
}

// }}}
// {{{ class MDB2_Row

/**
 * The simple class that accepts row data as an array
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Row
{
    // {{{ constructor: function __construct(&$row)

    /**
     * constructor
     *
     * @param   resource    row data as array
     */
    function __construct(&$row)
    {
        foreach ($row as $key => $value) {
            $this->$key = &$row[$key];
        }
    }

    // }}}
    // {{{ function MDB2_Row(&$row)

    /**
     * PHP 4 Constructor
     *
     * @param   resource    row data as array
     */
    function MDB2_Row(&$row)
    {
        $this->__construct($row);
    }

    // }}}
}

// }}}
// {{{ class MDB2_Statement_Common

/**
 * The common statement class for MDB2 statement objects
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Statement_Common
{
    // {{{ Variables (Properties)

    var $db;
    var $statement;
    var $query;
    var $result_types;
    var $types;
    var $values = array();
    var $limit;
    var $offset;
    var $is_manip;

    // }}}
    // {{{ constructor: function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)

    /**
     * Constructor
     */
    function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
    {
        $this->db =& $db;
        $this->statement =& $statement;
        $this->positions = $positions;
        $this->query = $query;
        $this->types = (array)$types;
        $this->result_types = (array)$result_types;
        $this->limit = $limit;
        $this->is_manip = $is_manip;
        $this->offset = $offset;
    }

    // }}}
    // {{{ function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)

    /**
     * PHP 4 Constructor
     */
    function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null)
    {
        $this->__construct($db, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
    }

    // }}}
    // {{{ function bindValue($parameter, &$value, $type = null)

    /**
     * Set the value of a parameter of a prepared query.
     *
     * @param   int     the order number of the parameter in the query
     *       statement. The order number of the first parameter is 1.
     * @param   mixed   value that is meant to be assigned to specified
     *       parameter. The type of the value depends on the $type argument.
     * @param   string  specifies the type of the field
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function bindValue($parameter, $value, $type = null)
    {
        if (!is_numeric($parameter)) {
            $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter);
        }
        if (!in_array($parameter, $this->positions)) {
            return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
        }
        $this->values[$parameter] = $value;
        if (!is_null($type)) {
            $this->types[$parameter] = $type;
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function bindValueArray($values, $types = null)

    /**
     * Set the values of multiple a parameter of a prepared query in bulk.
     *
     * @param   array   specifies all necessary information
     *       for bindValue() the array elements must use keys corresponding to
     *       the number of the position of the parameter.
     * @param   array   specifies the types of the fields
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     * @see     bindParam()
     */
    function bindValueArray($values, $types = null)
    {
        $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
        $parameters = array_keys($values);
        foreach ($parameters as $key => $parameter) {
            $err = $this->bindValue($parameter, $values[$parameter], $types[$key]);
            if (PEAR::isError($err)) {
                return $err;
            }
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function bindParam($parameter, &$value, $type = null)

    /**
     * Bind a variable to a parameter of a prepared query.
     *
     * @param   int     the order number of the parameter in the query
     *       statement. The order number of the first parameter is 1.
     * @param   mixed   variable that is meant to be bound to specified
     *       parameter. The type of the value depends on the $type argument.
     * @param   string  specifies the type of the field
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function bindParam($parameter, &$value, $type = null)
    {
        if (!is_numeric($parameter)) {
            $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter);
        }
        if (!in_array($parameter, $this->positions)) {
            return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
        }
        $this->values[$parameter] =& $value;
        if (!is_null($type)) {
            $this->types[$parameter] = $type;
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function bindParamArray(&$values, $types = null)

    /**
     * Bind the variables of multiple a parameter of a prepared query in bulk.
     *
     * @param   array   specifies all necessary information
     *       for bindParam() the array elements must use keys corresponding to
     *       the number of the position of the parameter.
     * @param   array   specifies the types of the fields
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     * @see     bindParam()
     */
    function bindParamArray(&$values, $types = null)
    {
        $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
        $parameters = array_keys($values);
        foreach ($parameters as $key => $parameter) {
            $err = $this->bindParam($parameter, $values[$parameter], $types[$key]);
            if (PEAR::isError($err)) {
                return $err;
            }
        }
        return MDB2_OK;
    }

    // }}}
    // {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false)

    /**
     * Execute a prepared query statement.
     *
     * @param   array   specifies all necessary information
     *       for bindParam() the array elements must use keys corresponding to
     *       the number of the position of the parameter.
     * @param   mixed   specifies which result class to use
     * @param   mixed   specifies which class to wrap results in
     *
     * @return  mixed   a result handle or MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function &execute($values = null, $result_class = true, $result_wrap_class = false)
    {
        if (is_null($this->positions)) {
            return $this->db->raiseError(MDB2_ERROR, null, null,
                'Prepared statement has already been freed', __FUNCTION__);
        }

        $values = (array)$values;
        if (!empty($values)) {
            $err = $this->bindValueArray($values);
            if (PEAR::isError($err)) {
                return $this->db->raiseError(MDB2_ERROR, null, null,
                                            'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__);
            }
        }
        $result =& $this->_execute($result_class, $result_wrap_class);
        return $result;
    }

    // }}}
    // {{{ function &_execute($result_class = true, $result_wrap_class = false)

    /**
     * Execute a prepared query statement helper method.
     *
     * @param   mixed   specifies which result class to use
     * @param   mixed   specifies which class to wrap results in
     *
     * @return  mixed   MDB2_Result or integer on success, a MDB2 error on failure
     *
     * @access  private
     */
    function &_execute($result_class = true, $result_wrap_class = false)
    {
        $this->last_query = $this->query;
        $query = '';
        $last_position = 0;
        foreach ($this->positions as $current_position => $parameter) {
            if (!array_key_exists($parameter, $this->values)) {
                return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                    'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
            }
            $value = $this->values[$parameter];
            $query.= substr($this->query, $last_position, $current_position - $last_position);
            if (!isset($value)) {
                $value_quoted = 'NULL';
            } else {
                $type = !empty($this->types[$parameter]) ? $this->types[$parameter] : null;
                $value_quoted = $this->db->quote($value, $type);
                if (PEAR::isError($value_quoted)) {
                    return $value_quoted;
                }
            }
            $query.= $value_quoted;
            $last_position = $current_position + 1;
        }
        $query.= substr($this->query, $last_position);

        $this->db->offset = $this->offset;
        $this->db->limit = $this->limit;
        if ($this->is_manip) {
            $result = $this->db->exec($query);
        } else {
            $result =& $this->db->query($query, $this->result_types, $result_class, $result_wrap_class);
        }
        return $result;
    }

    // }}}
    // {{{ function free()

    /**
     * Release resources allocated for the specified prepared query.
     *
     * @return  mixed   MDB2_OK on success, a MDB2 error on failure
     *
     * @access  public
     */
    function free()
    {
        if (is_null($this->positions)) {
            return $this->db->raiseError(MDB2_ERROR, null, null,
                'Prepared statement has already been freed', __FUNCTION__);
        }

        $this->statement = null;
        $this->positions = null;
        $this->query = null;
        $this->types = null;
        $this->result_types = null;
        $this->limit = null;
        $this->is_manip = null;
        $this->offset = null;
        $this->values = null;

        return MDB2_OK;
    }

    // }}}
}

// }}}
// {{{ class MDB2_Module_Common

/**
 * The common modules class for MDB2 module objects
 *
 * @package     MDB2
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 */
class MDB2_Module_Common
{
    // {{{ Variables (Properties)

    /**
     * contains the key to the global MDB2 instance array of the associated
     * MDB2 instance
     *
     * @var     int
     * @access  protected
     */
    var $db_index;

    // }}}
    // {{{ constructor: function __construct($db_index)

    /**
     * Constructor
     */
    function __construct($db_index)
    {
        $this->db_index = $db_index;
    }

    // }}}
    // {{{ function MDB2_Module_Common($db_index)

    /**
     * PHP 4 Constructor
     */
    function MDB2_Module_Common($db_index)
    {
        $this->__construct($db_index);
    }

    // }}}
    // {{{ function &getDBInstance()

    /**
     * Get the instance of MDB2 associated with the module instance
     *
     * @return  object  MDB2 instance or a MDB2 error on failure
     *
     * @access  public
     */
    function &getDBInstance()
    {
        if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
            $result =& $GLOBALS['_MDB2_databases'][$this->db_index];
        } else {
            $result =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'could not find MDB2 instance');
        }
        return $result;
    }

    // }}}
}

// }}}
// {{{ function MDB2_closeOpenTransactions()

/**
 * Close any open transactions form persistent connections
 *
 * @return  void
 *
 * @access  public
 */

function MDB2_closeOpenTransactions()
{
    reset($GLOBALS['_MDB2_databases']);
    while (next($GLOBALS['_MDB2_databases'])) {
        $key = key($GLOBALS['_MDB2_databases']);
        if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent
            && $GLOBALS['_MDB2_databases'][$key]->in_transaction
        ) {
            $GLOBALS['_MDB2_databases'][$key]->rollback();
        }
    }
}

// }}}
// {{{ function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null)

/**
 * default debug output handler
 *
 * @param   object  reference to an MDB2 database object
 * @param   string  usually the method name that triggered the debug call:
 *                  for example 'query', 'prepare', 'execute', 'parameters',
 *                  'beginTransaction', 'commit', 'rollback'
 * @param   string  message that should be appended to the debug variable
 * @param   array   contains context information about the debug() call
 *                  common keys are: is_manip, time, result etc.
 *
 * @return  void|string optionally return a modified message, this allows
 *                      rewriting a query before being issued or prepared
 *
 * @access  public
 */
function MDB2_defaultDebugOutput(&$db, $scope, $message, $context = array())
{
    $db->debug_output.= $scope.'('.$db->db_index.'): ';
    $db->debug_output.= $message.$db->getOption('log_line_break');
    return $message;
}

// }}}
?>
```

###**DB memo**

```php:
Last login: Thu Oct 20 22:55:00 on console
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:~ marimo$ cd /Applications/MAMP/Library/bin/
Marimo-no-MacBook-Air:bin marimo$ /mysql -u root
-bash: /mysql: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ myswl
-bash: myswl: command not found
Marimo-no-MacBook-Air:bin marimo$ ls
2to3				mysqldbcompare
Magick++-config			mysqldbcopy
Magick-config			mysqldbexport
MagickCore-config		mysqldbimport
MagickWand-config		mysqldiff
Wand-config			mysqldiskusage
a2p				mysqldump
ab				mysqldumpslow
animate				mysqlfailover
apachectl			mysqlfrm
apxs				mysqlhotcopy
autopoint			mysqlimport
bmp2tiff			mysqlindexcheck
c2ph				mysqlmetagrep
cgi-fcgi			mysqlprocgrep
checkgid			mysqlreplicate
cjpeg				mysqlrpladmin
compare				mysqlrplcheck
composite			mysqlrplshow
config_data			mysqlserverclone
conjure				mysqlserverinfo
convert				mysqlshow
corelist			mysqlslap
cpan				mysqltest
curl				mysqluc
curl-config			mysqluserclone
dbilogstrip			ngettext
dbiprof				nginxctl
dbiproxy			pal2rgb
dbmmanage			pcre-config
derb				pcregrep
display				pcretest
djpeg				pdf2dsc
dvipdf				pdf2ps
enc2xs				perl
envsubst			perl5.20.0
envvars-std_			perlbug
envvars_			perldoc
eps2eps				perlivp
fax2ps				perlthanks
fax2tiff			perror
find2perl			pf2afm
font2c				pfbtopfa
freetype-config			phpunit
genbrk				phpunit.phar
gencfu				piconv
gencnval			pkgdata
gendict				pl2pm
genrb				png-fix-itxt
gettext				pngfix
gettext.sh			pod2html
gettextize			pod2man
gif2tiff			pod2text
gs				pod2usage
gsbj				podchecker
gsdj				podselect
gsdj500				pphs
gslj				ppm2tiff
gslp				printafm
gsnd				prove
h2ph				ps2ascii
h2xs				ps2epsi
htcacheclean			ps2pdf
htdbm				ps2pdf12
htdigest			ps2pdf13
htpasswd			ps2pdf14
httpd				ps2pdfwr
httxt2dbm			ps2ps
iconv				ps2ps2
icu-config			psed
icuinfo				pstruct
identify			ptar
idle				ptardiff
idn				ptargrep
import				pydoc
innochecksum			python
instmodsh			python-config
jpegtran			python2
json_pp				python2-config
libmcrypt-config		python2.7
libnetcfg			python2.7-config
libpng-config			ras2tiff
libpng16-config			raw2tiff
libtool				rdjpgcom
libtoolize			recode-sr-latin
logresolve			replace
lprsetup.sh			resolve_stack_dump
makeconv			resolveip
mod_python			rgb2ycbcr
mogrify				rotatelogs
montage				s2p
mp2bug				sabcmd
msgattrib			sablot-config
msgcat				shasum
msgcmp				smtpd.py
msgcomm				spawn-fcgi
msgconv				splain
msgen				stream
msgexec				thumbnail
msgfilter			tiff2bw
msgfmt				tiff2pdf
msggrep				tiff2ps
msginit				tiff2rgba
msgmerge			tiffcmp
msgunfmt			tiffcp
msguniq				tiffcrop
msql2mysql			tiffdither
my_print_defaults		tiffdump
myisam_ftdump			tiffinfo
myisamchk			tiffmedian
myisamlog			tiffset
myisampack			tiffsplit
mysql				type1afm
mysql_client_test		uconv
mysql_config			unix-lpr.sh
mysql_convert_table_format	wftopfa
mysql_find_rows			wrjpgcom
mysql_fix_extensions		xgettext
mysql_plugin			xml2-config
mysql_secure_installation	xmlcatalog
mysql_setpermission		xmllint
mysql_tzinfo_to_sql		xmlwf
mysql_upgrade			xslt-config
mysql_waitpid			xsltproc
mysql_zap			xsubpp
mysqlaccess			yaz-asncomp
mysqlaccess.conf		yaz-client
mysqladmin			yaz-config
mysqlauditadmin			yaz-iconv
mysqlauditgrep			yaz-icu
mysqlbinlog			yaz-illclient
mysqlbug			yaz-json-parse
mysqlcheck			yaz-marcdump
mysqld				yaz-ztest
mysqld_multi			zipdetails
mysqld_safe			zoomsh
Marimo-no-MacBook-Air:bin marimo$ show databases
-bash: show: command not found
Marimo-no-MacBook-Air:bin marimo$ show databases;
-bash: show: command not found
Marimo-no-MacBook-Air:bin marimo$ cd /Applications/MAMP/Library/bin/
Marimo-no-MacBook-Air:bin marimo$ /mysql -u root -p
-bash: /mysql: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.5.38 Source distribution

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Cafe               |
| Englishwords       |
| Englishwords2      |
| mini_bbs           |
| myfavoriteshop     |
| mysql              |
| ourfavoriteshop    |
| ourfavoriteshop1   |
| performance_schema |
| slj                |
| tennis             |
| test01             |
| test01-index       |
+--------------------+
14 rows in set (0.01 sec)

mysql> use slj
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+---------------+
| Tables_in_slj |
+---------------+
| account       |
| article       |
| color_master  |
+---------------+
3 rows in set (0.00 sec)

mysql> desc account;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| user_id   | varchar(10) | NO   | PRI | NULL    |       |
| user_name | varchar(30) | NO   |     | NULL    |       |
| user_pass | char(8)     | NO   |     | NULL    |       |
| email     | varchar(30) | NO   |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql> desc article;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| article_id  | int(11)      | NO   | PRI | NULL    | auto_increment |
| create_date | datetime     | NO   |     | NULL    |                |
| name        | varchar(30)  | YES  |     | NULL    |                |
| email       | varchar(30)  | YES  |     | NULL    |                |
| title       | varchar(50)  | YES  |     | NULL    |                |
| text        | varchar(100) | NO   |     | NULL    |                |
| color_cd    | char(1)      | NO   |     | 0       |                |
| del_flg     | char(1)      | NO   |     | 0       |                |
+-------------+--------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

mysql> desc color_master;
+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| color_cd | char(1) | NO   | PRI | NULL    |       |
| color_nm | char(6) | NO   |     | NULL    |       |
+----------+---------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> use Cafe
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_cafe |
+----------------+
| Cafe_data      |
| Members        |
+----------------+
2 rows in set (0.00 sec)

mysql> desc Cafe_data
    -> desc Cafe_data;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc Cafe_data' at line 2
mysql> desc Cafe_data
    -> 
    -> desc Cafe_data;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc Cafe_data' at line 3
mysql> desc Cafe_data;
+------------------+--------------+------+-----+---------+----------------+
| Field            | Type         | Null | Key | Default | Extra          |
+------------------+--------------+------+-----+---------+----------------+
| CafeEnglish      | varchar(100) | NO   |     | NULL    |                |
| CafeJapanese     | varchar(100) | NO   |     | NULL    |                |
| CafeSignificance | varchar(100) | YES  |     | NULL    |                |
| ID               | int(100)     | NO   | PRI | NULL    | auto_increment |
+------------------+--------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

mysql> desc Members;
+----------+--------------+------+-----+-------------------+-----------------------------+
| Field    | Type         | Null | Key | Default           | Extra                       |
+----------+--------------+------+-----+-------------------+-----------------------------+
| id       | int(11)      | NO   | PRI | NULL              | auto_increment              |
| name     | varchar(255) | NO   |     | NULL              |                             |
| email    | varchar(255) | NO   |     | NULL              |                             |
| password | varchar(100) | NO   |     | NULL              |                             |
| picture  | varchar(255) | NO   |     | NULL              |                             |
| created  | datetime     | NO   |     | NULL              |                             |
| modified | timestamp    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+----------+--------------+------+-----+-------------------+-----------------------------+
7 rows in set (0.01 sec)

mysql> 
  [復元日時 2016/10/26 23:27:18]
Last login: Wed Oct 26 23:27:02 on console
Restored session: 2016年 10月21日 金曜日 00時48分17秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/10/27 23:21:21]
Last login: Thu Oct 27 23:21:10 on console
Restored session: 2016年 10月27日 木曜日 00時38分28秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/10/29 0:58:02]
Last login: Sat Oct 29 00:57:50 on console
Restored session: 2016年 10月27日 木曜日 23時37分14秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/01 0:15:14]
Last login: Tue Nov  1 00:14:51 on console
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/01 23:53:25]
Last login: Tue Nov  1 23:53:10 on console
Restored session: 2016年 11月 1日 火曜日 01時02分44秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/06 23:12:57]
Last login: Sun Nov  6 23:12:43 on console
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/13 4:07:57]
Last login: Sun Nov 13 04:07:43 on console
Restored session: 2016年 11月 6日 日曜日 23時28分51秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/15 0:00:52]
Last login: Tue Nov 15 00:00:42 on console
Restored session: 2016年 11月13日 日曜日 04時08分43秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/16 23:21:59]
Last login: Wed Nov 16 23:21:49 on console
Restored session: 2016年 11月15日 火曜日 00時01分07秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ heroku login
-bash: heroku: command not found
Marimo-no-MacBook-Air:bin marimo$ heroku login;
-bash: heroku: command not found
Marimo-no-MacBook-Air:bin marimo$ cd applications
-bash: cd: applications: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ ls
2to3				mysqldbcompare
Magick++-config			mysqldbcopy
Magick-config			mysqldbexport
MagickCore-config		mysqldbimport
MagickWand-config		mysqldiff
Wand-config			mysqldiskusage
a2p				mysqldump
ab				mysqldumpslow
animate				mysqlfailover
apachectl			mysqlfrm
apxs				mysqlhotcopy
autopoint			mysqlimport
bmp2tiff			mysqlindexcheck
c2ph				mysqlmetagrep
cgi-fcgi			mysqlprocgrep
checkgid			mysqlreplicate
cjpeg				mysqlrpladmin
compare				mysqlrplcheck
composite			mysqlrplshow
config_data			mysqlserverclone
conjure				mysqlserverinfo
convert				mysqlshow
corelist			mysqlslap
cpan				mysqltest
curl				mysqluc
curl-config			mysqluserclone
dbilogstrip			ngettext
dbiprof				nginxctl
dbiproxy			pal2rgb
dbmmanage			pcre-config
derb				pcregrep
display				pcretest
djpeg				pdf2dsc
dvipdf				pdf2ps
enc2xs				perl
envsubst			perl5.20.0
envvars-std_			perlbug
envvars_			perldoc
eps2eps				perlivp
fax2ps				perlthanks
fax2tiff			perror
find2perl			pf2afm
font2c				pfbtopfa
freetype-config			phpunit
genbrk				phpunit.phar
gencfu				piconv
gencnval			pkgdata
gendict				pl2pm
genrb				png-fix-itxt
gettext				pngfix
gettext.sh			pod2html
gettextize			pod2man
gif2tiff			pod2text
gs				pod2usage
gsbj				podchecker
gsdj				podselect
gsdj500				pphs
gslj				ppm2tiff
gslp				printafm
gsnd				prove
h2ph				ps2ascii
h2xs				ps2epsi
htcacheclean			ps2pdf
htdbm				ps2pdf12
htdigest			ps2pdf13
htpasswd			ps2pdf14
httpd				ps2pdfwr
httxt2dbm			ps2ps
iconv				ps2ps2
icu-config			psed
icuinfo				pstruct
identify			ptar
idle				ptardiff
idn				ptargrep
import				pydoc
innochecksum			python
instmodsh			python-config
jpegtran			python2
json_pp				python2-config
libmcrypt-config		python2.7
libnetcfg			python2.7-config
libpng-config			ras2tiff
libpng16-config			raw2tiff
libtool				rdjpgcom
libtoolize			recode-sr-latin
logresolve			replace
lprsetup.sh			resolve_stack_dump
makeconv			resolveip
mod_python			rgb2ycbcr
mogrify				rotatelogs
montage				s2p
mp2bug				sabcmd
msgattrib			sablot-config
msgcat				shasum
msgcmp				smtpd.py
msgcomm				spawn-fcgi
msgconv				splain
msgen				stream
msgexec				thumbnail
msgfilter			tiff2bw
msgfmt				tiff2pdf
msggrep				tiff2ps
msginit				tiff2rgba
msgmerge			tiffcmp
msgunfmt			tiffcp
msguniq				tiffcrop
msql2mysql			tiffdither
my_print_defaults		tiffdump
myisam_ftdump			tiffinfo
myisamchk			tiffmedian
myisamlog			tiffset
myisampack			tiffsplit
mysql				type1afm
mysql_client_test		uconv
mysql_config			unix-lpr.sh
mysql_convert_table_format	wftopfa
mysql_find_rows			wrjpgcom
mysql_fix_extensions		xgettext
mysql_plugin			xml2-config
mysql_secure_installation	xmlcatalog
mysql_setpermission		xmllint
mysql_tzinfo_to_sql		xmlwf
mysql_upgrade			xslt-config
mysql_waitpid			xsltproc
mysql_zap			xsubpp
mysqlaccess			yaz-asncomp
mysqlaccess.conf		yaz-client
mysqladmin			yaz-config
mysqlauditadmin			yaz-iconv
mysqlauditgrep			yaz-icu
mysqlbinlog			yaz-illclient
mysqlbug			yaz-json-parse
mysqlcheck			yaz-marcdump
mysqld				yaz-ztest
mysqld_multi			zipdetails
mysqld_safe			zoomsh
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/17 22:48:49]
Last login: Thu Nov 17 22:48:39 on console
Restored session: 2016年 11月17日 木曜日 00時25分04秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/11/25 0:17:22]
Last login: Fri Nov 25 00:17:11 on console
Restored session: 2016年 11月17日 木曜日 22時49分00秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2016/12/01 22:40:49]
Last login: Thu Dec  1 22:40:39 on console
Restored session: 2016年 11月25日 金曜日 00時32分57秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2017/03/19 5:10:06]
Last login: Sun Mar 19 04:58:43 on console
Restored session: 2016年 12月 2日 金曜日 00時50分18秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ mysql -u root -p
-bash: mysql: command not found
Marimo-no-MacBook-Air:bin marimo$ cd /Applications/MAMP/Library/bin/
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.5.38 Source distribution

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Cafe               |
| Englishwords       |
| Englishwords2      |
| mini_bbs           |
| myfavoriteshop     |
| mysql              |
| ourfavoriteshop    |
| ourfavoriteshop1   |
| performance_schema |
| slj                |
| tennis             |
| test01             |
| test01-index       |
+--------------------+
14 rows in set (0.00 sec)

mysql> show tables from mysql;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
24 rows in set (0.00 sec)

mysql> create table words(id int auto_increment primary key,word varchar(100),se 
    -> nse varchar(250),memo varchar(250));
ERROR 1046 (3D000): No database selected
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1046 (3D000): No database selected
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Cafe               |
| Englishwords       |
| Englishwords2      |
| mini_bbs           |
| myfavoriteshop     |
| mysql              |
| ourfavoriteshop    |
| ourfavoriteshop1   |
| performance_schema |
| slj                |
| tennis             |
| test01             |
| test01-index       |
+--------------------+
14 rows in set (0.00 sec)

mysql> show fields from test01;
ERROR 1146 (42S02): Table 'mysql.test01' doesn't exist
mysql> show fields from test01
    -> use test01;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'use test01' at line 2
mysql> show fields from test01 use test01;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'use test01' at line 1
mysql> use test01;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show fields from test01 use test01;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'use test01' at line 1
mysql> showt tables from test01;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'showt tables from test01' at line 1
mysql> use test01;
Database changed
mysql> show tables from test01;
+------------------+
| Tables_in_test01 |
+------------------+
| items            |
| my_items         |
+------------------+
2 rows in set (0.00 sec)

mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create database words;
Query OK, 1 row affected (0.01 sec)

mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> use words;
Database changed
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> createe table words(id int auto_increment primary key,word varchar(100),sense varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'createe table words(id int auto_increment primary key,word varchar(100),sense va' at line 1
mysql> createe table words(id int auto_increment primary key,word varchar(100),sense varchar(250),memo varchar(250);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'createe table words(id int auto_increment primary key,word varchar(100),sense va' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words (id int auto_increment primary key,word varchar(100),sense varchar(250),memo varchar(250));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into words values(null,'A','B','C');
Query OK, 1 row affected (0.01 sec)

mysql> select * from word;
ERROR 1146 (42S02): Table 'words.word' doesn't exist
mysql> select * from words;
+----+------+-------+------+
| id | word | sense | memo |
+----+------+-------+------+
|  1 | A    | B     | C    |
+----+------+-------+------+
1 row in set (0.00 sec)

mysql> 
  [復元日時 2017/03/20 3:55:09]
Last login: Mon Mar 20 03:54:59 on console
Restored session: 2017年 3月19日 日曜日 05時51分35秒 JST
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ 
  [復元日時 2017/03/20 14:14:05]
Last login: Mon Mar 20 13:48:51 on console
-bash: 0_29-b11-402.jdk/Contents/Home: No such file or directory
Marimo-no-MacBook-Air:bin marimo$ php version-
Could not open input file: version-
Marimo-no-MacBook-Air:bin marimo$ php -v
PHP 5.5.36 (cli) (built: May 29 2016 01:07:06) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
Marimo-no-MacBook-Air:bin marimo$ mysql -u root -p
-bash: mysql: command not found
Marimo-no-MacBook-Air:bin marimo$ cd /Applications/MAMP/Library/bin/
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.5.38 Source distribution

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW VARIABLES LIKE 'version%'
    -> SHOW VARIABLES LIKE 'version%';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW VARIABLES LIKE 'version%'' at line 2
mysql> SHOW VARIABLES LIKE 'version%';
+-------------------------+---------------------+
| Variable_name           | Value               |
+-------------------------+---------------------+
| version                 | 5.5.38              |
| version_comment         | Source distribution |
| version_compile_machine | i386                |
| version_compile_os      | osx10.6             |
+-------------------------+---------------------+
4 rows in set (0.01 sec)

mysql> ^DBye
Marimo-no-MacBook-Air:bin marimo$ mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306  -u nono -p 
-bash: mysql: command not found
Marimo-no-MacBook-Air:bin marimo$ ./my
my_print_defaults           mysqld_safe
myisam_ftdump               mysqldbcompare
myisamchk                   mysqldbcopy
myisamlog                   mysqldbexport
myisampack                  mysqldbimport
mysql                       mysqldiff
mysql_client_test           mysqldiskusage
mysql_config                mysqldump
mysql_convert_table_format  mysqldumpslow
mysql_find_rows             mysqlfailover
mysql_fix_extensions        mysqlfrm
mysql_plugin                mysqlhotcopy
mysql_secure_installation   mysqlimport
mysql_setpermission         mysqlindexcheck
mysql_tzinfo_to_sql         mysqlmetagrep
mysql_upgrade               mysqlprocgrep
mysql_waitpid               mysqlreplicate
mysql_zap                   mysqlrpladmin
mysqlaccess                 mysqlrplcheck
mysqlaccess.conf            mysqlrplshow
mysqladmin                  mysqlserverclone
mysqlauditadmin             mysqlserverinfo
mysqlauditgrep              mysqlshow
Marimo-no-MacBook-Air:bin marimo$ ./mysql
mysql                       mysqldbcopy
mysql_client_test           mysqldbexport
mysql_config                mysqldbimport
mysql_convert_table_format  mysqldiff
mysql_find_rows             mysqldiskusage
mysql_fix_extensions        mysqldump
mysql_plugin                mysqldumpslow
mysql_secure_installation   mysqlfailover
mysql_setpermission         mysqlfrm
mysql_tzinfo_to_sql         mysqlhotcopy
mysql_upgrade               mysqlimport
mysql_waitpid               mysqlindexcheck
mysql_zap                   mysqlmetagrep
mysqlaccess                 mysqlprocgrep
mysqlaccess.conf            mysqlreplicate
mysqladmin                  mysqlrpladmin
mysqlauditadmin             mysqlrplcheck
mysqlauditgrep              mysqlrplshow
mysqlbinlog                 mysqlserverclone
mysqlbug                    mysqlserverinfo
mysqlcheck                  mysqlshow
mysqld                      mysqlslap
mysqld_multi                mysqltest
Marimo-no-MacBook-Air:bin marimo$ ./mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306  -u nono -p
Enter password: 
ERROR 2005 (HY000): Unknown MySQL server host 'nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306' (0)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com -u nono -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'nono'@'106.171.74.98' (using password: YES)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306  -u nono -P 3306  -p 
Enter password: 
ERROR 2005 (HY000): Unknown MySQL server host 'nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306' (0)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306  -u nono  -p 
Enter password: 
ERROR 2005 (HY000): Unknown MySQL server host 'nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com:3306' (0)
Marimo-no-MacBook-Air:bin marimo$ ./mysql -h nonotest.cllelguzpkss.us-west-2.rds.amazonaws.com  -u nono -p 
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.5.53-log Source distribution

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| innodb             |
| mysql              |
| performance_schema |
| word               |
+--------------------+
5 rows in set (0.13 sec)

mysql> use word;
Database changed
mysql> create table words(id int auto_increment primary key,word varchar(100),se 
    -> nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 2
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nse varchar(250),memo varchar(250))' at line 1
mysql> create table words(id int auto_increment primary key,word varchar(100),se nse varchar(250),memo varchar(250)mysql> create table words(id int auto_increment primary key,word varchar(100),se
    -> create table words(id int auto_increment primary key,word varchar(100),sense varchar(250),memo varchar(250));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'create table words(id int auto_increment primary key,word varchar(100),sense var' at line 2
mysql> create table words(id int auto_increment primary key,word varchar(100),sense varchar(250),memo varchar(250));
Query OK, 0 rows affected (0.15 sec)

mysql> insert into words(null,'A','B','C');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'null,'A','B','C')' at line 1
mysql> insert into product values(null, 'A','B','C');
ERROR 1146 (42S02): Table 'word.product' doesn't exist
mysql> insert into words values(null, 'A','B','C');
Query OK, 1 row affected (0.14 sec)

mysql> select * from words;
+----+------+-------+------+
| id | word | sense | memo |
+----+------+-------+------+
|  1 | A    | B     | C    |
+----+------+-------+------+
1 row in set (0.13 sec)

mysql> grant select,insert,update,delete on word.* to worduser@172.31.19.131 identified by 'hiwoSh1o';
Query OK, 0 rows affected (0.13 sec)

mysql> 
```