alecpl
2008-05-02 d1403fd7268ccf96ab6e7d04506ea1b1802c7eb2
- fixed #1485032 and updated MDB2 package+drivers


29 files modified
2880 ■■■■ changed files
CHANGELOG 7 ●●●●● patch | view | raw | blame | history
program/lib/MDB2.php 46 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/Common.php 20 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/mssql.php 86 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/mysql.php 93 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/mysqli.php 92 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/pgsql.php 6 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Datatype/sqlite.php 5 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/Common.php 46 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/mssql.php 21 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/mysql.php 20 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/mysqli.php 20 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/pgsql.php 20 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Function/sqlite.php 41 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/Common.php 81 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/mssql.php 356 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/mysql.php 400 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/mysqli.php 403 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/pgsql.php 138 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Manager/sqlite.php 37 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Reverse/Common.php 4 ●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Reverse/mssql.php 2 ●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Reverse/pgsql.php 11 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/Reverse/sqlite.php 14 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/mssql.php 212 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/mysql.php 254 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/mysqli.php 298 ●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/pgsql.php 114 ●●●●● patch | view | raw | blame | history
program/lib/MDB2/Driver/sqlite.php 33 ●●●● patch | view | raw | blame | history
CHANGELOG
@@ -1,6 +1,13 @@
CHANGELOG RoundCube Webmail
---------------------------
2008/05/02 (alec)
----------
- Updated MDB2 package to version 2.5.0b1
- Updated MDB2 pgsql, mysql, mysqli, sqlite drivers to version 1.5.0b1
- Updated MDB2 mssql driver to version 1.3.0b1
- Fixed identities saving when using MDB2 pgsql driver (#1485032)
2008/05/01 (alec)
----------
- Fix BCC header reset (#1484997)
program/lib/MDB2.php
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: MDB2.php,v 1.307 2007/11/10 13:29:05 quipo Exp $
// $Id: MDB2.php,v 1.318 2008/03/08 14:18:38 quipo Exp $
//
/**
@@ -100,6 +100,8 @@
define('MDB2_ERROR_MANAGER_PARSE',      -33);
define('MDB2_ERROR_LOADMODULE',         -34);
define('MDB2_ERROR_INSUFFICIENT_DATA',  -35);
define('MDB2_ERROR_NO_PERMISSION',      -36);
// }}}
// {{{ Verbose constants
/**
@@ -564,7 +566,7 @@
     */
    function apiVersion()
    {
        return '2.5.0a2';
        return '2.5.0b1';
    }
    // }}}
@@ -764,6 +766,7 @@
                MDB2_ERROR_LOADMODULE         => 'error while including on demand module',
                MDB2_ERROR_TRUNCATED          => 'truncated',
                MDB2_ERROR_DEADLOCK           => 'deadlock detected',
                MDB2_ERROR_NO_PERMISSION      => 'no permission',
            );
        }
@@ -888,7 +891,7 @@
                //"username/password@[//]host[:port][/service_name]"
                //e.g. "scott/tiger@//mymachine:1521/oracle"
                $proto_opts = $dsn;
                $dsn = null;
                $dsn = substr($proto_opts, strrpos($proto_opts, '/') + 1);
            } elseif (strpos($dsn, '/') !== false) {
                list($proto_opts, $dsn) = explode('/', $dsn, 2);
            } else {
@@ -1095,6 +1098,7 @@
        'LOBs' => false,
        'replace' => false,
        'sub_selects' => false,
        'triggers' => false,
        'auto_increment' => false,
        'primary_key' => false,
        'result_introspection' => false,
@@ -1142,6 +1146,7 @@
     *  <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>
     *  <li>$options['bindname_format'] -> string: regular expression pattern for named parameters
     *  <li>$options['max_identifiers_length'] -> integer: max identifier length</li>
     * </ul>
     *
     * @var     array
@@ -1190,6 +1195,7 @@
        'nativetype_map_callback' => array(),
        'lob_allow_url_include' => false,
        'bindname_format' => '(?:\d+)|(?:[a-zA-Z][a-zA-Z0-9_]*)',
        'max_identifiers_length' => 30,
    );
    /**
@@ -2219,6 +2225,23 @@
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }
    // }}}
    // {{{ setCharset($charset, $connection = null)
    /**
@@ -2277,7 +2300,9 @@
    {
        $previous_database_name = (isset($this->database_name)) ? $this->database_name : '';
        $this->database_name = $name;
        if (!empty($this->connected_database_name) && ($this->connected_database_name != $this->database_name)) {
        $this->disconnect(false);
        }
        return $previous_database_name;
    }
@@ -2795,7 +2820,7 @@
                    return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
                        'key value '.$name.' may not be NULL', __FUNCTION__);
                }
                $condition[] = $name . '=' . $value;
                $condition[] = $this->quoteIdentifier($name, true) . '=' . $value;
            }
        }
        if (empty($condition)) {
@@ -2815,13 +2840,16 @@
        }
        $condition = ' WHERE '.implode(' AND ', $condition);
        $query = "DELETE FROM $table$condition";
        $query = 'DELETE FROM ' . $this->quoteIdentifier($table, true) . $condition;
        $result =& $this->_doQuery($query, true, $connection);
        if (!PEAR::isError($result)) {
            $affected_rows = $this->_affectedRows($connection, $result);
            $insert = implode(', ', array_keys($values));
            $insert = '';
            foreach ($values as $key => $value) {
                $insert .= ($insert?', ':'') . $this->quoteIdentifier($key, true);
            }
            $values = implode(', ', $values);
            $query = "INSERT INTO $table ($insert) VALUES ($values)";
            $query = 'INSERT INTO '. $this->quoteIdentifier($table, true) . "($insert) VALUES ($values)";
            $result =& $this->_doQuery($query, true, $connection);
            if (!PEAR::isError($result)) {
                $affected_rows += $this->_affectedRows($connection, $result);;
@@ -2998,7 +3026,7 @@
                                return $err;
                            }
                        }
                    } while ($ignore['escape'] && $query[($end_quote - 1)] == $ignore['escape']);
                    } while ($ignore['escape'] && $query[($end_quote - 1)] == $ignore['escape'] && $end_quote-1 != $start_quote);
                    $position = $end_quote + 1;
                    return $position;
                }
@@ -3980,9 +4008,11 @@
        $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
        $parameters = array_keys($values);
        foreach ($parameters as $key => $parameter) {
            $this->db->pushErrorHandling(PEAR_ERROR_RETURN);
            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
            $err = $this->bindValue($parameter, $values[$parameter], $types[$key]);
            $this->db->popExpect();
            $this->db->popErrorHandling();
            if (PEAR::isError($err)) {
                if ($err->getCode() == MDB2_ERROR_NOT_FOUND) {
                    //ignore (extra value for missing placeholder)
program/lib/MDB2/Driver/Datatype/Common.php
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.128 2007/11/09 20:54:58 quipo Exp $
// $Id: Common.php,v 1.137 2008/02/17 18:53:40 afz Exp $
require_once 'MDB2/LOB.php';
@@ -497,6 +497,7 @@
        $charset = empty($field['charset']) ? '' :
            ' '.$this->_getCharsetFieldDeclaration($field['charset']);
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        $default = '';
        if (array_key_exists('default', $field)) {
            if ($field['default'] === '') {
@@ -504,27 +505,20 @@
                if (PEAR::isError($db)) {
                    return $db;
                }
                if (empty($field['notnull'])) {
                    $field['default'] = null;
                } else {
                    $valid_default_values = $this->getValidTypes();
                    $field['default'] = $valid_default_values[$field['type']];
                }
                if ($field['default'] === ''
                    && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
                ) {
                if ($field['default'] === ''&& ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) {
                    $field['default'] = ' ';
                }
            }
            if (!is_null($field['default'])) {
            $default = ' DEFAULT '.$this->quote($field['default'], $field['type']);
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        }
        
        $collation = empty($field['collation']) ? '' :
            ' '.$this->_getCollationFieldDeclaration($field['collation']);
        return $charset.$default.$notnull.$collation;
    }
@@ -1490,7 +1484,7 @@
    {
        $value = (string)$value;
        $value = preg_replace('/[^\d\.,\-+eE]/', '', $value);
        if (preg_match('/[^.0-9]/', $value)) {
        if (preg_match('/[^\.\d]/', $value)) {
            if (strpos($value, ',')) {
                // 1000,00
                if (!strpos($value, '.')) {
program/lib/MDB2/Driver/Datatype/mssql.php
@@ -44,7 +44,7 @@
// |          Daniel Convissor <danielc@php.net>                          |
// +----------------------------------------------------------------------+
//
// $Id: mssql.php,v 1.59 2007/12/03 20:59:50 quipo Exp $
// $Id: mssql.php,v 1.65 2008/02/19 14:54:17 afz Exp $
//
require_once 'MDB2/Driver/Datatype/Common.php';
@@ -185,68 +185,6 @@
    }
    // }}}
    // {{{ _getDeclaration()
    /**
     * Obtain DBMS specific SQL code portion needed to declare a generic type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string $name   name the field to be declared.
     * @param array  $field  associative array with the name of the properties
     *      of the field being declared as array indexes. Currently, the types
     *      of supported field properties are as follows:
     *
     *      length
     *          Integer value that determines the maximum length of the text
     *          field. If this argument is missing the field should be
     *          declared to have the longest length allowed by the DBMS.
     *
     *      default
     *          Text value to be used as default for this field.
     *
     *      notnull
     *          Boolean flag that indicates whether this field is constrained
     *          to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *      declare the specified field.
     * @access protected
     */
    function _getDeclarationOptions($field)
    {
        $charset = empty($field['charset']) ? '' :
            ' '.$this->_getCharsetFieldDeclaration($field['charset']);
        $default = '';
        if (array_key_exists('default', $field)) {
            if ($field['default'] === '') {
                $db =& $this->getDBInstance();
                if (PEAR::isError($db)) {
                    return $db;
                }
                $field['default'] = empty($field['notnull'])
                    ? null : $this->valid_default_values[$field['type']];
                if ($field['default'] === ''
                    && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
                ) {
                    $field['default'] = ' ';
                }
            }
            $default = ' DEFAULT '.$this->quote($field['default'], $field['type']);
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
        $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
        if ($default == ' DEFAULT NULL' && $notnull == ' NULL') {
            $notnull = '';
        }
        $collation = empty($field['collation']) ? '' :
            ' '.$this->_getCollationFieldDeclaration($field['collation']);
        return $charset.$default.$notnull.$collation;
    }
    // }}}
    // {{{ _getIntegerDeclaration()
    /**
@@ -282,27 +220,27 @@
            return $db;
        }
        $default = $autoinc = '';;
        $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
        $default = $autoinc = '';
        if (!empty($field['autoincrement'])) {
            $autoinc = ' IDENTITY PRIMARY KEY';
        } elseif (array_key_exists('default', $field)) {
            if ($field['default'] === '') {
                $field['default'] = empty($field['notnull']) ? null : 0;
                $field['default'] = 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
            if (is_null($field['default'])) {
                $default = ' DEFAULT (null)';
            } else {
                $default = ' DEFAULT (' . $this->quote($field['default'], 'integer') . ')';
            }
        }
        $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
        if ($default == ' DEFAULT NULL' && $notnull == ' NULL') {
            $notnull = '';
        }
        if (!empty($field['unsigned'])) {
            $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
        }
        $name = $db->quoteIdentifier($name, true);
        return $name.' '.$this->getTypeDeclaration($field).$default.$notnull.$autoinc;
        return $name.' '.$this->getTypeDeclaration($field).$notnull.$default.$autoinc;
    }
    // }}}
@@ -396,7 +334,7 @@
        if (!$quote) {
            return $value;
        }
        $value = bin2hex("0x".$this->_readFile($value));
        $value = '0x'.bin2hex($this->_readFile($value));
        return $value;
    }
program/lib/MDB2/Driver/Datatype/mysql.php
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.62 2007/11/09 20:54:58 quipo Exp $
// $Id: mysql.php,v 1.65 2008/02/22 19:23:49 quipo Exp $
//
require_once 'MDB2/Driver/Datatype/Common.php';
@@ -232,6 +232,93 @@
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        }
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
        $name = $db->quoteIdentifier($name, true);
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
    }
    // }}}
    // {{{ _getFloatDeclaration()
    /**
     * Obtain DBMS specific SQL code portion needed to declare an float type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string  $name   name the field to be declared.
     * @param string  $field  associative array with the name of the properties
     *                        of the field being declared as array indexes.
     *                        Currently, the types of supported field
     *                        properties are as follows:
     *
     *                       unsigned
     *                        Boolean flag that indicates whether the field
     *                        should be declared as unsigned float if
     *                        possible.
     *
     *                       default
     *                        float value to be used as default for this
     *                        field.
     *
     *                       notnull
     *                        Boolean flag that indicates whether this field is
     *                        constrained to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     * @access protected
     */
    function _getFloatDeclaration($name, $field)
    {
        // Since AUTO_INCREMENT can be used for integer or floating-point types,
        // reuse the INTEGER declaration
        // @see http://bugs.mysql.com/bug.php?id=31032
        return $this->_getIntegerDeclaration($name, $field);
    }
    // }}}
    // {{{ _getDecimalDeclaration()
    /**
     * Obtain DBMS specific SQL code portion needed to declare an decimal type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string  $name   name the field to be declared.
     * @param string  $field  associative array with the name of the properties
     *                        of the field being declared as array indexes.
     *                        Currently, the types of supported field
     *                        properties are as follows:
     *
     *                       unsigned
     *                        Boolean flag that indicates whether the field
     *                        should be declared as unsigned integer if
     *                        possible.
     *
     *                       default
     *                        Decimal value to be used as default for this
     *                        field.
     *
     *                       notnull
     *                        Boolean flag that indicates whether this field is
     *                        constrained to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     * @access protected
     */
    function _getDecimalDeclaration($name, $field)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $default = '';
        if (array_key_exists('default', $field)) {
            if ($field['default'] === '') {
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
@@ -239,7 +326,7 @@
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
        $name = $db->quoteIdentifier($name, true);
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull;
    }
    // }}}
program/lib/MDB2/Driver/Datatype/mysqli.php
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysqli.php,v 1.61 2007/11/09 20:54:58 quipo Exp $
// $Id: mysqli.php,v 1.63 2008/02/22 19:23:49 quipo Exp $
//
require_once 'MDB2/Driver/Datatype/Common.php';
@@ -232,6 +232,93 @@
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        }
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
        $name = $db->quoteIdentifier($name, true);
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
    }
    // }}}
    // {{{ _getFloatDeclaration()
    /**
     * Obtain DBMS specific SQL code portion needed to declare an float type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string  $name   name the field to be declared.
     * @param string  $field  associative array with the name of the properties
     *                        of the field being declared as array indexes.
     *                        Currently, the types of supported field
     *                        properties are as follows:
     *
     *                       unsigned
     *                        Boolean flag that indicates whether the field
     *                        should be declared as unsigned float if
     *                        possible.
     *
     *                       default
     *                        float value to be used as default for this
     *                        field.
     *
     *                       notnull
     *                        Boolean flag that indicates whether this field is
     *                        constrained to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     * @access protected
     */
    function _getFloatDeclaration($name, $field)
    {
        // Since AUTO_INCREMENT can be used for integer or floating-point types,
        // reuse the INTEGER declaration
        // @see http://bugs.mysql.com/bug.php?id=31032
        return $this->_getIntegerDeclaration($name, $field);
    }
    // }}}
    // {{{ _getDecimalDeclaration()
    /**
     * Obtain DBMS specific SQL code portion needed to declare an decimal type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string  $name   name the field to be declared.
     * @param string  $field  associative array with the name of the properties
     *                        of the field being declared as array indexes.
     *                        Currently, the types of supported field
     *                        properties are as follows:
     *
     *                       unsigned
     *                        Boolean flag that indicates whether the field
     *                        should be declared as unsigned integer if
     *                        possible.
     *
     *                       default
     *                        Decimal value to be used as default for this
     *                        field.
     *
     *                       notnull
     *                        Boolean flag that indicates whether this field is
     *                        constrained to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     * @access protected
     */
    function _getDecimalDeclaration($name, $field)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $default = '';
        if (array_key_exists('default', $field)) {
            if ($field['default'] === '') {
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
@@ -239,7 +326,7 @@
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
        $name = $db->quoteIdentifier($name, true);
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull;
    }
    // }}}
@@ -355,7 +442,6 @@
        case 'tinytext':
        case 'mediumtext':
        case 'longtext':
        case 'text':
        case 'text':
        case 'varchar':
            $fixed = false;
program/lib/MDB2/Driver/Datatype/pgsql.php
@@ -42,7 +42,7 @@
// | Author: Paul Cooper <pgc@ucecom.com>                                 |
// +----------------------------------------------------------------------+
//
// $Id: pgsql.php,v 1.88 2007/11/09 20:54:58 quipo Exp $
// $Id: pgsql.php,v 1.91 2008/03/09 12:28:08 quipo Exp $
require_once 'MDB2/Driver/Datatype/Common.php';
@@ -217,8 +217,6 @@
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
@@ -453,6 +451,7 @@
            break;
        case 'datetime':
        case 'timestamp':
        case 'timestamptz':
            $type[] = 'timestamp';
            $length = null;
            break;
@@ -461,6 +460,7 @@
            $length = null;
            break;
        case 'float':
        case 'float4':
        case 'float8':
        case 'double':
        case 'real':
program/lib/MDB2/Driver/Datatype/sqlite.php
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: sqlite.php,v 1.65 2007/12/03 20:59:51 quipo Exp $
// $Id: sqlite.php,v 1.67 2008/02/22 19:58:06 quipo Exp $
//
require_once 'MDB2/Driver/Datatype/Common.php';
@@ -212,8 +212,6 @@
                $field['default'] = empty($field['notnull']) ? null : 0;
            }
            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
        } elseif (empty($field['notnull'])) {
            $default = ' DEFAULT NULL';
        }
        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
