alecpl
2008-05-02 d1403fd7268ccf96ab6e7d04506ea1b1802c7eb2
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);