summaryrefslogtreecommitdiffstats
path: root/system/database/drivers
diff options
context:
space:
mode:
authorAndrey Andreev <narf@bofh.bg>2012-02-10 13:27:44 +0100
committerAndrey Andreev <narf@bofh.bg>2012-02-10 13:27:44 +0100
commit6f6704f3283a7b663f1598bc6013e6658d8d269b (patch)
tree8574a6dcaf138972452a3d12ab0c9882e3029cc8 /system/database/drivers
parent1fb51fdd28eb7c24431849ad3b6ab35cab9596f6 (diff)
parent16af6afe991381360439135ddb0735dab1280fed (diff)
Merge remote-tracking branch 'upstream/develop' into develop-db-sqlsrv
Diffstat (limited to 'system/database/drivers')
-rw-r--r--system/database/drivers/pdo/pdo_driver.php272
-rw-r--r--system/database/drivers/pdo/pdo_forge.php12
-rw-r--r--system/database/drivers/pdo/pdo_result.php67
3 files changed, 272 insertions, 79 deletions
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 4f4f44ba7..fc378daeb 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -46,9 +46,10 @@ class CI_DB_pdo_driver extends CI_DB {
// the character used to excape - not necessary for PDO
var $_escape_char = '';
+
+ // clause and character used for LIKE escape sequences
var $_like_escape_str;
var $_like_escape_chr;
-
/**
* The syntax to count rows is slightly different across different
@@ -57,29 +58,36 @@ class CI_DB_pdo_driver extends CI_DB {
*/
var $_count_string = "SELECT COUNT(*) AS ";
var $_random_keyword;
-
+
+ // need to track the pdo DSN, driver and options
+ var $dsn;
+ var $pdodriver;
var $options = array();
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->_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 = '!';
@@ -90,14 +98,85 @@ class CI_DB_pdo_driver extends CI_DB {
$this->_like_escape_chr = '!';
}
- if (strpos($this->hostname, 'sqlite') === FALSE)
+ $this->trans_enabled = FALSE;
+ $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
+ }
+
+ /**
+ * Connection String
+ *
+ * @access private
+ * @param array
+ * @return void
+ */
+ function _connect_string($params)
+ {
+ if (strpos($this->hostname, ':'))
{
- $this->hostname .= ";dbname=".$this->database;
+ // hostname generally would have this prototype
+ // $db['hostname'] = 'pdodriver:host(/Server(/DSN))=hostname(/DSN);';
+ // We need to get the prefix (pdodriver used by PDO).
+ $this->dsn = $this->hostname;
+ $this->pdodriver = substr($this->hostname, 0, strpos($this->hostname, ':'));
}
-
- $this->trans_enabled = FALSE;
+ else
+ {
+ // Invalid DSN, display an error
+ if ( ! array_key_exists('pdodriver', $params))
+ {
+ show_error('Invalid DB Connection String for PDO');
+ }
- $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
+ // 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) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'sybase', 'mssql', 'dblib', 'cubrid')))
+ {
+ $this->dsn .= 'host='.$this->hostname.';';
+ }
+
+ // 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.';';
+ }
+ }
+
+ // 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.';';
+ }
}
/**
@@ -108,9 +187,9 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function db_connect()
{
- $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT;
-
- return new PDO($this->hostname, $this->username, $this->password, $this->options);
+ $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT;
+
+ return $this->pdo_connect();
}
// --------------------------------------------------------------------
@@ -123,10 +202,44 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function db_pconnect()
{
- $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT;
- $this->options['PDO::ATTR_PERSISTENT'] = TRUE;
+ $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);
+ return $this->pdo_connect();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * PDO connection
+ *
+ * @access private called by the PDO driver class
+ * @return resource
+ */
+ function pdo_connect()
+ {
+ // Refer : http://php.net/manual/en/ref.pdo-mysql.connection.php
+ if ($this->pdodriver == 'mysql' && is_php('5.3.6'))
+ {
+ $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES $this->char_set COLLATE '$this->dbcollat'";
+ }
+
+ // Connecting...
+ try
+ {
+ $db = 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;
+ }
+
+ return $db;
}
// --------------------------------------------------------------------
@@ -146,6 +259,7 @@ class CI_DB_pdo_driver extends CI_DB {
{
return $this->db->display_error('db_unsuported_feature');
}
+
return FALSE;
}
@@ -175,7 +289,6 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function db_set_charset($charset, $collation)
{
- // @todo - add support if needed
return TRUE;
}
@@ -204,6 +317,7 @@ class CI_DB_pdo_driver extends CI_DB {
function _execute($sql)
{
$sql = $this->_prep_query($sql);
+
$result_id = $this->conn_id->query($sql);
if (is_object($result_id))
@@ -231,6 +345,17 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function _prep_query($sql)
{
+ if ($this->pdodriver === 'pgsql')
+ {
+ // Change the backtick(s) for Postgre
+ $sql = str_replace('`', '"', $sql);
+ }
+ elseif ($this->pdodriver === 'sqlite')
+ {
+ // Change the backtick(s) for SQLite
+ $sql = str_replace('`', '', $sql);
+ }
+
return $sql;
}
@@ -285,6 +410,7 @@ class CI_DB_pdo_driver extends CI_DB {
}
$ret = $this->conn->commit();
+
return $ret;
}
@@ -310,6 +436,7 @@ class CI_DB_pdo_driver extends CI_DB {
}
$ret = $this->conn_id->rollBack();
+
return $ret;
}
@@ -348,7 +475,9 @@ class CI_DB_pdo_driver extends CI_DB {
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),
+ array($this->_like_escape_chr.'%',
+ $this->_like_escape_chr.'_',
+ $this->_like_escape_chr.$this->_like_escape_chr),
$str);
}
@@ -378,9 +507,9 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function insert_id($name=NULL)
{
- //Convenience method for postgres insertid
- if (strpos($this->hostname, 'pgsql') !== FALSE)
+ if ($this->pdodriver == 'pgsql')
{
+ //Convenience method for postgres insertid
$v = $this->_version();
$table = func_num_args() > 0 ? func_get_arg(0) : NULL;
@@ -389,8 +518,10 @@ class CI_DB_pdo_driver extends CI_DB {
{
$sql='SELECT LASTVAL() as ins_id';
}
+
$query = $this->query($sql);
- $row = $query->row();
+ $row = $query->row();
+
return $row->ins_id;
}
else
@@ -418,7 +549,9 @@ class CI_DB_pdo_driver extends CI_DB {
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 ';
+ $sql .= $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+ $query = $this->query($sql);
if ($query->num_rows() == 0)
{
@@ -427,6 +560,7 @@ class CI_DB_pdo_driver extends CI_DB {
$row = $query->row();
$this->_reset_select();
+
return (int) $row->numrows;
}
@@ -443,12 +577,19 @@ class CI_DB_pdo_driver extends CI_DB {
*/
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'";
+ }
+ else
+ {
+ $sql = "SHOW TABLES FROM `".$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;
@@ -467,7 +608,7 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function _list_columns($table = '')
{
- return "SHOW COLUMNS FROM ".$table;
+ return 'SHOW COLUMNS FROM '.$this->_from_tables($table);
}
// --------------------------------------------------------------------
@@ -483,7 +624,7 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function _field_data($table)
{
- return "SELECT TOP 1 FROM ".$table;
+ return 'SELECT TOP 1 FROM '.$this->_from_tables($table);
}
// --------------------------------------------------------------------
@@ -497,6 +638,7 @@ class CI_DB_pdo_driver extends CI_DB {
function _error_message()
{
$error_array = $this->conn_id->errorInfo();
+
return $error_array[2];
}
@@ -544,8 +686,8 @@ class CI_DB_pdo_driver extends CI_DB {
if (strpos($item, '.') !== FALSE)
{
- $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-
+ $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
+ $str .= $this->_escape_char;
}
else
{
@@ -575,7 +717,7 @@ class CI_DB_pdo_driver extends CI_DB {
$tables = array($tables);
}
- return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')';
+ return (count($tables) == 1) ? '`'.$tables[0].'`' : '('.implode(', ', $tables).')';
}
// --------------------------------------------------------------------
@@ -593,7 +735,7 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function _insert($table, $keys, $values)
{
- return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+ return 'INSERT INTO '.$this->_from_tables($table).' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
}
// --------------------------------------------------------------------
@@ -611,7 +753,7 @@ class CI_DB_pdo_driver extends CI_DB {
*/
function _insert_batch($table, $keys, $values)
{
- return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
+ return 'INSERT INTO '.$this->_from_tables($table).' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
}
// --------------------------------------------------------------------
@@ -636,14 +778,11 @@ class CI_DB_pdo_driver extends CI_DB {
$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) : '';
+ $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
+ $orderby = (count($orderby) >= 1) ? ' ORDER BY '.implode(', ', $orderby) : '';
+ $sql = 'UPDATE '.$this->_from_tables($table).' SET '.implode(', ', $valstr);
+ $sql .= ($where != '' && count($where) >= 1) ? ' WHERE '.implode(' ', $where) : '';
$sql .= $orderby.$limit;
return $sql;
@@ -664,8 +803,8 @@ class CI_DB_pdo_driver extends CI_DB {
*/
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 +819,13 @@ class CI_DB_pdo_driver extends CI_DB {
}
}
- $sql = "UPDATE ".$table." SET ";
+ $sql = 'UPDATE '.$this->_from_tables($table).' SET ';
$cases = '';
foreach ($final as $k => $v)
{
$cases .= $k.' = CASE '."\n";
+
foreach ($v as $row)
{
$cases .= $row."\n";
@@ -695,7 +835,6 @@ class CI_DB_pdo_driver extends CI_DB {
}
$sql .= substr($cases, 0, -2);
-
$sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
return $sql;
@@ -739,19 +878,20 @@ class CI_DB_pdo_driver extends CI_DB {
if (count($where) > 0 OR count($like) > 0)
{
- $conditions = "\nWHERE ";
+ $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 '.$this->_from_tables($table).$conditions.$limit;
}
// --------------------------------------------------------------------
@@ -769,27 +909,16 @@ class CI_DB_pdo_driver extends CI_DB {
*/
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;
-
- if ($offset > 0)
- {
- $sql .= " OFFSET ".$offset;
- }
+ $sql .= 'LIMIT '.$limit;
+ $sql .= ($offset > 0) ? ' OFFSET '.$offset : '';
return $sql;
}
@@ -809,10 +938,7 @@ class CI_DB_pdo_driver extends CI_DB {
$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..478b2dbfb 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -96,7 +96,7 @@ 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)
@@ -111,6 +111,7 @@ 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);
@@ -118,7 +119,11 @@ class CI_DB_pdo_forge extends CI_DB_forge {
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)
@@ -219,7 +224,7 @@ class CI_DB_pdo_forge extends CI_DB_forge {
*/
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')
@@ -271,7 +276,6 @@ class CI_DB_pdo_forge extends CI_DB_forge {
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..c333abc40 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -39,6 +39,16 @@
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
@@ -46,7 +56,59 @@ class CI_DB_pdo_result extends CI_DB_result {
*/
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
+ *
+ * @access public
+ * @return mixed
+ */
+ 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();
+ $this->_data_seek(0);
+
+ 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;
}
// --------------------------------------------------------------------
@@ -78,6 +140,7 @@ class CI_DB_pdo_result extends CI_DB_result {
{
return $this->db->display_error('db_unsuported_feature');
}
+
return FALSE;
}
@@ -110,6 +173,7 @@ class CI_DB_pdo_result extends CI_DB_result {
{
return $this->db->display_error('db_unsuported_feature');
}
+
return FALSE;
}
}
@@ -178,6 +242,5 @@ class CI_DB_pdo_result extends CI_DB_result {
}
-
/* End of file pdo_result.php */
/* Location: ./system/database/drivers/pdo/pdo_result.php */ \ No newline at end of file