@@ -394,7 +392,6 @@
            if (PEAR::isError($db)) {
                return $db;
            }
            return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                'unknown database attribute type: '.$db_type, __FUNCTION__);
        }
program/lib/MDB2/Driver/Function/Common.php
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.19 2007/09/09 13:47:36 quipo Exp $
// $Id: Common.php,v 1.21 2008/02/17 18:51:39 quipo Exp $
//
/**
@@ -74,6 +74,7 @@
     *                        the result set
     * @param mixed $result_class string which specifies which result class to use
     * @param mixed $result_wrap_class string which specifies which class to wrap results in
     *
     * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
@@ -113,6 +114,8 @@
     * - CURRENT_DATE (date, DATE type)
     * - CURRENT_TIME (time, TIME type)
     *
     * @param string $type 'timestamp' | 'time' | 'date'
     *
     * @return string to call a variable with the current timestamp
     * @access public
     */
@@ -127,6 +130,29 @@
        default:
            return 'CURRENT_TIMESTAMP';
        }
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
        return $error;
    }
    // }}}
@@ -147,6 +173,20 @@
    }
    // }}}
    // {{{ replace()
    /**
     * return string to call a function to get replace inside an SQL statement.
     *
     * @return string to call a function to get a replace
     * @access public
     */
    function replace($str, $from_str, $to_str)
    {
        return "REPLACE($str, $from_str , $to_str)";
    }
    // }}}
    // {{{ concat()
    /**
@@ -155,6 +195,7 @@
     * @param string $value1
     * @param string $value2
     * @param string $values...
     *
     * @return string to concatenate two strings
     * @access public
     */
@@ -185,6 +226,7 @@
     * return string to call a function to lower the case of an expression
     *
     * @param string $expression
     *
     * @return return string to lower case of an expression
     * @access public
     */
@@ -200,6 +242,7 @@
     * return string to call a function to upper the case of an expression
     *
     * @param string $expression
     *
     * @return return string to upper case of an expression
     * @access public
     */
@@ -215,6 +258,7 @@
     * return string to call a function to get the length of a string expression
     *
     * @param string $expression
     *
     * @return return string to get the string expression length
     * @access public
     */
program/lib/MDB2/Driver/Function/mssql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Frank M. Kromann <frank@kromann.info>                        |
// +----------------------------------------------------------------------+
//
// $Id: mssql.php,v 1.15 2007/08/11 16:02:22 quipo Exp $
// $Id: mssql.php,v 1.16 2008/02/17 18:54:08 quipo Exp $
//
require_once 'MDB2/Driver/Function/Common.php';
@@ -57,7 +57,6 @@
 */
class MDB2_Driver_Function_mssql extends MDB2_Driver_Function_Common
{
     // }}}
    // {{{ executeStoredProc()
    /**
@@ -109,6 +108,22 @@
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        return 'DATEDIFF(second, \'19700101\', '. $expression.') + DATEDIFF(second, GETDATE(), GETUTCDATE())';
    }
    // }}}
    // {{{ substring()
    /**
program/lib/MDB2/Driver/Function/mysql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.11 2007/01/12 11:29:12 quipo Exp $
// $Id: mysql.php,v 1.12 2008/02/17 18:54:08 quipo Exp $
//
require_once 'MDB2/Driver/Function/Common.php';
@@ -84,6 +84,22 @@
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        return 'UNIX_TIMESTAMP('. $expression.')';
    }
    // }}}
    // {{{ concat()
    /**
program/lib/MDB2/Driver/Function/mysqli.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysqli.php,v 1.13 2007/01/12 11:29:12 quipo Exp $
// $Id: mysqli.php,v 1.14 2008/02/17 18:54:08 quipo Exp $
//
require_once 'MDB2/Driver/Function/Common.php';
@@ -92,6 +92,22 @@
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        return 'UNIX_TIMESTAMP('. $expression.')';
    }
    // }}}
    // {{{ concat()
    /**
program/lib/MDB2/Driver/Function/pgsql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Paul Cooper <pgc@ucecom.com>                                 |
// +----------------------------------------------------------------------+
//
// $Id: pgsql.php,v 1.9 2006/06/12 21:48:43 lsmith Exp $
// $Id: pgsql.php,v 1.10 2008/02/17 18:54:08 quipo Exp $
require_once 'MDB2/Driver/Function/Common.php';
@@ -81,6 +81,22 @@
        return $db->query($query, $types, $result_class, $result_wrap_class);
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        return 'EXTRACT(EPOCH FROM DATE_TRUNC(\'seconds\', TIMESTAMP '. $expression.'))';
    }
    // }}}
    // {{{ random()
    /**
program/lib/MDB2/Driver/Function/sqlite.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: sqlite.php,v 1.8 2006/06/13 22:55:55 lsmith Exp $
// $Id: sqlite.php,v 1.10 2008/02/17 18:54:08 quipo Exp $
//
require_once 'MDB2/Driver/Function/Common.php';
@@ -90,6 +90,22 @@
    }
    // }}}
    // {{{ unixtimestamp()
    /**
     * return string to call a function to get the unix timestamp from a iso timestamp
     *
     * @param string $expression
     *
     * @return string to call a variable with the timestamp
     * @access public
     */
    function unixtimestamp($expression)
    {
        return 'strftime("%s",'. $expression.', "utc")';
    }
    // }}}
    // {{{ substring()
    /**
@@ -121,5 +137,26 @@
    }
    // }}}
    // {{{ replace()
    /**
     * return string to call a function to get a replacement inside an SQL statement.
     *
     * @return string to call a function to get a replace
     * @access public
     */
    function replace($str, $from_str, $to_str)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
        return $error;
    }
    // }}}
}
?>
program/lib/MDB2/Driver/Manager/Common.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -39,16 +39,18 @@
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
// | POSSIBILITY OF SUCH DAMAGE.                                          |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// | Authors: Lukas Smith <smith@pooteeweet.org>                          |
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.68 2007/12/03 20:59:15 quipo Exp $
// $Id: Common.php,v 1.71 2008/02/12 23:12:27 quipo Exp $
//
/**
 * @package  MDB2
 * @category Database
 * @author   Lukas Smith <smith@pooteeweet.org>
 * @author   Lorenzo Alberton <l.alberton@quipo.it>
 */
