diff options
Diffstat (limited to 'system/database/drivers/pdo')
-rw-r--r-- | system/database/drivers/pdo/pdo_driver.php | 670 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_forge.php | 124 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_result.php | 169 | ||||
-rw-r--r-- | system/database/drivers/pdo/pdo_utility.php | 73 |
4 files changed, 422 insertions, 614 deletions
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php index 4f4f44ba7..60151b900 100644 --- a/system/database/drivers/pdo/pdo_driver.php +++ b/system/database/drivers/pdo/pdo_driver.php @@ -1,13 +1,13 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * PDO Database Adapter Class * @@ -42,196 +40,238 @@ */ class CI_DB_pdo_driver extends CI_DB { - var $dbdriver = 'pdo'; + public $dbdriver = 'pdo'; // the character used to excape - not necessary for PDO - var $_escape_char = ''; - var $_like_escape_str; - var $_like_escape_chr; - + protected $_escape_char = ''; + + // clause and character used for LIKE escape sequences + protected $_like_escape_str = " ESCAPE '%s' "; + protected $_like_escape_chr = '!'; /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is * used for the count_all() and count_all_results() functions. */ - var $_count_string = "SELECT COUNT(*) AS "; - var $_random_keyword; - - var $options = array(); + protected $_count_string = 'SELECT COUNT(*) AS '; + protected $_random_keyword; - function __construct($params) + // need to track the pdo driver and options + public $pdodriver; + public $options = array(); + + public function __construct($params) { parent::__construct($params); - + + if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) == 2) + { + // If there is a minimum valid dsn string pattern found, we're done + // This is for general PDO users, who tend to have a full DSN string. + $this->pdodriver = end($match); + } + else + { + // Try to build a complete DSN string from params + $this->_connect_string($params); + } + // clause and character used for LIKE escape sequences - if (strpos($this->hostname, 'mysql') !== FALSE) + // this one depends on the driver being used + if ($this->pdodriver == 'mysql') { + $this->_escape_char = '`'; $this->_like_escape_str = ''; $this->_like_escape_chr = ''; - - //Prior to this version, the charset can't be set in the dsn - if(is_php('5.3.6')) - { - $this->hostname .= ";charset={$this->char_set}"; - } - - //Set the charset with the connection options - $this->options['PDO::MYSQL_ATTR_INIT_COMMAND'] = "SET NAMES {$this->char_set}"; } - else if (strpos($this->hostname, 'odbc') !== FALSE) + elseif ($this->pdodriver == 'odbc') { $this->_like_escape_str = " {escape '%s'} "; - $this->_like_escape_chr = '!'; } - else - { - $this->_like_escape_str = " ESCAPE '%s' "; - $this->_like_escape_chr = '!'; - } - - if (strpos($this->hostname, 'sqlite') === FALSE) + elseif ( ! in_array($this->pdodriver, array('sqlsrv', 'mssql', 'dblib', 'sybase'))) { - $this->hostname .= ";dbname=".$this->database; + $this->_escape_char = '"'; } - - $this->trans_enabled = FALSE; + $this->trans_enabled = FALSE; $this->_random_keyword = ' RND('.time().')'; // database specific random keyword } /** - * Non-persistent database connection + * Connection String * - * @access private called by the base class - * @return resource + * @param array + * @return void */ - function db_connect() + protected function _connect_string($params) { - $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; - - return new PDO($this->hostname, $this->username, $this->password, $this->options); - } + if (strpos($this->hostname, ':')) + { + // hostname generally would have this prototype + // $db['hostname'] = 'pdodriver:host(/Server(/DSN))=hostname(/DSN);'; + // We need to get the prefix (pdodriver used by PDO). + $dsnarray = explode(':', $this->hostname); + $this->pdodriver = $dsnarray[0]; - // -------------------------------------------------------------------- + // End dsn with a semicolon for extra backward compability + // if database property was not empty. + if ( ! empty($this->database)) + { + $this->dsn .= rtrim($this->hostname, ';').';'; + } + } + else + { + // Invalid DSN, display an error + if ( ! array_key_exists('pdodriver', $params)) + { + show_error('Invalid DB Connection String for PDO'); + } - /** - * Persistent database connection - * - * @access private called by the base class - * @return resource - */ - function db_pconnect() - { - $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; - $this->options['PDO::ATTR_PERSISTENT'] = TRUE; - - return new PDO($this->hostname, $this->username, $this->password, $this->options); - } + // Assuming that the following DSN string format is used: + // $dsn = 'pdo://username:password@hostname:port/database?pdodriver=pgsql'; + $this->dsn = $this->pdodriver.':'; - // -------------------------------------------------------------------- + // Add hostname to the DSN for databases that need it + if ( ! empty($this->hostname) + && strpos($this->hostname, ':') === FALSE + && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'sybase', 'mssql', 'dblib', 'cubrid'))) + { + $this->dsn .= 'host='.$this->hostname.';'; + } - /** - * Reconnect - * - * Keep / reestablish the db connection if no queries have been - * sent for a length of time exceeding the server's idle timeout - * - * @access public - * @return void - */ - function reconnect() - { - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); + // Add a port to the DSN for databases that can use it + if ( ! empty($this->port) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'ibm', 'cubrid'))) + { + $this->dsn .= 'port='.$this->port.';'; + } } - return FALSE; + + // Add the database name to the DSN, if needed + if (stripos($this->dsn, 'dbname') === FALSE + && in_array($this->pdodriver, array('4D', 'pgsql', 'mysql', 'firebird', 'sybase', 'mssql', 'dblib', 'cubrid'))) + { + $this->dsn .= 'dbname='.$this->database.';'; + } + elseif (stripos($this->dsn, 'database') === FALSE && in_array($this->pdodriver, array('ibm', 'sqlsrv'))) + { + if (stripos($this->dsn, 'dsn') === FALSE) + { + $this->dsn .= 'database='.$this->database.';'; + } + } + elseif ($this->pdodriver === 'sqlite' && $this->dsn === 'sqlite:') + { + if ($this->database !== ':memory') + { + if ( ! file_exists($this->database)) + { + show_error('Invalid DB Connection string for PDO SQLite'); + } + + $this->dsn .= (strpos($this->database, DIRECTORY_SEPARATOR) !== 0) ? DIRECTORY_SEPARATOR : ''; + } + + $this->dsn .= $this->database; + } + + // Add charset to the DSN, if needed + if ( ! empty($this->char_set) && in_array($this->pdodriver, array('4D', 'mysql', 'sybase', 'mssql', 'dblib', 'oci'))) + { + $this->dsn .= 'charset='.$this->char_set.';'; + } } // -------------------------------------------------------------------- /** - * Select the database + * Non-persistent database connection * - * @access private called by the base class - * @return resource + * @return object */ - function db_select() + public function db_connect() { - // Not needed for PDO - return TRUE; + return $this->_pdo_connect(); } // -------------------------------------------------------------------- /** - * Set client character set + * Persistent database connection * - * @access public - * @param string - * @param string - * @return resource + * @return object */ - function db_set_charset($charset, $collation) + public function db_pconnect() { - // @todo - add support if needed - return TRUE; + return $this->_pdo_connect(TRUE); } // -------------------------------------------------------------------- /** - * Version number query string + * PDO connection * - * @access public - * @return string + * @param bool + * @return object */ - function _version() + protected function _pdo_connect($persistent = FALSE) { - return $this->conn_id->getAttribute(PDO::ATTR_CLIENT_VERSION); + $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; + $persistent === FALSE OR $this->options[PDO::ATTR_PERSISTENT] = TRUE; + + /* Prior to PHP 5.3.6, even if the charset was supplied in the DSN + * on connect - it was ignored. This is a work-around for the issue. + * + * Reference: http://www.php.net/manual/en/ref.pdo-mysql.connection.php + */ + if ($this->subdriver === 'mysql' && ! is_php('5.3.6') && ! empty($this->char_set)) + { + $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set + .( ! empty($this->db_collat) ? " COLLATE '".$this->dbcollat."'" : ''); + } + + // Connecting... + try + { + return new PDO($this->dsn, $this->username, $this->password, $this->options); + } + catch (PDOException $e) + { + if ($this->db_debug && empty($this->failover)) + { + $this->display_error($e->getMessage(), '', TRUE); + } + + return FALSE; + } } // -------------------------------------------------------------------- /** - * Execute the query + * Database version number * - * @access private called by the base class - * @param string an SQL query - * @return object + * @return string */ - function _execute($sql) + public function version() { - $sql = $this->_prep_query($sql); - $result_id = $this->conn_id->query($sql); - - if (is_object($result_id)) - { - $this->affect_rows = $result_id->rowCount(); - } - else - { - $this->affect_rows = 0; - } - - return $result_id; + return isset($this->data_cache['version']) + ? $this->data_cache['version'] + : $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION); } // -------------------------------------------------------------------- /** - * Prep the query - * - * If needed, each database adapter can prep the query string + * Execute the query * - * @access private called by execute() * @param string an SQL query - * @return string + * @return mixed */ - function _prep_query($sql) + protected function _execute($sql) { - return $sql; + return $this->conn_id->query($sql); } // -------------------------------------------------------------------- @@ -239,18 +279,12 @@ class CI_DB_pdo_driver extends CI_DB { /** * Begin Transaction * - * @access public * @return bool */ - function trans_begin($test_mode = FALSE) + public function trans_begin($test_mode = FALSE) { - if ( ! $this->trans_enabled) - { - return TRUE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - if ($this->_trans_depth > 0) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -258,7 +292,7 @@ class CI_DB_pdo_driver extends CI_DB { // Reset the transaction failure flag. // If the $test_mode flag is set to TRUE transactions will be rolled back // even if the queries produce a successful result. - $this->_trans_failure = (bool) ($test_mode === TRUE); + $this->_trans_failure = ($test_mode === TRUE); return $this->conn_id->beginTransaction(); } @@ -268,24 +302,17 @@ class CI_DB_pdo_driver extends CI_DB { /** * Commit Transaction * - * @access public * @return bool */ - function trans_commit() + public function trans_commit() { - if ( ! $this->trans_enabled) - { - return TRUE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - if ($this->_trans_depth > 0) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } - $ret = $this->conn->commit(); - return $ret; + return $this->conn_id->commit(); } // -------------------------------------------------------------------- @@ -293,24 +320,17 @@ class CI_DB_pdo_driver extends CI_DB { /** * Rollback Transaction * - * @access public * @return bool */ - function trans_rollback() + public function trans_rollback() { - if ( ! $this->trans_enabled) - { - return TRUE; - } - // When transactions are nested we only begin/commit/rollback the outermost ones - if ($this->_trans_depth > 0) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } - $ret = $this->conn_id->rollBack(); - return $ret; + return $this->conn_id->rollBack(); } // -------------------------------------------------------------------- @@ -318,12 +338,11 @@ class CI_DB_pdo_driver extends CI_DB { /** * Escape String * - * @access public * @param string * @param bool whether or not the string will be used in a LIKE condition * @return string */ - function escape_str($str, $like = FALSE) + public function escape_str($str, $like = FALSE) { if (is_array($str)) { @@ -334,22 +353,22 @@ class CI_DB_pdo_driver extends CI_DB { return $str; } - - //Escape the string + + // Escape the string $str = $this->conn_id->quote($str); - - //If there are duplicated quotes, trim them away + + // If there are duplicated quotes, trim them away if (strpos($str, "'") === 0) { $str = substr($str, 1, -1); } - + // escape LIKE condition wildcards if ($like === TRUE) { - $str = str_replace( array('%', '_', $this->_like_escape_chr), - array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), - $str); + return str_replace(array($this->_like_escape_chr, '%', '_'), + array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'), + $str); } return $str; @@ -360,43 +379,31 @@ class CI_DB_pdo_driver extends CI_DB { /** * Affected Rows * - * @access public - * @return integer + * @return int */ - function affected_rows() + public function affected_rows() { - return $this->affect_rows; + return is_object($this->result_id) ? $this->result_id->rowCount() : 0; } // -------------------------------------------------------------------- /** * Insert ID - * - * @access public - * @return integer + * + * @param string + * @return int */ - function insert_id($name=NULL) + public function insert_id($name = NULL) { - //Convenience method for postgres insertid - if (strpos($this->hostname, 'pgsql') !== FALSE) + if ($this->pdodriver === 'pgsql' && $name === NULL && $this->version() >= '8.1') { - $v = $this->_version(); - - $table = func_num_args() > 0 ? func_get_arg(0) : NULL; - - if ($table == NULL && $v >= '8.1') - { - $sql='SELECT LASTVAL() as ins_id'; - } - $query = $this->query($sql); - $row = $query->row(); - return $row->ins_id; - } - else - { - return $this->conn_id->lastInsertId($name); + $query = $this->query('SELECT LASTVAL() AS ins_id'); + $query = $query->row(); + return $query->ins_id; } + + return $this->conn_id->lastInsertId($name); } // -------------------------------------------------------------------- @@ -407,18 +414,18 @@ class CI_DB_pdo_driver extends CI_DB { * Generates a platform-specific query string that counts all records in * the specified database * - * @access public * @param string * @return string */ - function count_all($table = '') + public function count_all($table = '') { if ($table == '') { return 0; } - $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + $sql = $this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); + $query = $this->query($sql); if ($query->num_rows() == 0) { @@ -427,6 +434,7 @@ class CI_DB_pdo_driver extends CI_DB { $row = $query->row(); $this->_reset_select(); + return (int) $row->numrows; } @@ -437,18 +445,29 @@ class CI_DB_pdo_driver extends CI_DB { * * Generates a platform-specific query string so that the table names can be fetched * - * @access private - * @param boolean + * @param bool * @return string */ - function _list_tables($prefix_limit = FALSE) + protected function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES FROM `".$this->database."`"; + if ($this->pdodriver == 'pgsql') + { + // Analog function to show all tables in postgre + $sql = "SELECT * FROM information_schema.tables WHERE table_schema = 'public'"; + } + elseif ($this->pdodriver == 'sqlite') + { + // Analog function to show all tables in sqlite + $sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"; + } + else + { + $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database); + } if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); - return FALSE; // not currently supported + return FALSE; } return $sql; @@ -461,13 +480,12 @@ class CI_DB_pdo_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @access public * @param string the table name * @return string */ - function _list_columns($table = '') + protected function _list_columns($table = '') { - return "SHOW COLUMNS FROM ".$table; + return 'SHOW COLUMNS FROM '.$this->escape_identifiers($table); } // -------------------------------------------------------------------- @@ -477,83 +495,57 @@ class CI_DB_pdo_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @access public * @param string the table name - * @return object - */ - function _field_data($table) - { - return "SELECT TOP 1 FROM ".$table; - } - - // -------------------------------------------------------------------- - - /** - * The error message string - * - * @access private * @return string */ - function _error_message() + protected function _field_data($table) { - $error_array = $this->conn_id->errorInfo(); - return $error_array[2]; - } - - // -------------------------------------------------------------------- + if ($this->pdodriver == 'mysql' or $this->pdodriver == 'pgsql') + { + // Analog function for mysql and postgre + return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1'; + } + elseif ($this->pdodriver == 'oci') + { + // Analog function for oci + return 'SELECT * FROM '.$this->escape_identifiers($table).' WHERE ROWNUM <= 1'; + } + elseif ($this->pdodriver == 'sqlite') + { + // Analog function for sqlite + return 'PRAGMA table_info('.$this->escape_identifiers($table).')'; + } - /** - * The error message number - * - * @access private - * @return integer - */ - function _error_number() - { - return $this->conn_id->errorCode(); + return 'SELECT TOP 1 FROM '.$this->escape_identifiers($table); } // -------------------------------------------------------------------- /** - * Escape the SQL Identifiers + * Error * - * This function escapes column and table names + * Returns an array containing code and message of the last + * database error that has occured. * - * @access private - * @param string - * @return string + * @return array */ - function _escape_identifiers($item) + public function error() { - if ($this->_escape_char == '') - { - return $item; - } + $error = array('code' => '00000', 'message' => ''); + $pdo_error = $this->conn_id->errorInfo(); - foreach ($this->_reserved_identifiers as $id) + if (empty($pdo_error[0])) { - if (strpos($item, '.'.$id) !== FALSE) - { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - - // remove duplicates if the user already included the escape - return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + return $error; } - if (strpos($item, '.') !== FALSE) - { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; - - } - else + $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0]; + if (isset($pdo_error[2])) { - $str = $this->_escape_char.$item.$this->_escape_char; + $error['message'] = $pdo_error[2]; } - // remove duplicates if the user already included the escape - return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + return $error; } // -------------------------------------------------------------------- @@ -564,108 +556,35 @@ class CI_DB_pdo_driver extends CI_DB { * This function implicitly groups FROM tables so there is no confusion * about operator precedence in harmony with SQL standards * - * @access public - * @param type - * @return type + * @param array + * @return string */ - function _from_tables($tables) + protected function _from_tables($tables) { if ( ! is_array($tables)) { $tables = array($tables); } - return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')'; - } - - // -------------------------------------------------------------------- - - /** - * Insert statement - * - * Generates a platform-specific insert string from the supplied data - * - * @access public - * @param string the table name - * @param array the insert keys - * @param array the insert values - * @return string - */ - function _insert($table, $keys, $values) - { - return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; - } - - // -------------------------------------------------------------------- - - /** - * Insert_batch statement - * - * Generates a platform-specific insert string from the supplied data - * - * @access public - * @param string the table name - * @param array the insert keys - * @param array the insert values - * @return string - */ - function _insert_batch($table, $keys, $values) - { - return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @access public - * @param string the table name - * @param array the update data - * @param array the where clause - * @param array the orderby clause - * @param array the limit clause - * @return string - */ - function _update($table, $values, $where, $orderby = array(), $limit = FALSE) - { - foreach ($values as $key => $val) - { - $valstr[] = $key." = ".$val; - } - - $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - - $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - - $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); - - $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; - - $sql .= $orderby.$limit; - - return $sql; - } - - // -------------------------------------------------------------------- - - /** * Update_Batch statement * * Generates a platform-specific batch update string from the supplied data * - * @access public * @param string the table name * @param array the update data * @param array the where clause * @return string */ - function _update_batch($table, $values, $index, $where = NULL) + protected function _update_batch($table, $values, $index, $where = NULL) { - $ids = array(); - $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + $ids = array(); + $where = ($where != '' && count($where) >=1) ? implode(" ", $where).' AND ' : ''; foreach ($values as $key => $val) { @@ -680,12 +599,13 @@ class CI_DB_pdo_driver extends CI_DB { } } - $sql = "UPDATE ".$table." SET "; + $sql = 'UPDATE '.$table.' SET '; $cases = ''; foreach ($final as $k => $v) { $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) { $cases .= $row."\n"; @@ -695,63 +615,27 @@ class CI_DB_pdo_driver extends CI_DB { } $sql .= substr($cases, 0, -2); - $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; return $sql; } - // -------------------------------------------------------------------- /** * Truncate statement * * Generates a platform-specific truncate string from the supplied data - * If the database does not support the truncate() command - * This function maps to "DELETE FROM table" * - * @access public - * @param string the table name - * @return string - */ - function _truncate($table) - { - return $this->_delete($table); - } - - // -------------------------------------------------------------------- - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data + * If the database does not support the truncate() command, + * then this method maps to 'DELETE FROM table' * - * @access public * @param string the table name - * @param array the where clause - * @param string the limit clause * @return string */ - function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _truncate($table) { - $conditions = ''; - - if (count($where) > 0 OR count($like) > 0) - { - $conditions = "\nWHERE "; - $conditions .= implode("\n", $this->ar_where); - - if (count($where) > 0 && count($like) > 0) - { - $conditions .= " AND "; - } - $conditions .= implode("\n", $like); - } - - $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - - return "DELETE FROM ".$table.$conditions.$limit; + return 'DELETE FROM '.$table; } // -------------------------------------------------------------------- @@ -761,36 +645,24 @@ class CI_DB_pdo_driver extends CI_DB { * * Generates a platform-specific LIMIT clause * - * @access public * @param string the sql query string - * @param integer the number of rows to limit the query to - * @param integer the offset value + * @param int the number of rows to limit the query to + * @param int the offset value * @return string */ - function _limit($sql, $limit, $offset) + protected function _limit($sql, $limit, $offset) { - if (strpos($this->hostname, 'cubrid') !== FALSE || strpos($this->hostname, 'sqlite') !== FALSE) + if ($this->pdodriver == 'cubrid' OR $this->pdodriver == 'sqlite') { - if ($offset == 0) - { - $offset = ''; - } - else - { - $offset .= ", "; - } + $offset = ($offset == 0) ? '' : $offset.', '; - return $sql."LIMIT ".$offset.$limit; + return $sql.'LIMIT '.$offset.$limit; } else { - $sql .= "LIMIT ".$limit; + $sql .= 'LIMIT '.$limit; + $sql .= ($offset > 0) ? ' OFFSET '.$offset : ''; - if ($offset > 0) - { - $sql .= " OFFSET ".$offset; - } - return $sql; } } @@ -800,19 +672,15 @@ class CI_DB_pdo_driver extends CI_DB { /** * Close DB Connection * - * @access public - * @param resource + * @param object * @return void */ - function _close($conn_id) + protected function _close($conn_id) { - $this->conn_id = null; + $this->conn_id = NULL; } - } - - /* End of file pdo_driver.php */ /* Location: ./system/database/drivers/pdo/pdo_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php index 076415928..ca8657a0f 100644 --- a/system/database/drivers/pdo/pdo_forge.php +++ b/system/database/drivers/pdo/pdo_forge.php @@ -1,13 +1,13 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * PDO Forge Class * @@ -36,58 +34,20 @@ */ class CI_DB_pdo_forge extends CI_DB_forge { - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database() - { - // PDO has no "create database" command since it's - // designed to connect to an existing database - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - // PDO has no "drop database" command since it's - // designed to connect to an existing database - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- + protected $_drop_database = 'DROP DATABASE %s'; + protected $_drop_table = 'DROP TABLE %s'; /** * Create Table * - * @access private * @param string the table name * @param array the fields * @param mixed primary key(s) * @param mixed key(s) - * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @param bool should 'IF NOT EXISTS' be added to the SQL * @return bool */ - function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; @@ -96,10 +56,10 @@ class CI_DB_pdo_forge extends CI_DB_forge { $sql .= 'IF NOT EXISTS '; } - $sql .= $this->db->_escape_identifiers($table)." ("; + $sql .= $this->db->escape_identifiers($table).' ('; $current_field_count = 0; - foreach ($fields as $field=>$attributes) + foreach ($fields as $field => $attributes) { // Numeric field names aren't allowed in databases, so if the key is // numeric, we know it was assigned by PHP and the developer manually @@ -111,14 +71,19 @@ class CI_DB_pdo_forge extends CI_DB_forge { else { $attributes = array_change_key_case($attributes, CASE_UPPER); + $numeric = array('SERIAL', 'INTEGER'); - $sql .= "\n\t".$this->db->_protect_identifiers($field); + $sql .= "\n\t".$this->db->protect_identifiers($field); $sql .= ' '.$attributes['TYPE']; if (array_key_exists('CONSTRAINT', $attributes)) { - $sql .= '('.$attributes['CONSTRAINT'].')'; + // Exception for Postgre numeric which not too happy with constraint within those type + if ( ! ($this->db->pdodriver == 'pgsql' && in_array($attributes['TYPE'], $numeric))) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } } if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) @@ -155,7 +120,7 @@ class CI_DB_pdo_forge extends CI_DB_forge { if (count($primary_keys) > 0) { - $primary_keys = $this->db->_protect_identifiers($primary_keys); + $primary_keys = $this->db->protect_identifiers($primary_keys); $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; } @@ -165,11 +130,11 @@ class CI_DB_pdo_forge extends CI_DB_forge { { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->protect_identifiers($key); } else { - $key = array($this->db->_protect_identifiers($key)); + $key = array($this->db->protect_identifiers($key)); } $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; @@ -184,42 +149,23 @@ class CI_DB_pdo_forge extends CI_DB_forge { // -------------------------------------------------------------------- /** - * Drop Table - * - * @access private - * @return bool - */ - function _drop_table($table) - { - // Not a supported PDO feature - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- - - /** * Alter table query * * Generates a platform-specific query so that a table can be altered * Called by add_column(), drop_column(), and column_alter(), * - * @access private * @param string the ALTER type (ADD, DROP, CHANGE) * @param string the column name * @param string the table name * @param string the column definition * @param string the default value - * @param boolean should 'NOT NULL' be added + * @param bool should 'NOT NULL' be added * @param string the field after which we should add the new field - * @return object + * @return string */ - function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') { - $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + $sql = 'ALTER TABLE `'.$this->db->protect_identifiers($table).'` '.$alter_type.' '.$this->db->protect_identifiers($column_name); // DROP has everything it needs now. if ($alter_type == 'DROP') @@ -245,33 +191,13 @@ class CI_DB_pdo_forge extends CI_DB_forge { if ($after_field != '') { - $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + return $sql.' AFTER '.$this->db->protect_identifiers($after_field); } return $sql; } - - // -------------------------------------------------------------------- - - /** - * Rename a table - * - * Generates a platform-specific query so that a table can be renamed - * - * @access private - * @param string the old table name - * @param string the new table name - * @return string - */ - function _rename_table($table_name, $new_table_name) - { - $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); - return $sql; - } - - } /* End of file pdo_forge.php */ diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php index 6b523b001..19aee1dfc 100644 --- a/system/database/drivers/pdo/pdo_result.php +++ b/system/database/drivers/pdo/pdo_result.php @@ -1,13 +1,13 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * PDO Result Class * @@ -39,14 +37,73 @@ class CI_DB_pdo_result extends CI_DB_result { /** + * @var bool Hold the flag whether a result handler already fetched before + */ + protected $is_fetched = FALSE; + + /** + * @var mixed Hold the fetched assoc array of a result handler + */ + protected $result_assoc; + + /** * Number of rows in the result set * - * @access public - * @return integer + * @return int */ - function num_rows() + public function num_rows() { - return $this->result_id->rowCount(); + if (empty($this->result_id) OR ! is_object($this->result_id)) + { + // invalid result handler + return 0; + } + elseif (($num_rows = $this->result_id->rowCount()) && $num_rows > 0) + { + // If rowCount return something, we're done. + return $num_rows; + } + + // Fetch the result, instead perform another extra query + return ($this->is_fetched && is_array($this->result_assoc)) ? count($this->result_assoc) : count($this->result_assoc()); + } + + /** + * Fetch the result handler + * + * @return mixed + */ + public function result_assoc() + { + // If the result already fetched before, use that one + if (count($this->result_array) > 0 OR $this->is_fetched) + { + return $this->result_array(); + } + + // Define the output + $output = array('assoc', 'object'); + + // Fetch the result + foreach ($output as $type) + { + // Define the method and handler + $res_method = '_fetch_'.$type; + $res_handler = 'result_'.$type; + + $this->$res_handler = array(); + + while ($row = $this->$res_method()) + { + $this->{$res_handler}[] = $row; + } + } + + // Save this as buffer and marked the fetch flag + $this->result_array = $this->result_assoc; + $this->is_fetched = TRUE; + + return $this->result_assoc; } // -------------------------------------------------------------------- @@ -54,10 +111,9 @@ class CI_DB_pdo_result extends CI_DB_result { /** * Number of fields in the result set * - * @access public - * @return integer + * @return int */ - function num_fields() + public function num_fields() { return $this->result_id->columnCount(); } @@ -69,15 +125,15 @@ class CI_DB_pdo_result extends CI_DB_result { * * Generates an array of column names * - * @access public - * @return array + * @return bool */ - function list_fields() + public function list_fields() { if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); } + return FALSE; } @@ -88,20 +144,58 @@ class CI_DB_pdo_result extends CI_DB_result { * * Generates an array of objects containing field meta-data * - * @access public * @return array */ - function field_data() + public function field_data() { $data = array(); - + try { - for($i = 0; $i < $this->num_fields(); $i++) + if (strpos($this->result_id->queryString, 'PRAGMA') !== FALSE) + { + foreach ($this->result_array() as $field) + { + preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field['type'], $matches); + + $F = new stdClass(); + $F->name = $field['name']; + $F->type = ( ! empty($matches[1])) ? $matches[1] : NULL; + $F->default = NULL; + $F->max_length = ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL; + $F->primary_key = (int) $field['pk']; + $F->pdo_type = NULL; + + $data[] = $F; + } + } + else { - $data[] = $this->result_id->getColumnMeta($i); + for($i = 0, $max = $this->num_fields(); $i < $max; $i++) + { + $field = $this->result_id->getColumnMeta($i); + + $F = new stdClass(); + $F->name = $field['name']; + $F->type = $field['native_type']; + $F->default = NULL; + $F->pdo_type = $field['pdo_type']; + + if ($field['precision'] < 0) + { + $F->max_length = NULL; + $F->primary_key = 0; + } + else + { + $F->max_length = ($field['len'] > 255) ? 0 : $field['len']; + $F->primary_key = (int) ( ! empty($field['flags']) && in_array('primary_key', $field['flags'])); + } + + $data[] = $F; + } } - + return $data; } catch (Exception $e) @@ -110,6 +204,7 @@ class CI_DB_pdo_result extends CI_DB_result { { return $this->db->display_error('db_unsuported_feature'); } + return FALSE; } } @@ -119,9 +214,9 @@ class CI_DB_pdo_result extends CI_DB_result { /** * Free the result * - * @return null + * @return void */ - function free_result() + public function free_result() { if (is_object($this->result_id)) { @@ -132,31 +227,13 @@ class CI_DB_pdo_result extends CI_DB_result { // -------------------------------------------------------------------- /** - * Data Seek - * - * Moves the internal pointer to the desired offset. We call - * this internally before fetching results to make sure the - * result set starts at zero - * - * @access private - * @return array - */ - function _data_seek($n = 0) - { - return FALSE; - } - - // -------------------------------------------------------------------- - - /** * Result - associative array * * Returns the result set as an array * - * @access private * @return array */ - function _fetch_assoc() + protected function _fetch_assoc() { return $this->result_id->fetch(PDO::FETCH_ASSOC); } @@ -168,16 +245,14 @@ class CI_DB_pdo_result extends CI_DB_result { * * Returns the result set as an object * - * @access private * @return object */ - function _fetch_object() - { + protected function _fetch_object() + { return $this->result_id->fetchObject(); } } - /* End of file pdo_result.php */ /* Location: ./system/database/drivers/pdo/pdo_result.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php index 971ec8803..930842118 100644 --- a/system/database/drivers/pdo/pdo_utility.php +++ b/system/database/drivers/pdo/pdo_utility.php @@ -1,13 +1,13 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -25,8 +25,6 @@ * @filesource */ -// ------------------------------------------------------------------------ - /** * PDO Utility Class * @@ -36,74 +34,15 @@ */ class CI_DB_pdo_utility extends CI_DB_utility { - /** - * List databases - * - * @access private - * @return bool - */ - function _list_databases() - { - // Not sure if PDO lets you list all databases... - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Optimize table query - * - * Generates a platform-specific query so that a table can be optimized - * - * @access private - * @param string the table name - * @return object - */ - function _optimize_table($table) - { - // Not a supported PDO feature - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Repair table query - * - * Generates a platform-specific query so that a table can be repaired - * - * @access private - * @param string the table name - * @return object - */ - function _repair_table($table) - { - // Not a supported PDO feature - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- + protected $_list_databases = FALSE; /** * PDO Export * - * @access private * @param array Preferences * @return mixed */ - function _backup($params = array()) + protected function _backup($params = array()) { // Currently unsupported return $this->db->display_error('db_unsuported_feature'); |