| | |
| | | // +----------------------------------------------------------------------+
|
| | | // | 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. |
|
| | | // +----------------------------------------------------------------------+
|
| | |
| | | // | 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 $ |
| | | //
|
| | |
|
| | | /**
|
| | |
| | | $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;
|
| | |
| | | $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(); |
| | | }
|
| | |
|
| | | // }}}
|
| | |
| | | 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,
|
| | |
| | | 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) {
|
| | |
| | | }
|
| | |
|
| | | // }}}
|
| | | // {{{ 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__);
|
| | |
| | | $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)
|
| | | ) {
|
| | |
| | | $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) {
|
| | |
| | | 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;
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | $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;
|
| | |
| | | /**
|
| | | * 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
|
| | |
| | | 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; |
| | | }
|
| | |
|
| | | // }}}
|
| | |
| | | }
|
| | | }
|
| | | 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; |
| | | }
|
| | |
|
| | | // }}}
|
| | |
| | | //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; |
| | | }
|
| | | }
|
| | | }
|
| | |
| | | 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)) {
|
| | |
| | | $query .= ',';
|
| | | $values.= ',';
|
| | | }
|
| | | $query.= $name;
|
| | | $query.= $this->quoteIdentifier($name, true); |
| | | if (isset($fields[$name]['null']) && $fields[$name]['null']) {
|
| | | $value = 'NULL';
|
| | | } else {
|
| | |
| | | return $connection;
|
| | | }
|
| | |
|
| | | $table = $this->quoteIdentifier($table, true); |
| | | $query = "REPLACE INTO $table ($query) VALUES ($values)";
|
| | | $result =& $this->_doQuery($query, true, $connection);
|
| | | if (PEAR::isError($result)) {
|
| | |
| | | $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);
|