/**
@@ -188,6 +190,29 @@
     * @access public
     */
    function createDatabase($database, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }
    // }}}
    // {{{ alterDatabase()
    /**
     * alter an existing database
     *
     * @param string $name    name of the database that should be created
     * @param array  $options array with charset, collation info
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function alterDatabase($database, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
@@ -360,6 +385,56 @@
    }
    // }}}
    // {{{ truncateTable()
    /**
     * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
     * it falls back to a DELETE FROM TABLE query)
     *
     * @param string $name name of the table that should be truncated
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function truncateTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("DELETE FROM $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
            'method not implemented', __FUNCTION__);
    }
    // }}}
    // {{{ alterTable()
    /**
program/lib/MDB2/Driver/Manager/mssql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -44,7 +44,7 @@
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: mssql.php,v 1.93 2007/12/03 20:59:15 quipo Exp $
// $Id: mssql.php,v 1.109 2008/03/05 12:55:57 afz Exp $
//
require_once 'MDB2/Driver/Manager/Common.php';
@@ -90,6 +90,39 @@
            $query .= ' COLLATE ' . $options['collation'];
        }
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
    // {{{ alterDatabase()
    /**
     * alter an existing database
     *
     * @param string $name    name of the database that is intended to be changed
     * @param array  $options array with name, collation info
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function alterDatabase($name, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = '';
        if (!empty($options['name'])) {
            $query .= ' MODIFY NAME = ' .$db->quoteIdentifier($options['name'], true);
        }
        if (!empty($options['collation'])) {
            $query .= ' COLLATE ' . $options['collation'];
        }
        if (!empty($query)) {
            $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true) . $query;
            return $db->standaloneQuery($query, null, true);
        }
        return MDB2_OK;
    }
    // }}}
@@ -200,6 +233,64 @@
    }
    // }}}
    // {{{ truncateTable()
    /**
     * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
     * it falls back to a DELETE FROM TABLE query)
     *
     * @param string $name name of the table that should be truncated
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function truncateTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("TRUNCATE TABLE $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * NB: you have to run the NSControl Create utility to enable VACUUM
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $timeout = isset($options['timeout']) ? (int)$options['timeout'] : 300;
        $query = 'NSControl Create';
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        }
        return $db->exec('EXEC NSVacuum '.$timeout);
    }
    // }}}
    // {{{ alterTable()
    /**
@@ -298,16 +389,16 @@
        if (PEAR::isError($db)) {
            return $db;
        }
        $name_quoted = $db->quoteIdentifier($name, true);
        foreach ($changes as $change_name => $change) {
            switch ($change_name) {
            case 'add':
                break;
            case 'remove':
                break;
            case 'name':
            case 'rename':
            case 'add':
            case 'change':
            case 'name':
                break;
            default:
                return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
                    'change type "'.$change_name.'" not yet supported', __FUNCTION__);
@@ -318,34 +409,257 @@
            return MDB2_OK;
        }
        $query = '';
        if (!empty($changes['add']) && is_array($changes['add'])) {
            foreach ($changes['add'] as $field_name => $field) {
                if ($query) {
                    $query.= ', ';
                } else {
                    $query.= 'ADD COLUMN ';
                }
                $query.= $db->getDeclaration($field['type'], $field_name, $field);
            }
        }
        $idxname_format = $db->getOption('idxname_format');
        $db->setOption('idxname_format', '%s');
        if (!empty($changes['remove']) && is_array($changes['remove'])) {
            $result = $this->_dropConflictingIndices($name, array_keys($changes['remove']));
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
            $result = $this->_dropConflictingConstraints($name, array_keys($changes['remove']));
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
            $query = '';
            foreach ($changes['remove'] as $field_name => $field) {
                if ($query) {
                    $query.= ', ';
                }
                $field_name = $db->quoteIdentifier($field_name, true);
                $query.= 'DROP COLUMN ' . $field_name;
                $query.= 'COLUMN ' . $field_name;
            }
            $result = $db->exec("ALTER TABLE $name_quoted DROP $query");
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
        }
        if (!$query) {
        if (!empty($changes['rename']) && is_array($changes['rename'])) {
            foreach ($changes['rename'] as $field_name => $field) {
                $field_name = $db->quoteIdentifier($field_name, true);
                $result = $db->exec("sp_rename '$name_quoted.$field_name', '".$field['name']."', 'COLUMN'");
                if (PEAR::isError($result)) {
                    $db->setOption('idxname_format', $idxname_format);
                    return $result;
                }
            }
        }
        if (!empty($changes['add']) && is_array($changes['add'])) {
            $query = '';
            foreach ($changes['add'] as $field_name => $field) {
                if ($query) {
                    $query.= ', ';
                } else {
                    $query.= 'ADD ';
                }
                $query.= $db->getDeclaration($field['type'], $field_name, $field);
            }
            $result = $db->exec("ALTER TABLE $name_quoted $query");
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
        }
        $dropped_indices     = array();
        $dropped_constraints = array();
        if (!empty($changes['change']) && is_array($changes['change'])) {
            $dropped = $this->_dropConflictingIndices($name, array_keys($changes['change']));
            if (PEAR::isError($dropped)) {
                $db->setOption('idxname_format', $idxname_format);
                return $dropped;
            }
            $dropped_indices = array_merge($dropped_indices, $dropped);
            $dropped = $this->_dropConflictingConstraints($name, array_keys($changes['change']));
            if (PEAR::isError($dropped)) {
                $db->setOption('idxname_format', $idxname_format);
                return $dropped;
            }
            $dropped_constraints = array_merge($dropped_constraints, $dropped);
            foreach ($changes['change'] as $field_name => $field) {
                //MSSQL doesn't allow multiple ALTER COLUMNs in one query
                $query = 'ALTER COLUMN ';
                //MSSQL doesn't allow changing the DEFAULT value of a field in altering mode
                if (array_key_exists('default', $field['definition'])) {
                    unset($field['definition']['default']);
                }
                $query .= $db->getDeclaration($field['definition']['type'], $field_name, $field['definition']);
                $result = $db->exec("ALTER TABLE $name_quoted $query");
                if (PEAR::isError($result)) {
                    $db->setOption('idxname_format', $idxname_format);
                    return $result;
                }
            }
        }
        // restore the dropped conflicting indices and constraints
        foreach ($dropped_indices as $index_name => $index) {
            $result = $this->createIndex($name, $index_name, $index);
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
        }
        foreach ($dropped_constraints as $constraint_name => $constraint) {
            $result = $this->createConstraint($name, $constraint_name, $constraint);
            if (PEAR::isError($result)) {
                $db->setOption('idxname_format', $idxname_format);
                return $result;
            }
        }
        $db->setOption('idxname_format', $idxname_format);
        if (!empty($changes['name'])) {
            $new_name = $db->quoteIdentifier($changes['name'], true);
            $result = $db->exec("sp_rename '$name_quoted', '$new_name'");
            if (PEAR::isError($result)) {
                return $result;
            }
        }
            return MDB2_OK;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("ALTER TABLE $name $query");
    // }}}
    // {{{ _dropConflictingIndices()
    /**
     * Drop the indices that prevent a successful ALTER TABLE action
     *
     * @param string $table  table name
     * @param array  $fields array of names of the fields affected by the change
     *
     * @return array dropped indices definitions
     */
    function _dropConflictingIndices($table, $fields)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $dropped = array();
        $index_names = $this->listTableIndexes($table);
        if (PEAR::isError($index_names)) {
            return $index_names;
        }
        $db->loadModule('Reverse');
        $indexes = array();
        foreach ($index_names as $index_name) {
            $idx_def = $db->reverse->getTableIndexDefinition($table, $index_name);
            if (!PEAR::isError($idx_def)) {
                $indexes[$index_name] = $idx_def;
            }
        }
        foreach ($fields as $field_name) {
            foreach ($indexes as $index_name => $index) {
                if (!isset($dropped[$index_name]) && array_key_exists($field_name, $index['fields'])) {
                    $dropped[$index_name] = $index;
                    $result = $this->dropIndex($table, $index_name);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        return $dropped;
    }
    // }}}
    // {{{ _dropConflictingConstraints()
    /**
     * Drop the constraints that prevent a successful ALTER TABLE action
     *
     * @param string $table  table name
     * @param array  $fields array of names of the fields affected by the change
     *
     * @return array dropped constraints definitions
     */
    function _dropConflictingConstraints($table, $fields)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $dropped = array();
        $constraint_names = $this->listTableConstraints($table);
        if (PEAR::isError($constraint_names)) {
            return $constraint_names;
        }
        $db->loadModule('Reverse');
        $constraints = array();
        foreach ($constraint_names as $constraint_name) {
            $cons_def = $db->reverse->getTableConstraintDefinition($table, $constraint_name);
            if (!PEAR::isError($cons_def)) {
                $constraints[$constraint_name] = $cons_def;
            }
        }
        foreach ($fields as $field_name) {
            foreach ($constraints as $constraint_name => $constraint) {
                if (!isset($dropped[$constraint_name]) && array_key_exists($field_name, $constraint['fields'])) {
                    $dropped[$constraint_name] = $constraint;
                    $result = $this->dropConstraint($table, $constraint_name);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
            // also drop implicit DEFAULT constraints
            $default = $this->_getTableFieldDefaultConstraint($table, $field_name);
            if (!PEAR::isError($default) && !empty($default)) {
                $result = $this->dropConstraint($table, $default);
                if (PEAR::isError($result)) {
                    return $result;
                }
            }
        }
        return $dropped;
    }
    // }}}
    // {{{ _getTableFieldDefaultConstraint()
    /**
     * Get the default constraint for a table field
     *
     * @param string $table name of table that should be used in method
     * @param string $field name of field that should be used in method
     *
     * @return mixed name of default constraint on success, a MDB2 error on failure
     * @access private
     */
    function _getTableFieldDefaultConstraint($table, $field)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $table = $db->quoteIdentifier($table, true);
        $field = $db->quote($field, 'text');
        $query = "SELECT OBJECT_NAME(syscolumns.cdefault)
                    FROM syscolumns
                   WHERE syscolumns.id = object_id('$table')
                     AND syscolumns.name = $field
                     AND syscolumns.cdefault <> 0";
        return $db->queryOne($query);
    }
    // }}}
program/lib/MDB2/Driver/Manager/mysql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.100 2007/12/03 20:59:15 quipo Exp $
// $Id: mysql.php,v 1.108 2008/03/11 19:58:12 quipo Exp $
//
require_once 'MDB2/Driver/Manager/Common.php';
@@ -79,16 +79,41 @@
        $name  = $db->quoteIdentifier($name, true);
        $query = 'CREATE DATABASE ' . $name;
        if (!empty($options['charset'])) {
            $query .= ' DEFAULT CHARACTER SET ' . $options['charset'];
            $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
        }
        if (!empty($options['collation'])) {
            $query .= ' COLLATE ' . $options['collation'];
            $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
        }
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        return $db->standaloneQuery($query, null, true);
        }
        return MDB2_OK;
    // }}}
    // {{{ alterDatabase()
    /**
     * alter an existing database
     *
     * @param string $name    name of the database that is intended to be changed
     * @param array  $options array with charset, collation info
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function alterDatabase($name, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true);
        if (!empty($options['charset'])) {
            $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
        }
        if (!empty($options['collation'])) {
            $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
        }
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
@@ -110,11 +135,7 @@
        $name = $db->quoteIdentifier($name, true);
        $query = "DROP DATABASE $name";
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        }
        return MDB2_OK;
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
@@ -188,9 +209,35 @@
            return $db;
        }
        // if we have an AUTO_INCREMENT column and a PK on more than one field,
        // we have to handle it differently...
        $autoincrement = null;
        if (empty($options['primary'])) {
            $pk_fields = array();
            foreach ($fields as $fieldname => $def) {
                if (!empty($def['primary'])) {
                    $pk_fields[$fieldname] = true;
                }
                if (!empty($def['autoincrement'])) {
                    $autoincrement = $fieldname;
                }
            }
            if (!is_null($autoincrement) && count($pk_fields) > 1) {
                $options['primary'] = $pk_fields;
            } else {
                // the PK constraint is on max one field => OK
                $autoincrement = null;
            }
        }
        $query = $this->_getCreateTableQuery($name, $fields, $options);
        if (PEAR::isError($query)) {
            return $query;
        }
        if (!is_null($autoincrement)) {
            // we have to remove the PK clause added by _getIntegerDeclaration()
            $query = str_replace('AUTO_INCREMENT PRIMARY KEY', 'AUTO_INCREMENT', $query);
        }
        $options_strings = array();
@@ -222,6 +269,112 @@
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ dropTable()
    /**
     * drop an existing table
     *
     * @param string $name name of the table that should be dropped
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function dropTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        //delete the triggers associated to existing FK constraints
        $constraints = $this->listTableConstraints($name);
        if (!PEAR::isError($constraints) && !empty($constraints)) {
            $db->loadModule('Reverse', null, true);
            foreach ($constraints as $constraint) {
                $definition = $db->reverse->getTableConstraintDefinition($name, $constraint);
                if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
                    $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        return parent::dropTable($name);
    }
    // }}}
    // {{{ truncateTable()
    /**
     * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
     * it falls back to a DELETE FROM TABLE query)
     *
     * @param string $name name of the table that should be truncated
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function truncateTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("TRUNCATE TABLE $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        if (empty($table)) {
            $table = $this->listTables();
            if (PEAR::isError($table)) {
                return $table;
            }
        }
        if (is_array($table)) {
            foreach (array_keys($table) as $k) {
                $table[$k] = $db->quoteIdentifier($table[$k], true);
            }
            $table = implode(', ', $table);
        } else {
            $table = $db->quoteIdentifier($table, true);
        }
        $result = $db->exec('OPTIMIZE TABLE '.$table);
        if (PEAR::isError($result)) {
            return $result;
        }
        if (!empty($options['analyze'])) {
            return $db->exec('ANALYZE TABLE '.$table);
        }
        return MDB2_OK;
    }
@@ -656,6 +809,7 @@
     *                                            'last_login' => array()
     *                                        )
     *                                    )
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
@@ -800,8 +954,8 @@
                'invalid definition, could not create constraint', __FUNCTION__);
        }
        $table = $db->quoteIdentifier($table, true);
        $query = "ALTER TABLE $table ADD $type $name";
        $table_quoted = $db->quoteIdentifier($table, true);
        $query = "ALTER TABLE $table_quoted ADD $type $name";
        if (!empty($definition['foreign'])) {
            $query .= ' FOREIGN KEY ';
        }
@@ -819,7 +973,14 @@
            $query .= ' ('. implode(', ', $referenced_fields) . ')';
            $query .= $this->_getAdvancedFKOptions($definition);
        }
        return $db->exec($query);
        $res = $db->exec($query);
        if (PEAR::isError($res)) {
            return $res;
        }
        if (!empty($definition['foreign'])) {
            return $this->_createFKTriggers($table, array($name => $definition));
        }
        return MDB2_OK;
    }
    // }}}
@@ -841,14 +1002,208 @@
            return $db;
        }
        $table = $db->quoteIdentifier($table, true);
        if ($primary || strtolower($name) == 'primary') {
            $query = "ALTER TABLE $table DROP PRIMARY KEY";
        } else {
            $query = 'ALTER TABLE '. $db->quoteIdentifier($table, true) .' DROP PRIMARY KEY';
            return $db->exec($query);
        }
        //is it a FK constraint? If so, also delete the associated triggers
        $db->loadModule('Reverse', null, true);
        $definition = $db->reverse->getTableConstraintDefinition($table, $name);
        if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
            //first drop the FK enforcing triggers
            $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']);
            if (PEAR::isError($result)) {
                return $result;
            }
            //then drop the constraint itself
            $table = $db->quoteIdentifier($table, true);
            $name = $db->quoteIdentifier($db->getIndexName($name), true);
            $query = "ALTER TABLE $table DROP FOREIGN KEY $name";
            return $db->exec($query);
        }
        $table = $db->quoteIdentifier($table, true);
            $name = $db->quoteIdentifier($db->getIndexName($name), true);
            $query = "ALTER TABLE $table DROP INDEX $name";
        }
        return $db->exec($query);
    }
    // }}}
    // {{{ _createFKTriggers()
    /**
     * Create triggers to enforce the FOREIGN KEY constraint on the table
     *
     * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql,
     * we call a non-existent procedure to raise the FK violation message.
     * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877
     *
     * @param string $table        table name
     * @param array  $foreign_keys FOREIGN KEY definitions
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access private
     */
    function _createFKTriggers($table, $foreign_keys)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        // create triggers to enforce FOREIGN KEY constraints
        if ($db->supports('triggers') && !empty($foreign_keys)) {
            $table = $db->quoteIdentifier($table, true);
            foreach ($foreign_keys as $fkname => $fkdef) {
                if (empty($fkdef)) {
                    continue;
                }
                //set actions to 'RESTRICT' if not set
                $fkdef['onupdate'] = empty($fkdef['onupdate']) ? 'RESTRICT' : strtoupper($fkdef['onupdate']);
                $fkdef['ondelete'] = empty($fkdef['ondelete']) ? 'RESTRICT' : strtoupper($fkdef['ondelete']);
                $trigger_names = array(
                    'insert'    => $fkname.'_insert_trg',
                    'update'    => $fkname.'_update_trg',
                    'pk_update' => $fkname.'_pk_update_trg',
                    'pk_delete' => $fkname.'_pk_delete_trg',
                );
                $table_fields = array_keys($fkdef['fields']);
                $referenced_fields = array_keys($fkdef['references']['fields']);
                //create the ON [UPDATE|DELETE] triggers on the primary table
                $restrict_action = ' IF (SELECT ';
                $aliased_fields = array();
                foreach ($table_fields as $field) {
                    $aliased_fields[] = $table .'.'.$field .' AS '.$field;
                }
                $restrict_action .= implode(',', $aliased_fields)
                       .' FROM '.$table
                       .' WHERE ';
                $conditions  = array();
                $new_values  = array();
                $null_values = array();
                for ($i=0; $i<count($table_fields); $i++) {
                    $conditions[]  = $table_fields[$i] .' = OLD.'.$referenced_fields[$i];
                    $new_values[]  = $table_fields[$i] .' = NEW.'.$referenced_fields[$i];
                    $null_values[] = $table_fields[$i] .' = NULL';
                }
                $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL'
                                .' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();'
                                .' END IF;';
                $cascade_action_update = 'UPDATE '.$table.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions). ';';
                $cascade_action_delete = 'DELETE FROM '.$table.' WHERE '.implode(' AND ', $conditions). ';';
                $setnull_action        = 'UPDATE '.$table.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions). ';';
                if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) {
                    $db->loadModule('Reverse', null, true);
                    $default_values = array();
                    foreach ($table_fields as $table_field) {
                        $field_definition = $db->reverse->getTableFieldDefinition($table, $field);
                        if (PEAR::isError($field_definition)) {
                            return $field_definition;
                        }
                        $default_values[] = $table_field .' = '. $field_definition[0]['default'];
                    }
                    $setdefault_action = 'UPDATE '.$table.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions). ';';
                }
                $query = 'CREATE TRIGGER %s'
                        .' %s ON '.$fkdef['references']['table']
                        .' FOR EACH ROW BEGIN '
                        .' SET FOREIGN_KEY_CHECKS = 0; ';  //only really needed for ON UPDATE CASCADE
                if ('CASCADE' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE',  'update') . $cascade_action_update;
                } elseif ('SET NULL' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action;
                } elseif ('SET DEFAULT' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action;
                } elseif ('NO ACTION' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'AFTER UPDATE', 'update');
                } else {
                    //'RESTRICT'
                    $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update');
                }
                if ('CASCADE' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE',  'delete') . $cascade_action_delete;
                } elseif ('SET NULL' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action;
                } elseif ('SET DEFAULT' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action;
                } elseif ('NO ACTION' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete');
                } else {
                    //'RESTRICT'
                    $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete');
                }
                $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
                $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
                $db->pushErrorHandling(PEAR_ERROR_RETURN);
                $db->expectError(MDB2_ERROR_CANNOT_CREATE);
                $result = $db->exec($sql_delete);
                $expected_errmsg = 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table';
                $db->popExpect();
                $db->popErrorHandling();
                if (PEAR::isError($result)) {
                    if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                        return $result;
                    }
                    $db->warnings[] = $expected_errmsg;
                }
                $db->pushErrorHandling(PEAR_ERROR_RETURN);
                $db->expectError(MDB2_ERROR_CANNOT_CREATE);
                $result = $db->exec($sql_update);
                $db->popExpect();
                $db->popErrorHandling();
                if (PEAR::isError($result) && $result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                    if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                        return $result;
                    }
                    $db->warnings[] = $expected_errmsg;
                }
            }
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ _dropFKTriggers()
    /**
     * Drop the triggers created to enforce the FOREIGN KEY constraint on the table
     *
     * @param string $table            table name
     * @param string $fkname           FOREIGN KEY constraint name
     * @param string $referenced_table referenced table name
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access private
     */
    function _dropFKTriggers($table, $fkname, $referenced_table)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $triggers  = $this->listTableTriggers($table);
        $triggers2 = $this->listTableTriggers($referenced_table);
        if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) {
            $triggers = array_merge($triggers, $triggers2);
            $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i';
            foreach ($triggers as $trigger) {
                if (preg_match($pattern, $trigger)) {
                    $result = $db->exec('DROP TRIGGER '.$trigger);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        return MDB2_OK;
    }
    // }}}
@@ -904,8 +1259,8 @@
        $query = 'SHOW CREATE TABLE '. $db->escape($table);
        $definition = $db->queryOne($query, 'text', 1);
        if (!PEAR::isError($definition) && !empty($definition)) {
            $pattern = '/\bCONSTRAINT\s+([^\s]+)\s+FOREIGN KEY\b/i';
            if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 1) {
            $pattern = '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims';
            if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 0) {
                foreach ($matches[1] as $constraint) {
                    $result[$constraint] = true;
                }
@@ -974,7 +1329,6 @@
            $query .= ' '.implode(' ', $options_strings);
        }
        $res = $db->exec($query);
        if (PEAR::isError($res)) {
            return $res;
        }
program/lib/MDB2/Driver/Manager/mysqli.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysqli.php,v 1.87 2007/12/03 20:59:15 quipo Exp $
// $Id: mysqli.php,v 1.95 2008/03/11 19:58:12 quipo Exp $
//
require_once 'MDB2/Driver/Manager/Common.php';
@@ -79,16 +79,41 @@
        $name  = $db->quoteIdentifier($name, true);
        $query = 'CREATE DATABASE ' . $name;
        if (!empty($options['charset'])) {
            $query .= ' DEFAULT CHARACTER SET ' . $options['charset'];
            $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
        }
        if (!empty($options['collation'])) {
            $query .= ' COLLATE ' . $options['collation'];
            $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
        }
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        return $db->standaloneQuery($query, null, true);
        }
        return MDB2_OK;
    // }}}
    // {{{ alterDatabase()
    /**
     * alter an existing database
     *
     * @param string $name    name of the database that is intended to be changed
     * @param array  $options array with charset, collation info
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function alterDatabase($name, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true);
        if (!empty($options['charset'])) {
            $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
        }
        if (!empty($options['collation'])) {
            $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
        }
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
@@ -110,11 +135,7 @@
        $name = $db->quoteIdentifier($name, true);
        $query = "DROP DATABASE $name";
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        }
        return MDB2_OK;
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
@@ -188,9 +209,35 @@
            return $db;
        }
        // if we have an AUTO_INCREMENT column and a PK on more than one field,
        // we have to handle it differently...
        $autoincrement = null;
        if (empty($options['primary'])) {
            $pk_fields = array();
            foreach ($fields as $fieldname => $def) {
                if (!empty($def['primary'])) {
                    $pk_fields[$fieldname] = true;
                }
                if (!empty($def['autoincrement'])) {
                    $autoincrement = $fieldname;
                }
            }
            if (!is_null($autoincrement) && count($pk_fields) > 1) {
                $options['primary'] = $pk_fields;
            } else {
                // the PK constraint is on max one field => OK
                $autoincrement = null;
            }
        }
        $query = $this->_getCreateTableQuery($name, $fields, $options);
        if (PEAR::isError($query)) {
            return $query;
        }
        if (!is_null($autoincrement)) {
            // we have to remove the PK clause added by _getIntegerDeclaration()
            $query = str_replace('AUTO_INCREMENT PRIMARY KEY', 'AUTO_INCREMENT', $query);
        }
        $options_strings = array();
@@ -222,6 +269,112 @@
        $result = $db->exec($query);
        if (PEAR::isError($result)) {
            return $result;
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ dropTable()
    /**
     * drop an existing table
     *
     * @param string $name name of the table that should be dropped
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function dropTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        //delete the triggers associated to existing FK constraints
        $constraints = $this->listTableConstraints($name);
        if (!PEAR::isError($constraints) && !empty($constraints)) {
            $db->loadModule('Reverse', null, true);
            foreach ($constraints as $constraint) {
                $definition = $db->reverse->getTableConstraintDefinition($name, $constraint);
                if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
                    $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        return parent::dropTable($name);
    }
    // }}}
    // {{{ truncateTable()
    /**
     * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
     * it falls back to a DELETE FROM TABLE query)
     *
     * @param string $name name of the table that should be truncated
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function truncateTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("TRUNCATE TABLE $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        if (empty($table)) {
            $table = $this->listTables();
            if (PEAR::isError($table)) {
                return $table;
            }
        }
        if (is_array($table)) {
            foreach (array_keys($table) as $k) {
                $table[$k] = $db->quoteIdentifier($table[$k], true);
            }
            $table = implode(', ', $table);
        } else {
            $table = $db->quoteIdentifier($table, true);
        }
        $result = $db->exec('OPTIMIZE TABLE '.$table);
        if (PEAR::isError($result)) {
            return $result;
        }
        if (!empty($options['analyze'])) {
            return $db->exec('ANALYZE TABLE '.$table);
        }
        return MDB2_OK;
    }
@@ -656,6 +809,7 @@
     *                                            'last_login' => array()
     *                                        )
     *                                    )
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
@@ -800,8 +954,8 @@
                'invalid definition, could not create constraint', __FUNCTION__);
        }
        $table = $db->quoteIdentifier($table, true);
        $query = "ALTER TABLE $table ADD $type $name";
        $table_quoted = $db->quoteIdentifier($table, true);
        $query = "ALTER TABLE $table_quoted ADD $type $name";
        if (!empty($definition['foreign'])) {
            $query .= ' FOREIGN KEY ';
        }
@@ -819,7 +973,14 @@
            $query .= ' ('. implode(', ', $referenced_fields) . ')';
            $query .= $this->_getAdvancedFKOptions($definition);
        }
        return $db->exec($query);
        $res = $db->exec($query);
        if (PEAR::isError($res)) {
            return $res;
        }
        if (!empty($definition['foreign'])) {
            return $this->_createFKTriggers($table, array($name => $definition));
        }
        return MDB2_OK;
    }
    // }}}
@@ -841,14 +1002,208 @@
            return $db;
        }
        $table = $db->quoteIdentifier($table, true);
        if ($primary || strtolower($name) == 'primary') {
            $query = "ALTER TABLE $table DROP PRIMARY KEY";
        } else {
            $query = 'ALTER TABLE '. $db->quoteIdentifier($table, true) .' DROP PRIMARY KEY';
            return $db->exec($query);
        }
        //is it a FK constraint? If so, also delete the associated triggers
        $db->loadModule('Reverse', null, true);
        $definition = $db->reverse->getTableConstraintDefinition($table, $name);
        if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
            //first drop the FK enforcing triggers
            $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']);
            if (PEAR::isError($result)) {
                return $result;
            }
            //then drop the constraint itself
            $table = $db->quoteIdentifier($table, true);
            $name = $db->quoteIdentifier($db->getIndexName($name), true);
            $query = "ALTER TABLE $table DROP FOREIGN KEY $name";
            return $db->exec($query);
        }
        $table = $db->quoteIdentifier($table, true);
            $name = $db->quoteIdentifier($db->getIndexName($name), true);
            $query = "ALTER TABLE $table DROP INDEX $name";
        }
        return $db->exec($query);
    }
    // }}}
    // {{{ _createFKTriggers()
    /**
     * Create triggers to enforce the FOREIGN KEY constraint on the table
     *
     * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql,
     * we call a non-existent procedure to raise the FK violation message.
     * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877
     *
     * @param string $table        table name
     * @param array  $foreign_keys FOREIGN KEY definitions
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access private
     */
    function _createFKTriggers($table, $foreign_keys)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        // create triggers to enforce FOREIGN KEY constraints
        if ($db->supports('triggers') && !empty($foreign_keys)) {
            $table = $db->quoteIdentifier($table, true);
            foreach ($foreign_keys as $fkname => $fkdef) {
                if (empty($fkdef)) {
                    continue;
                }
                //set actions to 'RESTRICT' if not set
                $fkdef['onupdate'] = empty($fkdef['onupdate']) ? 'RESTRICT' : strtoupper($fkdef['onupdate']);
                $fkdef['ondelete'] = empty($fkdef['ondelete']) ? 'RESTRICT' : strtoupper($fkdef['ondelete']);
                $trigger_names = array(
                    'insert'    => $fkname.'_insert_trg',
                    'update'    => $fkname.'_update_trg',
                    'pk_update' => $fkname.'_pk_update_trg',
                    'pk_delete' => $fkname.'_pk_delete_trg',
                );
                $table_fields = array_keys($fkdef['fields']);
                $referenced_fields = array_keys($fkdef['references']['fields']);
                //create the ON [UPDATE|DELETE] triggers on the primary table
                $restrict_action = ' IF (SELECT ';
                $aliased_fields = array();
                foreach ($table_fields as $field) {
                    $aliased_fields[] = $table .'.'.$field .' AS '.$field;
                }
                $restrict_action .= implode(',', $aliased_fields)
                       .' FROM '.$table
                       .' WHERE ';
                $conditions  = array();
                $new_values  = array();
                $null_values = array();
                for ($i=0; $i<count($table_fields); $i++) {
                    $conditions[]  = $table_fields[$i] .' = OLD.'.$referenced_fields[$i];
                    $new_values[]  = $table_fields[$i] .' = NEW.'.$referenced_fields[$i];
                    $null_values[] = $table_fields[$i] .' = NULL';
                }
                $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL'
                                .' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();'
                                .' END IF;';
                $cascade_action_update = 'UPDATE '.$table.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions). ';';
                $cascade_action_delete = 'DELETE FROM '.$table.' WHERE '.implode(' AND ', $conditions). ';';
                $setnull_action        = 'UPDATE '.$table.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions). ';';
                if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) {
                    $db->loadModule('Reverse', null, true);
                    $default_values = array();
                    foreach ($table_fields as $table_field) {
                        $field_definition = $db->reverse->getTableFieldDefinition($table, $field);
                        if (PEAR::isError($field_definition)) {
                            return $field_definition;
                        }
                        $default_values[] = $table_field .' = '. $field_definition[0]['default'];
                    }
                    $setdefault_action = 'UPDATE '.$table.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions). ';';
                }
                $query = 'CREATE TRIGGER %s'
                        .' %s ON '.$fkdef['references']['table']
                        .' FOR EACH ROW BEGIN '
                        .' SET FOREIGN_KEY_CHECKS = 0; ';  //only really needed for ON UPDATE CASCADE
                if ('CASCADE' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE',  'update') . $cascade_action_update;
                } elseif ('SET NULL' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action;
                } elseif ('SET DEFAULT' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action;
                } elseif ('NO ACTION' == $fkdef['onupdate']) {
                    $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'AFTER UPDATE', 'update');
                } else {
                    //'RESTRICT'
                    $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update');
                }
                if ('CASCADE' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE',  'delete') . $cascade_action_delete;
                } elseif ('SET NULL' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action;
                } elseif ('SET DEFAULT' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action;
                } elseif ('NO ACTION' == $fkdef['ondelete']) {
                    $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete');
                } else {
                    //'RESTRICT'
                    $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete');
                }
                $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
                $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
                $db->pushErrorHandling(PEAR_ERROR_RETURN);
                $db->expectError(MDB2_ERROR_CANNOT_CREATE);
                $result = $db->exec($sql_delete);
                $expected_errmsg = 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table';
                $db->popExpect();
                $db->popErrorHandling();
                if (PEAR::isError($result)) {
                    if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                        return $result;
                    }
                    $db->warnings[] = $expected_errmsg;
                }
                $db->pushErrorHandling(PEAR_ERROR_RETURN);
                $db->expectError(MDB2_ERROR_CANNOT_CREATE);
                $result = $db->exec($sql_update);
                $db->popExpect();
                $db->popErrorHandling();
                if (PEAR::isError($result) && $result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                    if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
                        return $result;
                    }
                    $db->warnings[] = $expected_errmsg;
                }
            }
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ _dropFKTriggers()
    /**
     * Drop the triggers created to enforce the FOREIGN KEY constraint on the table
     *
     * @param string $table            table name
     * @param string $fkname           FOREIGN KEY constraint name
     * @param string $referenced_table referenced table name
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access private
     */
    function _dropFKTriggers($table, $fkname, $referenced_table)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $triggers  = $this->listTableTriggers($table);
        $triggers2 = $this->listTableTriggers($referenced_table);
        if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) {
            $triggers = array_merge($triggers, $triggers2);
            $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i';
            foreach ($triggers as $trigger) {
                if (preg_match($pattern, $trigger)) {
                    $result = $db->exec('DROP TRIGGER '.$trigger);
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        return MDB2_OK;
    }
    // }}}
@@ -904,8 +1259,8 @@
        $query = 'SHOW CREATE TABLE '. $db->escape($table);
        $definition = $db->queryOne($query, 'text', 1);
        if (!PEAR::isError($definition) && !empty($definition)) {
            $pattern = '/\bCONSTRAINT\s+([^\s]+)\s+FOREIGN KEY\b/i';
            if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 1) {
            $pattern = '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims';
            if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 0) {
                foreach ($matches[1] as $constraint) {
                    $result[$constraint] = true;
                }
@@ -967,10 +1322,6 @@
        }
        if ($type) {
            $options_strings[] = "ENGINE = $type";
        }
        if (!empty($options_strings)) {
            $query.= ' '.implode(' ', $options_strings);
        }
        $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))";
program/lib/MDB2/Driver/Manager/pgsql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -42,7 +42,7 @@
// | Author: Paul Cooper <pgc@ucecom.com>                                 |
// +----------------------------------------------------------------------+
//
// $Id: pgsql.php,v 1.74 2007/12/03 20:59:15 quipo Exp $
// $Id: pgsql.php,v 1.82 2008/03/05 12:55:57 afz Exp $
require_once 'MDB2/Driver/Manager/Common.php';
@@ -82,6 +82,35 @@
    }
    // }}}
    // {{{ alterDatabase()
    /**
     * alter an existing database
     *
     * @param string $name    name of the database that is intended to be changed
     * @param array  $options array with name, owner info
     *
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function alterDatabase($name, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true);
        if (!empty($options['name'])) {
            $query .= ' RENAME TO ' . $options['name'];
        }
        if (!empty($options['owner'])) {
            $query .= ' OWNER TO ' . $options['owner'];
        }
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
    // {{{ dropDatabase()
    /**
@@ -99,7 +128,8 @@
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->standaloneQuery("DROP DATABASE $name", null, true);
        $query = "DROP DATABASE $name";
        return $db->standaloneQuery($query, null, true);
    }
    // }}}
@@ -136,6 +166,69 @@
            $query .= ' INITIALLY IMMEDIATE';
        }
        return $query;
    }
    // }}}
    // {{{ truncateTable()
    /**
     * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
     * it falls back to a DELETE FROM TABLE query)
     *
     * @param string $name name of the table that should be truncated
     * @return mixed MDB2_OK on success, a MDB2 error on failure
     * @access public
     */
    function truncateTable($name)
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("TRUNCATE TABLE $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = 'VACUUM';
        if (!empty($options['full'])) {
            $query .= ' FULL';
        }
        if (!empty($options['freeze'])) {
            $query .= ' FREEZE';
        }
        if (!empty($options['analyze'])) {
            $query .= ' ANALYZE';
        }
        if (!empty($table)) {
            $query .= ' '.$db->quoteIdentifier($table, true);
        }
        return $db->exec($query);
    }
    // }}}
@@ -256,9 +349,10 @@
            return MDB2_OK;
        }
        if (!empty($changes['add']) && is_array($changes['add'])) {
            foreach ($changes['add'] as $field_name => $field) {
                $query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
        if (!empty($changes['remove']) && is_array($changes['remove'])) {
            foreach ($changes['remove'] as $field_name => $field) {
                $field_name = $db->quoteIdentifier($field_name, true);
                $query = 'DROP ' . $field_name;
                $result = $db->exec("ALTER TABLE $name $query");
                if (PEAR::isError($result)) {
                    return $result;
@@ -266,10 +360,19 @@
            }
        }
        if (!empty($changes['remove']) && is_array($changes['remove'])) {
            foreach ($changes['remove'] as $field_name => $field) {
        if (!empty($changes['rename']) && is_array($changes['rename'])) {
            foreach ($changes['rename'] as $field_name => $field) {
                $field_name = $db->quoteIdentifier($field_name, true);
                $query = 'DROP ' . $field_name;
                $result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true));
                if (PEAR::isError($result)) {
                    return $result;
                }
            }
        }
        if (!empty($changes['add']) && is_array($changes['add'])) {
            foreach ($changes['add'] as $field_name => $field) {
                $query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
                $result = $db->exec("ALTER TABLE $name $query");
                if (PEAR::isError($result)) {
                    return $result;
@@ -309,16 +412,6 @@
                    if (PEAR::isError($result)) {
                        return $result;
                    }
                }
            }
        }
        if (!empty($changes['rename']) && is_array($changes['rename'])) {
            foreach ($changes['rename'] as $field_name => $field) {
                $field_name = $db->quoteIdentifier($field_name, true);
                $result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true));
                if (PEAR::isError($result)) {
                    return $result;
                }
            }
        }
@@ -662,9 +755,10 @@
        }
        $table = $db->quote($table, 'text');
        $subquery = "SELECT indexrelid FROM pg_index, pg_class";
        $subquery.= " WHERE pg_class.relname=$table AND pg_class.oid=pg_index.indrelid AND (indisunique = 't' OR indisprimary = 't')";
        $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
        $query = 'SELECT conname
                    FROM pg_constraint, pg_class
                   WHERE pg_constraint.conrelid = pg_class.oid
                     AND relname = ' .$table;
        $constraints = $db->queryCol($query);
        if (PEAR::isError($constraints)) {
            return $constraints;
program/lib/MDB2/Driver/Manager/sqlite.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton                       |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: sqlite.php,v 1.72 2007/12/03 20:59:15 quipo Exp $
// $Id: sqlite.php,v 1.74 2008/03/05 11:08:53 quipo Exp $
//
require_once 'MDB2/Driver/Manager/Common.php';
@@ -401,6 +401,37 @@
        $name = $db->quoteIdentifier($name, true);
        return $db->exec("DROP TABLE $name");
    }
    // }}}
    // {{{ vacuum()
    /**
     * Optimize (vacuum) all the tables in the db (or only the specified table)
     * and optionally run ANALYZE.
     *
     * @param string $table table name (all the tables if empty)
     * @param array  $options an array with driver-specific options:
     *               - timeout [int] (in seconds) [mssql-only]
     *               - analyze [boolean] [pgsql and mysql]
     *               - full [boolean] [pgsql-only]
     *               - freeze [boolean] [pgsql-only]
     *
     * @return mixed MDB2_OK success, a MDB2 error on failure
     * @access public
     */
    function vacuum($table = null, $options = array())
    {
        $db =& $this->getDBInstance();
        if (PEAR::isError($db)) {
            return $db;
        }
        $query = 'VACUUM';
        if (!empty($table)) {
            $query .= ' '.$db->quoteIdentifier($table, true);
        }
        return $db->exec($query);
    }
    // }}}
@@ -1207,7 +1238,7 @@
        if (PEAR::isError($table_def)) {
            return $table_def;
        }
        if (preg_match("/\bPRIMARY\s+KEY\b\s*\(([^)]+)/i", $table_def, $tmp)) {
        if (preg_match("/\bPRIMARY\s+KEY\b/i", $table_def, $tmp)) {
            $result['primary'] = true;
        }
program/lib/MDB2/Driver/Reverse/Common.php
@@ -42,7 +42,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.41 2007/09/09 13:47:36 quipo Exp $
// $Id: Common.php,v 1.42 2008/01/12 12:50:58 quipo Exp $
//
/**
@@ -466,6 +466,8 @@
            }
        }
        $res = array();
        if ($mode) {
            $res['num_fields'] = count($fields);
        }
program/lib/MDB2/Driver/Reverse/mssql.php
@@ -43,7 +43,7 @@
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: mssql.php,v 1.48 2007/11/25 13:38:29 quipo Exp $
// $Id: mssql.php,v 1.49 2008/02/17 15:30:57 quipo Exp $
//
require_once 'MDB2/Driver/Reverse/Common.php';
program/lib/MDB2/Driver/Reverse/pgsql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: pgsql.php,v 1.68 2007/11/25 13:38:29 quipo Exp $
// $Id: pgsql.php,v 1.70 2008/03/13 20:38:09 quipo Exp $
require_once 'MDB2/Driver/Reverse/Common.php';
@@ -358,7 +358,7 @@
            $query = 'SELECT a.attname
                        FROM pg_constraint c
                   LEFT JOIN pg_class t  ON c.confrelid  = t.oid
                   LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
                   LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.confkey)
                       WHERE c.conname = %s
                         AND t.relname = ' . $db->quote($definition['references']['table'], 'text');
            $constraint_name_mdb2 = $db->getIndexName($constraint_name);
@@ -424,7 +424,10 @@
                            WHEN 24 THEN 'UPDATE, DELETE'
                            WHEN 12 THEN 'INSERT, DELETE'
                         END AS trigger_event,
                         trg.tgenabled AS trigger_enabled,
                         CASE trg.tgenabled
                            WHEN 'O' THEN 't'
                            ELSE trg.tgenabled
                         END AS trigger_enabled,
                         obj_description(trg.oid, 'pg_trigger') AS trigger_comment
                    FROM pg_trigger trg,
                         pg_class tbl,
program/lib/MDB2/Driver/Reverse/sqlite.php
@@ -43,7 +43,7 @@
// |          Lorenzo Alberton <l.alberton@quipo.it>                      |
// +----------------------------------------------------------------------+
//
// $Id: sqlite.php,v 1.78 2007/12/01 10:46:13 quipo Exp $
// $Id: sqlite.php,v 1.79 2008/03/05 11:08:53 quipo Exp $
//
require_once 'MDB2/Driver/Reverse/Common.php';
@@ -393,6 +393,18 @@
                    }
                    return $definition;
                }
                if (preg_match("/\"([^\"]+)\"[^\,\"]+\bPRIMARY\s+KEY\b[^\,\)]*/i", $sql, $tmp)) {
                    $definition['primary'] = true;
                    $definition['fields'] = array();
                    $column_names = split(',', $tmp[1]);
                    $colpos = 1;
                    foreach ($column_names as $column_name) {
                        $definition['fields'][trim($column_name)] = array(
                            'position' => $colpos++
                        );
                    }
                    return $definition;
                }
            } else {
                // search in table definition for FOREIGN KEYs
                $pattern = "/\bCONSTRAINT\b\s+%s\s+
program/lib/MDB2/Driver/mssql.php
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann                       |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// | Author: Frank M. Kromann <frank@kromann.info>                        |
// +----------------------------------------------------------------------+
//
// $Id: mssql.php,v 1.161 2007/11/18 17:52:00 quipo Exp $
// $Id: mssql.php,v 1.174 2008/03/08 14:18:39 quipo Exp $
//
// {{{ Class MDB2_Driver_mssql
/**
@@ -86,6 +86,7 @@
        $this->supported['LOBs'] = true;
        $this->supported['replace'] = 'emulated';
        $this->supported['sub_selects'] = true;
        $this->supported['triggers'] = true;
        $this->supported['auto_increment'] = true;
        $this->supported['primary_key'] = true;
        $this->supported['result_introspection'] = true;
@@ -93,8 +94,11 @@
        $this->supported['pattern_escaping'] = true;
        $this->supported['new_link'] = true;
        $this->options['DBA_username'] = false;
        $this->options['DBA_password'] = false;
        $this->options['database_device'] = false;
        $this->options['database_size'] = false;
        $this->options['max_identifiers_length'] = 128; // MS Access: 64
    }
    // }}}
@@ -107,11 +111,15 @@
     * @return array
     * @access public
     */
    function errorInfo($error = null)
    function errorInfo($error = null, $connection = null)
    {
        if (is_null($connection)) {
            $connection = $this->connection;
        }
        $native_code = null;
        if ($this->connection) {
            $result = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
        if ($connection) {
            $result = @mssql_query('select @@ERROR as ErrorCode', $connection);
            if ($result) {
                $native_code = @mssql_result($result, 0, 0);
                @mssql_free_result($result);
@@ -136,8 +144,10 @@
                    336   => MDB2_ERROR_SYNTAX,
                    515   => MDB2_ERROR_CONSTRAINT_NOT_NULL,
                    547   => MDB2_ERROR_CONSTRAINT,
                    911   => MDB2_ERROR_NOT_FOUND,
                    1018  => MDB2_ERROR_SYNTAX,
                    1035  => MDB2_ERROR_SYNTAX,
                    1801  => MDB2_ERROR_ALREADY_EXISTS,
                    1913  => MDB2_ERROR_ALREADY_EXISTS,
                    2209  => MDB2_ERROR_SYNTAX,
                    2223  => MDB2_ERROR_SYNTAX,
@@ -296,6 +306,68 @@
    }
    // }}}
    // {{{ _doConnect()
    /**
     * do the grunt work of the connect
     *
     * @return connection on success or MDB2 Error Object on failure
     * @access protected
     */
    function _doConnect($username, $password, $persistent = false)
    {
        if (!PEAR::loadExtension($this->phptype) && !PEAR::loadExtension('sybase_ct')) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        $params = array(
            $this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost',
            $username ? $username : null,
            $password ? $password : null,
        );
        if ($this->dsn['port']) {
            $params[0].= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':').$this->dsn['port'];
        }
        if (!$persistent) {
            if (isset($this->dsn['new_link'])
                && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true)
            ) {
                $params[] = true;
            } else {
                $params[] = false;
            }
        }
        $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
        $connection = @call_user_func_array($connect_function, $params);
        if ($connection <= 0) {
            return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
                'unable to establish a connection', __FUNCTION__, __FUNCTION__);
        }
        @mssql_query('SET ANSI_NULL_DFLT_ON ON', $connection);
        if (!empty($this->dsn['charset'])) {
            $result = $this->setCharset($this->dsn['charset'], $connection);
            if (PEAR::isError($result)) {
                return $result;
            }
        }
       if ((bool)ini_get('mssql.datetimeconvert')) {
           @ini_set('mssql.datetimeconvert', '0');
       }
       if (empty($this->dsn['disable_iso_date'])) {
           @mssql_query('SET DATEFORMAT ymd', $connection);
       }
       return $connection;
    }
    // }}}
    // {{{ connect()
    /**
@@ -315,50 +387,13 @@
            $this->disconnect(false);
        }
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        $params = array(
            $this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost',
            $this->dsn['username'] ? $this->dsn['username'] : null,
            $this->dsn['password'] ? $this->dsn['password'] : null,
        $connection = $this->_doConnect(
            $this->dsn['username'],
            $this->dsn['password'],
            $this->options['persistent']
        );
        if ($this->dsn['port']) {
            $params[0].= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':').$this->dsn['port'];
        }
        if (!$this->options['persistent']) {
            if (isset($this->dsn['new_link'])
                && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true)
            ) {
                $params[] = true;
            } else {
                $params[] = false;
            }
        }
        $connect_function = $this->options['persistent'] ? 'mssql_pconnect' : 'mssql_connect';
        $connection = @call_user_func_array($connect_function, $params);
        if ($connection <= 0) {
            return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
                'unable to establish a connection', __FUNCTION__, __FUNCTION__);
        }
        if (!empty($this->dsn['charset'])) {
            $result = $this->setCharset($this->dsn['charset'], $connection);
            if (PEAR::isError($result)) {
                return $result;
            }
        }
       if ((bool)ini_get('mssql.datetimeconvert')) {
           @ini_set('mssql.datetimeconvert', '0');
       }
       if (empty($this->dsn['disable_iso_date'])) {
           @mssql_query('SET DATEFORMAT ymd', $connection);
        if (PEAR::isError($connection)) {
            return $connection;
       }
        $this->connection = $connection;
@@ -379,6 +414,41 @@
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        $connection = $this->_doConnect($this->dsn['username'],
                                        $this->dsn['password'],
                                        $this->options['persistent']);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $result = @mssql_select_db($name, $connection);
        $errorInfo = $this->errorInfo(null, $connection);
        @mssql_close($connection);
        if (!$result) {
            if ($errorInfo[0] != MDB2_ERROR_NOT_FOUND) {
            exit;
                $result = $this->raiseError($errorInfo[0], null, null, $errorInfo[2], __FUNCTION__);
                return $result;
            }
            $result = false;
        }
        return $result;
    }
    // }}}
@@ -414,6 +484,42 @@
            }
        }
        return parent::disconnect($force);
    }
    // }}}
    // {{{ standaloneQuery()
   /**
     * execute a query as DBA
     *
     * @param string $query the SQL query
     * @param mixed   $types  array that contains the types of the columns in
     *                        the result set
     * @param boolean $is_manip  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)
    {
        $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
        $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
        $connection = $this->_doConnect($user, $pass, $this->options['persistent']);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
        $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name);
        if (!PEAR::isError($result)) {
            $result = $this->_affectedRows($connection, $result);
        }
        @mssql_close($connection);
        return $result;
    }
    // }}}
@@ -546,7 +652,7 @@
        // cache server_info
        $this->connected_server_info = $server_info;
        if (!$native && !PEAR::isError($server_info)) {
            if (preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $server_info, $tmp)) {
            if (preg_match('/(\d+)\.(\d+)\.(\d+)/', $server_info, $tmp)) {
                $server_info = array(
                    'major' => $tmp[1],
                    'minor' => $tmp[2],
@@ -609,6 +715,7 @@
    {
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
        $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
        $this->pushErrorHandling(PEAR_ERROR_RETURN);
        $this->expectError(MDB2_ERROR_NOSUCHTABLE);
        
        $seq_val = $this->_checkSequence($sequence_name);
@@ -621,6 +728,7 @@
        }
        $result =& $this->_doQuery($query, true);
        $this->popExpect();
        $this->popErrorHandling();
        if (PEAR::isError($result)) {
            if ($ondemand && !$this->_checkSequence($sequence_name)) {
                $this->loadModule('Manager', null, true);
@@ -669,6 +777,7 @@
     *
     * @param string $table name of the table into which a new row was inserted
     * @param string $field name of the field into which a new row was inserted
     *
     * @return mixed MDB2 Error Object or id
     * @access public
     */
@@ -678,9 +787,12 @@
        if (is_array($server_info) && !is_null($server_info['major'])
           && $server_info['major'] >= 8
        ) {
            $query = "SELECT SCOPE_IDENTITY()";
            $query = "SELECT IDENT_CURRENT('$table')";
        } else {
            $query = "SELECT @@IDENTITY";
            if (!is_null($table)) {
                $query .= ' FROM '.$this->quoteIdentifier($table, true);
            }
        }
        return $this->queryOne($query, 'integer');
program/lib/MDB2/Driver/mysql.php
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.195 2007/11/10 13:27:03 quipo Exp $
// $Id: mysql.php,v 1.208 2008/03/13 03:31:55 afz Exp $
//
/**
@@ -98,6 +98,7 @@
        $this->supported['LOBs'] = true;
        $this->supported['replace'] = true;
        $this->supported['sub_selects'] = 'emulated';
        $this->supported['triggers'] = false;
        $this->supported['auto_increment'] = true;
        $this->supported['primary_key'] = true;
        $this->supported['result_introspection'] = true;
@@ -106,7 +107,66 @@
        $this->supported['pattern_escaping'] = true;
        $this->supported['new_link'] = true;
        $this->options['DBA_username'] = false;
        $this->options['DBA_password'] = false;
        $this->options['default_table_type'] = '';
        $this->options['max_identifiers_length'] = 64;
        $this->_reCheckSupportedOptions();
    }
    // }}}
    // {{{ _reCheckSupportedOptions()
    /**
     * If the user changes certain options, other capabilities may depend
     * on the new settings, so we need to check them (again).
     *
     * @access private
     */
    function _reCheckSupportedOptions()
    {
        $this->supported['transactions'] = $this->options['use_transactions'];
        $this->supported['savepoints']   = $this->options['use_transactions'];
        if ($this->options['default_table_type']) {
            switch (strtoupper($this->options['default_table_type'])) {
            case 'BLACKHOLE':
            case 'MEMORY':
            case 'ARCHIVE':
            case 'CSV':
            case 'HEAP':
            case 'ISAM':
            case 'MERGE':
            case 'MRG_ISAM':
            case 'ISAM':
            case 'MRG_MYISAM':
            case 'MYISAM':
                $this->supported['savepoints']   = false;
                $this->supported['transactions'] = false;
                $this->warnings[] = $this->options['default_table_type'] .
                    ' is not a supported default table type';
                break;
            }
        }
    }
    // }}}
    // {{{ 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)
    {
        $res = parent::setOption($option, $value);
        $this->_reCheckSupportedOptions();
    }
    // }}}
@@ -177,6 +237,7 @@
                    1216 => MDB2_ERROR_CONSTRAINT,
                    1217 => MDB2_ERROR_CONSTRAINT,
                    1227 => MDB2_ERROR_ACCESS_VIOLATION,
                    1235 => MDB2_ERROR_CANNOT_CREATE,
                    1299 => MDB2_ERROR_INVALID_DATE,
                    1300 => MDB2_ERROR_INVALID,
                    1304 => MDB2_ERROR_ALREADY_EXISTS,
@@ -195,6 +256,8 @@
                    1542 => MDB2_ERROR_CANNOT_DROP,
                    1546 => MDB2_ERROR_CONSTRAINT,
                    1582 => MDB2_ERROR_CONSTRAINT,
                    2003 => MDB2_ERROR_CONNECT_FAILED,
                    2019 => MDB2_ERROR_INVALID,
                );
            }
            if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) {
@@ -422,26 +485,16 @@
    }
    // }}}
    // {{{ connect()
    // {{{ _doConnect()
    /**
     * Connect to the database
     * do the grunt work of the connect
     *
     * @return true on success, MDB2 Error Object on failure
     * @return connection on success or MDB2 Error Object on failure
     * @access protected
     */
    function connect()
    function _doConnect($username, $password, $persistent = false)
    {
        if (is_resource($this->connection)) {
            //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
            if (MDB2::areEquals($this->connected_dsn, $this->dsn)
                && $this->opened_persistent == $this->options['persistent']
                && $this->connected_database_name == $this->database_name
            ) {
                return MDB2_OK;
            }
            $this->disconnect(false);
        }
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
@@ -457,9 +510,9 @@
                $params[0].= ':' . $this->dsn['port'];
            }
        }
        $params[] = $this->dsn['username'] ? $this->dsn['username'] : null;
        $params[] = $this->dsn['password'] ? $this->dsn['password'] : null;
        if (!$this->options['persistent']) {
        $params[] = $username ? $username : null;
        $params[] = $password ? $password : null;
        if (!$persistent) {
            if (isset($this->dsn['new_link'])
                && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true)
            ) {
@@ -472,7 +525,7 @@
            $params[] = isset($this->dsn['client_flags'])
                ? $this->dsn['client_flags'] : null;
        }
        $connect_function = $this->options['persistent'] ? 'mysql_pconnect' : 'mysql_connect';
        $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
        $connection = @call_user_func_array($connect_function, $params);
        if (!$connection) {
@@ -488,8 +541,42 @@
        if (!empty($this->dsn['charset'])) {
            $result = $this->setCharset($this->dsn['charset'], $connection);
            if (PEAR::isError($result)) {
                $this->disconnect(false);
                return $result;
            }
        }
        return $connection;
    }
    // }}}
    // {{{ connect()
    /**
     * Connect to the database
     *
     * @return MDB2_OK on success, MDB2 Error Object on failure
     * @access public
     */
    function connect()
    {
        if (is_resource($this->connection)) {
            //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
            if (MDB2::areEquals($this->connected_dsn, $this->dsn)
                && $this->opened_persistent == $this->options['persistent']
            ) {
                return MDB2_OK;
            }
            $this->disconnect(false);
        }
        $connection = $this->_doConnect(
            $this->dsn['username'],
            $this->dsn['password'],
            $this->options['persistent']
        );
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $this->connection = $connection;
@@ -509,27 +596,6 @@
            }
        }
        $this->supported['transactions'] = $this->options['use_transactions'];
        if ($this->options['default_table_type']) {
            switch (strtoupper($this->options['default_table_type'])) {
            case 'BLACKHOLE':
            case 'MEMORY':
            case 'ARCHIVE':
            case 'CSV':
            case 'HEAP':
            case 'ISAM':
            case 'MERGE':
            case 'MRG_ISAM':
            case 'ISAM':
            case 'MRG_MYISAM':
            case 'MYISAM':
                $this->supported['transactions'] = false;
                $this->warnings[] = $this->options['default_table_type'] .
                    ' is not a supported default table type';
                break;
            }
        }
        $this->_getServerCapabilities();
        return MDB2_OK;
@@ -541,7 +607,7 @@
    /**
     * Set the charset on the current connection
     *
     * @param string    charset
     * @param string    charset (or array(charset, collation))
     * @param resource  connection handle
     *
     * @return true on success, MDB2 Error Object on failure
@@ -554,8 +620,42 @@
                return $connection;
            }
        }
        $collation = null;
        if (is_array($charset) && 2 == count($charset)) {
            $collation = array_pop($charset);
            $charset   = array_pop($charset);
        }
        $query = "SET NAMES '".mysql_real_escape_string($charset, $connection)."'";
        if (!is_null($collation)) {
            $query .= " COLLATE '".mysqli_real_escape_string($connection, $collation)."'";
        }
        return $this->_doQuery($query, true, $connection);
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        $connection = $this->_doConnect($this->dsn['username'],
                                        $this->dsn['password'],
                                        $this->options['persistent']);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $result = @mysql_select_db($name, $connection);
        @mysql_close($connection);
        return $result;
    }
    // }}}
@@ -591,6 +691,42 @@
            }
        }
        return parent::disconnect($force);
    }
    // }}}
    // {{{ standaloneQuery()
   /**
     * execute a query as DBA
     *
     * @param string $query the SQL query
     * @param mixed   $types  array that contains the types of the columns in
     *                        the result set
     * @param boolean $is_manip  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)
    {
        $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
        $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
        $connection = $this->_doConnect($user, $pass, $this->options['persistent']);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
        $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name);
        if (!PEAR::isError($result)) {
            $result = $this->_affectedRows($connection, $result);
        }
        @mysql_close($connection);
        return $result;
    }
    // }}}
@@ -793,28 +929,38 @@
            //set defaults
            $this->supported['sub_selects'] = 'emulated';
            $this->supported['prepared_statements'] = 'emulated';
            $this->supported['triggers'] = false;
            $this->start_transaction = false;
            $this->varchar_max_length = 255;
            
            $server_info = $this->getServerVersion();
            if (is_array($server_info)) {
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) {
                $server_version = $server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'];
                if (!version_compare($server_version, '4.1.0', '<')) {
                    $this->supported['sub_selects'] = true;
                    $this->supported['prepared_statements'] = true;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<')
                    || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<')
                ) {
                    $this->supported['savepoints'] = true;
                // SAVEPOINTs were introduced in MySQL 4.0.14 and 4.1.1 (InnoDB)
                if (version_compare($server_version, '4.1.0', '>=')) {
                    if (version_compare($server_version, '4.1.1', '<')) {
                        $this->supported['savepoints'] = false;
                    }
                } elseif (version_compare($server_version, '4.0.14', '<')) {
                    $this->supported['savepoints'] = false;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) {
                if (!version_compare($server_version, '4.0.11', '<')) {
                    $this->start_transaction = true;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) {
                if (!version_compare($server_version, '5.0.3', '<')) {
                    $this->varchar_max_length = 65532;
                }
                if (!version_compare($server_version, '5.0.2', '<')) {
                    $this->supported['triggers'] = true;
                }
            }
        }
@@ -958,7 +1104,8 @@
            return $connection;
        }
        static $prep_statement_counter = 1;
        $statement_name = sprintf($this->options['statement_format'], $this->phptype, sha1(microtime() + mt_rand())) . $prep_statement_counter++;
        $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand()));
        $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']);
        $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text');
        $statement =& $this->_doQuery($query, true, $connection);
        if (PEAR::isError($statement)) {
@@ -1049,7 +1196,7 @@
                $query .= ',';
                $values.= ',';
            }
            $query.= $name;
            $query.= $this->quoteIdentifier($name, true);
            if (isset($fields[$name]['null']) && $fields[$name]['null']) {
                $value = 'NULL';
            } else {
@@ -1078,6 +1225,7 @@
            return $connection;
        }
        $table = $this->quoteIdentifier($table, true);
        $query = "REPLACE INTO $table ($query) VALUES ($values)";
        $result =& $this->_doQuery($query, true, $connection);
        if (PEAR::isError($result)) {
@@ -1105,9 +1253,11 @@
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
        $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
        $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
        $this->pushErrorHandling(PEAR_ERROR_RETURN);
        $this->expectError(MDB2_ERROR_NOSUCHTABLE);
        $result =& $this->_doQuery($query, true);
        $this->popExpect();
        $this->popErrorHandling();
        if (PEAR::isError($result)) {
            if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
                $this->loadModule('Manager', null, true);
program/lib/MDB2/Driver/mysqli.php
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: mysqli.php,v 1.176 2007/11/10 13:27:03 quipo Exp $
// $Id: mysqli.php,v 1.188 2008/03/13 03:31:55 afz Exp $
//
/**
@@ -98,6 +98,7 @@
        $this->supported['LOBs'] = true;
        $this->supported['replace'] = true;
        $this->supported['sub_selects'] = 'emulated';
        $this->supported['triggers'] = false;
        $this->supported['auto_increment'] = true;
        $this->supported['primary_key'] = true;
        $this->supported['result_introspection'] = true;
@@ -106,8 +107,67 @@
        $this->supported['pattern_escaping'] = true;
        $this->supported['new_link'] = true;
        $this->options['DBA_username'] = false;
        $this->options['DBA_password'] = false;
        $this->options['default_table_type'] = '';
        $this->options['multi_query'] = false;
        $this->options['max_identifiers_length'] = 64;
        $this->_reCheckSupportedOptions();
    }
    // }}}
    // {{{ _reCheckSupportedOptions()
    /**
     * If the user changes certain options, other capabilities may depend
     * on the new settings, so we need to check them (again).
     *
     * @access private
     */
    function _reCheckSupportedOptions()
    {
        $this->supported['transactions'] = $this->options['use_transactions'];
        $this->supported['savepoints']   = $this->options['use_transactions'];
        if ($this->options['default_table_type']) {
            switch (strtoupper($this->options['default_table_type'])) {
            case 'BLACKHOLE':
            case 'MEMORY':
            case 'ARCHIVE':
            case 'CSV':
            case 'HEAP':
            case 'ISAM':
            case 'MERGE':
            case 'MRG_ISAM':
            case 'ISAM':
            case 'MRG_MYISAM':
            case 'MYISAM':
                $this->supported['savepoints']   = false;
                $this->supported['transactions'] = false;
                $this->warnings[] = $this->options['default_table_type'] .
                    ' is not a supported default table type';
                break;
            }
        }
    }
    // }}}
    // {{{ 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)
    {
        $res = parent::setOption($option, $value);
        $this->_reCheckSupportedOptions();
    }
    // }}}
@@ -178,6 +238,7 @@
                    1216 => MDB2_ERROR_CONSTRAINT,
                    1217 => MDB2_ERROR_CONSTRAINT,
                    1227 => MDB2_ERROR_ACCESS_VIOLATION,
                    1235 => MDB2_ERROR_CANNOT_CREATE,
                    1299 => MDB2_ERROR_INVALID_DATE,
                    1300 => MDB2_ERROR_INVALID,
                    1304 => MDB2_ERROR_ALREADY_EXISTS,
@@ -196,6 +257,7 @@
                    1542 => MDB2_ERROR_CANNOT_DROP,
                    1546 => MDB2_ERROR_CONSTRAINT,
                    1582 => MDB2_ERROR_CONSTRAINT,
                    2003 => MDB2_ERROR_CONNECT_FAILED,
                    2019 => MDB2_ERROR_INVALID,
                );
            }
@@ -420,6 +482,66 @@
    }
    // }}}
    // {{{ _doConnect()
    /**
     * do the grunt work of the connect
     *
     * @return connection on success or MDB2 Error Object on failure
     * @access protected
     */
    function _doConnect($username, $password, $persistent = false)
    {
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        $connection = @mysqli_init();
        if (!empty($this->dsn['charset']) && defined('MYSQLI_SET_CHARSET_NAME')) {
            @mysqli_options($connection, MYSQLI_SET_CHARSET_NAME, $this->dsn['charset']);
        }
        if ($this->options['ssl']) {
            @mysqli_ssl_set(
                $connection,
                empty($this->dsn['key'])    ? null : $this->dsn['key'],
                empty($this->dsn['cert'])   ? null : $this->dsn['cert'],
                empty($this->dsn['ca'])     ? null : $this->dsn['ca'],
                empty($this->dsn['capath']) ? null : $this->dsn['capath'],
                empty($this->dsn['cipher']) ? null : $this->dsn['cipher']
            );
        }
        if (!@mysqli_real_connect(
            $connection,
            $this->dsn['hostspec'],
            $username,
            $password,
            $this->database_name,
            $this->dsn['port'],
            $this->dsn['socket']
        )) {
            if (($err = @mysqli_connect_error()) != '') {
                return $this->raiseError(null,
                    null, null, $err, __FUNCTION__);
            } else {
                return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
                    'unable to establish a connection', __FUNCTION__);
            }
        }
        if (!empty($this->dsn['charset']) && !defined('MYSQLI_SET_CHARSET_NAME')) {
            $result = $this->setCharset($this->dsn['charset'], $connection);
            if (PEAR::isError($result)) {
                return $result;
            }
        }
        return $connection;
    }
    // }}}
    // {{{ connect()
    /**
@@ -437,79 +559,18 @@
            $this->connection = 0;
        }
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        $connection = @mysqli_init();
        if (!empty($this->dsn['charset']) && defined('MYSQLI_SET_CHARSET_NAME')) {
            @mysqli_options($connection, MYSQLI_SET_CHARSET_NAME, $this->dsn['charset']);
        }
        if ($this->options['ssl']) {
            @mysqli_ssl_set(
                $connection,
                empty($this->dsn['key'])    ? null : $this->dsn['key'],
                empty($this->dsn['cert'])   ? null : $this->dsn['cert'],
                empty($this->dsn['ca'])     ? null : $this->dsn['ca'],
                empty($this->dsn['capath']) ? null : $this->dsn['capath'],
                empty($this->dsn['cipher']) ? null : $this->dsn['cipher']
            );
        }
        if (!@mysqli_real_connect(
            $connection,
            $this->dsn['hostspec'],
        $connection = $this->_doConnect(
            $this->dsn['username'],
            $this->dsn['password'],
            $this->database_name,
            $this->dsn['port'],
            $this->dsn['socket']
        )) {
            if (($err = @mysqli_connect_error()) != '') {
                return $this->raiseError(null,
                    null, null, $err, __FUNCTION__);
            } else {
                return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
                    'unable to establish a connection', __FUNCTION__);
            }
        }
        if (!empty($this->dsn['charset']) && !defined('MYSQLI_SET_CHARSET_NAME')) {
            $result = $this->setCharset($this->dsn['charset'], $connection);
            if (PEAR::isError($result)) {
                return $result;
            }
            $this->dsn['password']
        );
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $this->connection = $connection;
        $this->connected_dsn = $this->dsn;
        $this->connected_database_name = $this->database_name;
        $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
        $this->supported['transactions'] = $this->options['use_transactions'];
        if ($this->options['default_table_type']) {
            switch (strtoupper($this->options['default_table_type'])) {
            case 'BLACKHOLE':
            case 'MEMORY':
            case 'ARCHIVE':
            case 'CSV':
            case 'HEAP':
            case 'ISAM':
            case 'MERGE':
            case 'MRG_ISAM':
            case 'ISAM':
            case 'MRG_MYISAM':
            case 'MYISAM':
                $this->supported['transactions'] = false;
                $this->warnings[] = $this->options['default_table_type'] .
                    ' is not a supported default table type';
                break;
            }
        }
        
        $this->_getServerCapabilities();
@@ -522,7 +583,7 @@
    /**
     * Set the charset on the current connection
     *
     * @param string    charset
     * @param string    charset (or array(charset, collation))
     * @param resource  connection handle
     *
     * @return true on success, MDB2 Error Object on failure
@@ -535,11 +596,19 @@
                return $connection;
            }
        }
        $collation = null;
        if (is_array($charset) && 2 == count($charset)) {
            $collation = array_pop($charset);
            $charset   = array_pop($charset);
        }
        $client_info = mysqli_get_client_version();
        if (OS_WINDOWS && ((40111 > $client_info) ||
            ((50000 <= $client_info) && (50006 > $client_info)))
        ) {
            $query = "SET NAMES '".mysqli_real_escape_string($connection, $charset)."'";
            if (!is_null($collation)) {
                $query .= " COLLATE '".mysqli_real_escape_string($connection, $collation)."'";
            }
            return $this->_doQuery($query, true, $connection);
        }
        if (!$result = mysqli_set_charset($connection, $charset)) {
@@ -547,6 +616,31 @@
                'Could not set client character set', __FUNCTION__);
            return $err;
        }
        return $result;
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        $connection = $this->_doConnect($this->dsn['username'],
                                        $this->dsn['password']);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $result = @mysqli_select_db($connection, $name);
        @mysqli_close($connection);
        return $result;
    }
@@ -583,6 +677,42 @@
            }
        }
        return parent::disconnect($force);
    }
    // }}}
    // {{{ standaloneQuery()
   /**
     * execute a query as DBA
     *
     * @param string $query the SQL query
     * @param mixed   $types  array that contains the types of the columns in
     *                        the result set
     * @param boolean $is_manip  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)
    {
        $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
        $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
        $connection = $this->_doConnect($user, $pass);
        if (PEAR::isError($connection)) {
            return $connection;
        }
        $offset = $this->offset;
        $limit = $this->limit;
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
        $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name);
        if (!PEAR::isError($result)) {
            $result = $this->_affectedRows($connection, $result);
        }
        @mysqli_close($connection);
        return $result;
    }
    // }}}
@@ -803,28 +933,38 @@
            //set defaults
            $this->supported['sub_selects'] = 'emulated';
            $this->supported['prepared_statements'] = 'emulated';
            $this->supported['triggers'] = false;
            $this->start_transaction = false;
            $this->varchar_max_length = 255;
            $server_info = $this->getServerVersion();
            if (is_array($server_info)) {
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) {
                $server_version = $server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'];
                if (!version_compare($server_version, '4.1.0', '<')) {
                    $this->supported['sub_selects'] = true;
                    $this->supported['prepared_statements'] = true;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<')
                    || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<')
                ) {
                    $this->supported['savepoints'] = true;
                // SAVEPOINTS were introduced in MySQL 4.0.14 and 4.1.1 (InnoDB)
                if (version_compare($server_version, '4.1.0', '>=')) {
                    if (version_compare($server_version, '4.1.1', '<')) {
                        $this->supported['savepoints'] = false;
                    }
                } elseif (version_compare($server_version, '4.0.14', '<')) {
                    $this->supported['savepoints'] = false;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) {
                if (!version_compare($server_version, '4.0.11', '<')) {
                    $this->start_transaction = true;
                }
                if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) {
                if (!version_compare($server_version, '5.0.3', '<')) {
                    $this->varchar_max_length = 65532;
                }
                if (!version_compare($server_version, '5.0.2', '<')) {
                    $this->supported['triggers'] = true;
                }
            }
        }
@@ -970,7 +1110,8 @@
        if (!$is_manip) {
            static $prep_statement_counter = 1;
            $statement_name = sprintf($this->options['statement_format'], $this->phptype, sha1(microtime() + mt_rand())) . $prep_statement_counter++;
            $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand()));
            $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']);
            $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text');
            $statement =& $this->_doQuery($query, true, $connection);
@@ -1071,7 +1212,7 @@
                $query .= ',';
                $values.= ',';
            }
            $query.= $name;
            $query.= $this->quoteIdentifier($name, true);
            if (isset($fields[$name]['null']) && $fields[$name]['null']) {
                $value = 'NULL';
            } else {
@@ -1100,6 +1241,7 @@
            return $connection;
        }
        $table = $this->quoteIdentifier($table, true);
        $query = "REPLACE INTO $table ($query) VALUES ($values)";
        $result =& $this->_doQuery($query, true, $connection);
        if (PEAR::isError($result)) {
@@ -1127,9 +1269,11 @@
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
        $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
        $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
        $this->pushErrorHandling(PEAR_ERROR_RETURN);
        $this->expectError(MDB2_ERROR_NOSUCHTABLE);
        $result =& $this->_doQuery($query, true);
        $this->popExpect();
        $this->popErrorHandling();
        if (PEAR::isError($result)) {
            if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
                $this->loadModule('Manager', null, true);
program/lib/MDB2/Driver/pgsql.php
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// | Author: Paul Cooper <pgc@ucecom.com>                                 |
// +----------------------------------------------------------------------+
//
// $Id: pgsql.php,v 1.186 2007/11/10 13:27:03 quipo Exp $
// $Id: pgsql.php,v 1.197 2008/03/08 14:18:39 quipo Exp $
/**
 * MDB2 PostGreSQL driver
@@ -83,6 +83,7 @@
        $this->supported['LOBs'] = true;
        $this->supported['replace'] = 'emulated';
        $this->supported['sub_selects'] = true;
        $this->supported['triggers'] = true;
        $this->supported['auto_increment'] = 'emulated';
        $this->supported['primary_key'] = true;
        $this->supported['result_introspection'] = true;
@@ -91,8 +92,11 @@
        $this->supported['pattern_escaping'] = true;
        $this->supported['new_link'] = true;
        $this->options['DBA_username'] = false;
        $this->options['DBA_password'] = false;
        $this->options['multi_query'] = false;
        $this->options['disable_smart_seqname'] = false;
        $this->options['max_identifiers_length'] = 63;
    }
    // }}}
@@ -119,6 +123,8 @@
                $native_msg = 'Database connection has been lost.';
                $error_code = MDB2_ERROR_CONNECT_FAILED;
            }
        } else {
            $native_msg = @pg_last_error();
        }
        static $error_regexps;
@@ -128,8 +134,12 @@
                    => MDB2_ERROR_NOSUCHFIELD,
                '/(relation|sequence|table).*does not exist|class .* not found/i'
                    => MDB2_ERROR_NOSUCHTABLE,
                '/database .* does not exist/'
                    => MDB2_ERROR_NOT_FOUND,
                '/index .* does not exist/'
                    => MDB2_ERROR_NOT_FOUND,
                '/database .* already exists/i'
                    => MDB2_ERROR_ALREADY_EXISTS,
                '/relation .* already exists/i'
                    => MDB2_ERROR_ALREADY_EXISTS,
                '/(divide|division) by zero$/i'
@@ -202,7 +212,7 @@
        if (PEAR::isError($connection)) {
            return $connection;
        }
        if (version_compare(PHP_VERSION, '5.2.0RC5', '>=')) {
        if (is_resource($connection) && version_compare(PHP_VERSION, '5.2.0RC5', '>=')) {
            $text = @pg_escape_string($connection, $text);
        } else {
            $text = @pg_escape_string($text);
@@ -353,13 +363,18 @@
    // {{{ _doConnect()
    /**
     * Does the grunt work of connecting to the database
     * Do the grunt work of connecting to the database
     *
     * @return mixed connection resource on success, MDB2 Error Object on failure
     * @access protected
     **/
    function _doConnect($database_name, $persistent = false)
     */
    function _doConnect($username, $password, $database_name, $persistent = false)
    {
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        if ($database_name == '') {
            $database_name = 'template1';
        }
@@ -386,11 +401,11 @@
        if ($database_name) {
            $params[0].= ' dbname=\'' . addslashes($database_name) . '\'';
        }
        if ($this->dsn['username']) {
            $params[0].= ' user=\'' . addslashes($this->dsn['username']) . '\'';
        if ($username) {
            $params[0].= ' user=\'' . addslashes($username) . '\'';
        }
        if ($this->dsn['password']) {
            $params[0].= ' password=\'' . addslashes($this->dsn['password']) . '\'';
        if ($password) {
            $params[0].= ' password=\'' . addslashes($password) . '\'';
        }
        if (!empty($this->dsn['options'])) {
            $params[0].= ' options=' . $this->dsn['options'];
@@ -417,7 +432,6 @@
        }
        $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
        $connection = @call_user_func_array($connect_function, $params);
        if (!$connection) {
            return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
@@ -449,7 +463,7 @@
     *
     * @return true on success, MDB2 Error Object on failure
     * @access public
     **/
     */
    function connect()
    {
        if (is_resource($this->connection)) {
@@ -463,22 +477,22 @@
            $this->disconnect(false);
        }
        if (!PEAR::loadExtension($this->phptype)) {
            return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
                'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
        }
        if ($this->database_name) {
            $connection = $this->_doConnect($this->database_name, $this->options['persistent']);
            $connection = $this->_doConnect($this->dsn['username'],
                                            $this->dsn['password'],
                                            $this->database_name,
                                            $this->options['persistent']);
            if (PEAR::isError($connection)) {
                return $connection;
            }
            $this->connection = $connection;
            $this->connected_dsn = $this->dsn;
            $this->connected_database_name = $this->database_name;
            $this->opened_persistent = $this->options['persistent'];
            $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
        }
        return MDB2_OK;
    }
@@ -501,13 +515,40 @@
                return $connection;
            }
        }
        if (is_array($charset)) {
            $charset   = array_shift($charset);
            $this->warnings[] = 'postgresql does not support setting client collation';
        }
        $result = @pg_set_client_encoding($connection, $charset);
        if ($result == -1) {
            return $this->raiseError(null, null, null,
                'Unable to set client charset: '.$charset, __FUNCTION__);
        }
        return MDB2_OK;
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        $res = $this->_doConnect($this->dsn['username'],
                                 $this->dsn['password'],
                                 $this->escape($name),
                                 $this->options['persistent']);
        if (!PEAR::isError($res)) {
            return true;
        }
        return false;
    }
    // }}}
@@ -560,11 +601,11 @@
     */
    function &standaloneQuery($query, $types = null, $is_manip = false)
    {
        $connection = $this->_doConnect('template1', false);
        $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
        $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
        $connection = $this->_doConnect($user, $pass, $this->database_name, $this->options['persistent']);
        if (PEAR::isError($connection)) {
            $err =& $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
                'Cannot connect to template1', __FUNCTION__);
            return $err;
            return $connection;
        }
        $offset = $this->offset;
@@ -572,17 +613,16 @@
        $this->offset = $this->limit = 0;
        $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
        $result =& $this->_doQuery($query, $is_manip, $connection, false);
        @pg_close($connection);
        if (PEAR::isError($result)) {
            return $result;
        $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name);
        if (!PEAR::isError($result)) {
            if ($is_manip) {
                $result =  $this->_affectedRows($connection, $result);
            } else {
                $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset);
            }
        }
        if ($is_manip) {
            $affected_rows =  $this->_affectedRows($connection, $result);
            return $affected_rows;
        }
        $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset);
        @pg_close($connection);
        return $result;
    }
@@ -910,8 +950,8 @@
            return $connection;
        }
        static $prep_statement_counter = 1;
        $statement_name = sprintf($this->options['statement_format'], $this->phptype, sha1(microtime() + mt_rand())) . $prep_statement_counter++;
        $statement_name = strtolower($statement_name);
        $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand()));
        $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']);
        if ($pgtypes === false) {
            $result = @pg_prepare($connection, $statement_name, $query);
            if (!$result) {
@@ -975,7 +1015,7 @@
                           WHERE d.adrelid = a.attrelid
                             AND d.adnum = a.attnum
                             AND a.atthasdef
                         ) FROM 'nextval[^\']*\'([^\']*)')
                         ) FROM 'nextval[^'']*''([^'']*)')
                        FROM pg_attribute a
                    LEFT JOIN pg_class c ON c.oid = a.attrelid
                    LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef
@@ -1017,9 +1057,11 @@
    {
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
        $query = "SELECT NEXTVAL('$sequence_name')";
        $this->pushErrorHandling(PEAR_ERROR_RETURN);
        $this->expectError(MDB2_ERROR_NOSUCHTABLE);
        $result = $this->queryOne($query, 'integer');
        $this->popExpect();
        $this->popErrorHandling();
        if (PEAR::isError($result)) {
            if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
                $this->loadModule('Manager', null, true);
@@ -1052,7 +1094,7 @@
            return $this->queryOne('SELECT lastval()', 'integer');
        }
        $seq = $table.(empty($field) ? '' : '_'.$field);
        $sequence_name = $this->getSequenceName($seq);
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq), true);
        return $this->queryOne("SELECT currval('$sequence_name')", 'integer');
    }
program/lib/MDB2/Driver/sqlite.php
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
// | Stig. S. Bakken, Lukas Smith                                         |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
@@ -43,7 +43,7 @@
// | Author: Lukas Smith <smith@pooteeweet.org>                           |
// +----------------------------------------------------------------------+
//
// $Id: sqlite.php,v 1.152 2007/11/27 07:44:41 quipo Exp $
// $Id: sqlite.php,v 1.158 2008/03/08 14:18:39 quipo Exp $
//
/**
@@ -89,6 +89,7 @@
        $this->supported['transactions'] = true;
        $this->supported['savepoints'] = false;
        $this->supported['sub_selects'] = true;
        $this->supported['triggers'] = true;
        $this->supported['auto_increment'] = true;
        $this->supported['primary_key'] = false; // requires alter table implementation
        $this->supported['result_introspection'] = false; // not implemented
@@ -97,11 +98,14 @@
        $this->supported['pattern_escaping'] = false;
        $this->supported['new_link'] = false;
        $this->options['DBA_username'] = false;
        $this->options['DBA_password'] = false;
        $this->options['base_transaction_name'] = '___php_MDB2_sqlite_auto_commit_off';
        $this->options['fixed_float'] = 0;
        $this->options['database_path'] = '';
        $this->options['database_extension'] = '';
        $this->options['server_version'] = '';
        $this->options['max_identifiers_length'] = 128; //no real limit
    }
    // }}}
@@ -125,7 +129,7 @@
            
        // PHP 5.2+ prepends the function name to $php_errormsg, so we need
        // this hack to work around it, per bug #9599.
        $native_msg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $native_msg);
        $native_msg = preg_replace('/^sqlite[a-z_]+\(\)[^:]*: /', '', $native_msg);
        if (is_null($error)) {
            static $error_regexps;
@@ -425,6 +429,24 @@
    }
    // }}}
    // {{{ databaseExists()
    /**
     * check if given database name is exists?
     *
     * @param string $name    name of the database that should be checked
     *
     * @return mixed true/false on success, a MDB2 error on failure
     * @access public
     */
    function databaseExists($name)
    {
        $database_file = $this->_getDatabaseFile($name);
        $result = file_exists($database_file);
        return $result;
    }
    // }}}
    // {{{ disconnect()
    /**
@@ -721,7 +743,7 @@
                $query .= ',';
                $values.= ',';
            }
            $query.= $name;
            $query.= $this->quoteIdentifier($name, true);
            if (isset($fields[$name]['null']) && $fields[$name]['null']) {
                $value = 'NULL';
            } else {
@@ -750,6 +772,7 @@
            return $connection;
        }
        $table = $this->quoteIdentifier($table, true);
        $query = "REPLACE INTO $table ($query) VALUES ($values)";
        $result =& $this->_doQuery($query, true, $connection);
        if (PEAR::isError($result)) {
@@ -777,9 +800,11 @@
        $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
        $seqcol_name = $this->options['seqcol_name'];
        $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
        $this->pushErrorHandling(PEAR_ERROR_RETURN);
        $this->expectError(MDB2_ERROR_NOSUCHTABLE);
        $result =& $this->_doQuery($query, true);
        $this->popExpect();
        $this->popErrorHandling();
        if (PEAR::isError($result)) {
            if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
                $this->loadModule('Manager', null, true);