summaryrefslogtreecommitdiffstats
path: root/system/database
diff options
context:
space:
mode:
Diffstat (limited to 'system/database')
-rw-r--r--system/database/DB.php59
-rw-r--r--system/database/DB_cache.php72
-rw-r--r--system/database/DB_driver.php413
-rw-r--r--system/database/DB_forge.php722
-rw-r--r--system/database/DB_query_builder.php968
-rw-r--r--system/database/DB_result.php236
-rw-r--r--system/database/DB_utility.php85
-rw-r--r--system/database/drivers/cubrid/cubrid_driver.php145
-rw-r--r--system/database/drivers/cubrid/cubrid_forge.php264
-rw-r--r--system/database/drivers/cubrid/cubrid_result.php24
-rw-r--r--system/database/drivers/cubrid/cubrid_utility.php5
-rw-r--r--system/database/drivers/ibase/ibase_driver.php167
-rw-r--r--system/database/drivers/ibase/ibase_forge.php215
-rw-r--r--system/database/drivers/ibase/ibase_result.php7
-rw-r--r--system/database/drivers/ibase/ibase_utility.php7
-rw-r--r--system/database/drivers/mssql/mssql_driver.php247
-rw-r--r--system/database/drivers/mssql/mssql_forge.php164
-rw-r--r--system/database/drivers/mssql/mssql_result.php26
-rw-r--r--system/database/drivers/mssql/mssql_utility.php20
-rw-r--r--system/database/drivers/mysql/mysql_driver.php155
-rw-r--r--system/database/drivers/mysql/mysql_forge.php242
-rw-r--r--system/database/drivers/mysql/mysql_result.php17
-rw-r--r--system/database/drivers/mysql/mysql_utility.php26
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php158
-rw-r--r--system/database/drivers/mysqli/mysqli_forge.php242
-rw-r--r--system/database/drivers/mysqli/mysqli_result.php12
-rw-r--r--system/database/drivers/mysqli/mysqli_utility.php26
-rw-r--r--system/database/drivers/oci8/oci8_driver.php248
-rw-r--r--system/database/drivers/oci8/oci8_forge.php151
-rw-r--r--system/database/drivers/oci8/oci8_result.php93
-rw-r--r--system/database/drivers/oci8/oci8_utility.php14
-rw-r--r--system/database/drivers/odbc/odbc_driver.php106
-rw-r--r--system/database/drivers/odbc/odbc_forge.php131
-rw-r--r--system/database/drivers/odbc/odbc_result.php17
-rw-r--r--system/database/drivers/odbc/odbc_utility.php11
-rw-r--r--system/database/drivers/pdo/pdo_driver.php354
-rw-r--r--system/database/drivers/pdo/pdo_forge.php130
-rw-r--r--system/database/drivers/pdo/pdo_result.php62
-rw-r--r--system/database/drivers/pdo/pdo_utility.php11
-rw-r--r--system/database/drivers/pdo/subdrivers/index.html10
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_4d_driver.php192
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_4d_forge.php209
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php247
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php219
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php329
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php136
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php260
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php229
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php236
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php146
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_informix_driver.php301
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_informix_forge.php155
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php283
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php229
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_oci_driver.php291
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_oci_forge.php133
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php258
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php62
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php357
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php195
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php202
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php229
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php363
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php136
-rw-r--r--system/database/drivers/postgre/postgre_driver.php301
-rw-r--r--system/database/drivers/postgre/postgre_forge.php257
-rw-r--r--system/database/drivers/postgre/postgre_result.php12
-rw-r--r--system/database/drivers/postgre/postgre_utility.php22
-rw-r--r--system/database/drivers/sqlite/sqlite_driver.php82
-rw-r--r--system/database/drivers/sqlite/sqlite_forge.php195
-rw-r--r--system/database/drivers/sqlite/sqlite_result.php16
-rw-r--r--system/database/drivers/sqlite/sqlite_utility.php11
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php104
-rw-r--r--system/database/drivers/sqlite3/sqlite3_forge.php207
-rw-r--r--system/database/drivers/sqlite3/sqlite3_result.php38
-rw-r--r--system/database/drivers/sqlite3/sqlite3_utility.php13
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_driver.php246
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_forge.php164
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_result.php19
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_utility.php22
80 files changed, 10029 insertions, 3139 deletions
diff --git a/system/database/DB.php b/system/database/DB.php
index 032cf1b76..f4062fa73 100644
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Initialize the database
@@ -31,8 +32,10 @@
* @category Database
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/database/
- * @param string
- * @param bool Determines if query builder should be used or not
+ *
+ * @param string|string[] $params
+ * @param bool $query_builder_override
+ * Determines if query builder should be used or not
*/
function &DB($params = '', $query_builder_override = NULL)
{
@@ -47,18 +50,18 @@ function &DB($params = '', $query_builder_override = NULL)
}
include($file_path);
- //make packages contain database config files
- foreach(get_instance()->load->get_package_paths() as $path)
+ // Make packages contain database config files
+ foreach (get_instance()->load->get_package_paths() as $path)
{
if ($path !== APPPATH)
{
- if (file_exists ($file_path = $path.'config/'.ENVIRONMENT.'/database.php'))
+ if (file_exists($file_path = $path.'config/'.ENVIRONMENT.'/database.php'))
{
- include ($file_path);
+ include($file_path);
}
- elseif ( file_exists ($file_path = $path.'config/database.php'))
+ elseif (file_exists($file_path = $path.'config/database.php'))
{
- include ($file_path);
+ include($file_path);
}
}
}
@@ -82,12 +85,12 @@ function &DB($params = '', $query_builder_override = NULL)
}
elseif (is_string($params))
{
-
- /* parse the URL from the DSN string
- * Database settings can be passed as discreet
- * parameters or as a data source name in the first
- * parameter. DSNs must have this prototype:
- * $dsn = 'driver://username:password@hostname/database';
+ /**
+ * Parse the URL from the DSN string
+ * Database settings can be passed as discreet
+ * parameters or as a data source name in the first
+ * parameter. DSNs must have this prototype:
+ * $dsn = 'driver://username:password@hostname/database';
*/
if (($dsn = @parse_url($params)) === FALSE)
{
@@ -103,7 +106,7 @@ function &DB($params = '', $query_builder_override = NULL)
'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : ''
);
- // were additional config items set?
+ // Were additional config items set?
if (isset($dsn['query']))
{
parse_str($dsn['query'], $extra);
@@ -148,11 +151,22 @@ function &DB($params = '', $query_builder_override = NULL)
require_once(BASEPATH.'database/DB_query_builder.php');
if ( ! class_exists('CI_DB'))
{
+ /**
+ * CI_DB
+ *
+ * Acts as an alias for both CI_DB_driver and CI_DB_query_builder.
+ *
+ * @see CI_DB_query_builder
+ * @see CI_DB_driver
+ */
class CI_DB extends CI_DB_query_builder { }
}
}
elseif ( ! class_exists('CI_DB'))
{
+ /**
+ * @ignore
+ */
class CI_DB extends CI_DB_driver { }
}
@@ -170,6 +184,19 @@ function &DB($params = '', $query_builder_override = NULL)
$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
$DB = new $driver($params);
+ // Check for a subdriver
+ if ( ! empty($DB->subdriver))
+ {
+ $driver_file = BASEPATH.'database/drivers/'.$DB->dbdriver.'/subdrivers/'.$DB->dbdriver.'_'.$DB->subdriver.'_driver.php';
+
+ if (file_exists($driver_file))
+ {
+ require_once($driver_file);
+ $driver = 'CI_DB_'.$DB->dbdriver.'_'.$DB->subdriver.'_driver';
+ $DB = new $driver($params);
+ }
+ }
+
if ($DB->autoinit === TRUE)
{
$DB->initialize();
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index ba9110382..fd01dc2d8 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Cache Class
@@ -34,15 +35,39 @@
*/
class CI_DB_Cache {
+ /**
+ * CI Singleton
+ *
+ * @var object
+ */
public $CI;
- public $db; // allows passing of db object so that multiple database connections and returned db objects can be supported
+ /**
+ * Database object
+ *
+ * Allows passing of DB object so that multiple database connections
+ * and returned DB objects can be supported.
+ *
+ * @var object
+ */
+ public $db;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param object &$db
+ * @return void
+ */
public function __construct(&$db)
{
// Assign the main CI object to $this->CI and load the file helper since we use it a lot
$this->CI =& get_instance();
$this->db =& $db;
$this->CI->load->helper('file');
+
+ $this->check_path();
}
// --------------------------------------------------------------------
@@ -50,7 +75,7 @@ class CI_DB_Cache {
/**
* Set Cache Directory Path
*
- * @param string the path to the cache directory
+ * @param string $path Path to the cache directory
* @return bool
*/
public function check_path($path = '')
@@ -66,14 +91,26 @@ class CI_DB_Cache {
}
// Add a trailing slash to the path if needed
- $path = preg_replace('/(.+?)\/*$/', '\\1/', $path);
+ $path = realpath($path)
+ ? rtrim(realpath($path), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR
+ : rtrim($path, '/').'/';
- if ( ! is_dir($path) OR ! is_really_writable($path))
+ if ( ! is_dir($path))
{
+ log_message('debug', 'DB cache path error: '.$path);
+
// If the path is wrong we'll turn off caching
return $this->db->cache_off();
}
+ if ( ! is_really_writable($path))
+ {
+ log_message('debug', 'DB cache dir not writable: '.$path);
+
+ // If the path is not really writable we'll turn off caching
+ return $this->db->cache_off();
+ }
+
$this->db->cachedir = $path;
return TRUE;
}
@@ -84,22 +121,18 @@ class CI_DB_Cache {
* Retrieve a cached query
*
* The URI being requested will become the name of the cache sub-folder.
- * An MD5 hash of the SQL statement will become the cache file name
+ * An MD5 hash of the SQL statement will become the cache file name.
*
+ * @param string $sql
* @return string
*/
public function read($sql)
{
- if ( ! $this->check_path())
- {
- return $this->db->cache_off();
- }
-
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
- if (FALSE === ($cachedata = file_get_contents($filepath)))
+ if (FALSE === ($cachedata = @file_get_contents($filepath)))
{
return FALSE;
}
@@ -112,15 +145,12 @@ class CI_DB_Cache {
/**
* Write a query to a cache file
*
+ * @param string $sql
+ * @param object $object
* @return bool
*/
public function write($sql, $object)
{
- if ( ! $this->check_path())
- {
- return $this->db->cache_off();
- }
-
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';
@@ -150,7 +180,9 @@ class CI_DB_Cache {
/**
* Delete cache files within a particular directory
*
- * @return bool
+ * @param string $segment_one
+ * @param string $segment_two
+ * @return void
*/
public function delete($segment_one = '', $segment_two = '')
{
@@ -173,11 +205,11 @@ class CI_DB_Cache {
/**
* Delete all existing cache files
*
- * @return bool
+ * @return void
*/
public function delete_all()
{
- delete_files($this->db->cachedir, TRUE, 0, TRUE);
+ delete_files($this->db->cachedir, TRUE, TRUE);
}
}
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 1060ecc6c..2d5b91541 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Driver Class
@@ -40,54 +41,314 @@
*/
abstract class CI_DB_driver {
+ /**
+ * Data Source Name / Connect string
+ *
+ * @var string
+ */
public $dsn;
+
+ /**
+ * Username
+ *
+ * @var string
+ */
public $username;
+
+ /**
+ * Password
+ *
+ * @var string
+ */
public $password;
+
+ /**
+ * Hostname
+ *
+ * @var string
+ */
public $hostname;
+
+ /**
+ * Database name
+ *
+ * @var string
+ */
public $database;
+
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'mysqli';
+
+ /**
+ * Sub-driver
+ *
+ * @used-by CI_DB_pdo_driver
+ * @var string
+ */
+ public $subdriver;
+
+ /**
+ * Table prefix
+ *
+ * @var string
+ */
public $dbprefix = '';
+
+ /**
+ * Character set
+ *
+ * @var string
+ */
public $char_set = 'utf8';
+
+ /**
+ * Collation
+ *
+ * @var string
+ */
public $dbcollat = 'utf8_general_ci';
- public $autoinit = TRUE; // Whether to automatically initialize the DB
+
+ /**
+ * Auto-init flag
+ *
+ * Whether to automatically initialize the DB connection.
+ *
+ * @var bool
+ */
+ public $autoinit = TRUE;
+
+ /**
+ * Encryption flag/data
+ *
+ * @var mixed
+ */
+ public $encrypt = FALSE;
+
+ /**
+ * Swap Prefix
+ *
+ * @var string
+ */
public $swap_pre = '';
+
+ /**
+ * Database port
+ *
+ * @var int
+ */
public $port = '';
+
+ /**
+ * Persistent connection flag
+ *
+ * @var bool
+ */
public $pconnect = FALSE;
+
+ /**
+ * Connection ID
+ *
+ * @var object|resource
+ */
public $conn_id = FALSE;
+
+ /**
+ * Result ID
+ *
+ * @var object|resource
+ */
public $result_id = FALSE;
+
+ /**
+ * Debug flag
+ *
+ * Whether to display error messages.
+ *
+ * @var bool
+ */
public $db_debug = FALSE;
+
+ /**
+ * Benchmark time
+ *
+ * @var int
+ */
public $benchmark = 0;
+
+ /**
+ * Executed queries count
+ *
+ * @var int
+ */
public $query_count = 0;
+
+ /**
+ * Bind marker
+ *
+ * Character used to identify values in a prepared statement.
+ *
+ * @var string
+ */
public $bind_marker = '?';
+
+ /**
+ * Save queries flag
+ *
+ * Whether to keep an in-memory history of queries for debugging purposes.
+ *
+ * @var bool
+ */
public $save_queries = TRUE;
+
+ /**
+ * Queries list
+ *
+ * @see CI_DB_driver::$save_queries
+ * @var string[]
+ */
public $queries = array();
+
+ /**
+ * Query times
+ *
+ * A list of times that queries took to execute.
+ *
+ * @var array
+ */
public $query_times = array();
+
+ /**
+ * Data cache
+ *
+ * An internal generic value cache.
+ *
+ * @var array
+ */
public $data_cache = array();
+ /**
+ * Transaction enabled flag
+ *
+ * @var bool
+ */
public $trans_enabled = TRUE;
+
+ /**
+ * Strict transaction mode flag
+ *
+ * @var bool
+ */
public $trans_strict = TRUE;
+
+ /**
+ * Transaction depth level
+ *
+ * @var int
+ */
protected $_trans_depth = 0;
- protected $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
+ /**
+ * Transaction status flag
+ *
+ * Used with transactions to determine if a rollback should occur.
+ *
+ * @var bool
+ */
+ protected $_trans_status = TRUE;
+
+ /**
+ * Cache On flag
+ *
+ * @var bool
+ */
public $cache_on = FALSE;
+
+ /**
+ * Cache directory path
+ *
+ * @var bool
+ */
public $cachedir = '';
+
+ /**
+ * Cache auto-delete flag
+ *
+ * @var bool
+ */
public $cache_autodel = FALSE;
- public $CACHE; // The cache class object
+ /**
+ * DB Cache object
+ *
+ * @see CI_DB_cache
+ * @var object
+ */
+ public $CACHE;
+
+ /**
+ * Protect identifiers flag
+ *
+ * @var bool
+ */
protected $_protect_identifiers = TRUE;
- protected $_reserved_identifiers = array('*'); // Identifiers that should NOT be escaped
/**
- * 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.
+ * List of reserved identifiers
+ *
+ * Identifiers that must NOT be escaped.
+ *
+ * @var string[]
+ */
+ protected $_reserved_identifiers = array('*');
+
+ /**
+ * Identifier escape character
+ *
+ * @var string
+ */
+ protected $_escape_char = '"';
+
+ /**
+ * ESCAPE statement string
+ *
+ * @var string
+ */
+ protected $_like_escape_str = " ESCAPE '%s' ";
+
+ /**
+ * ESCAPE character
+ *
+ * @var string
+ */
+ protected $_like_escape_chr = '!';
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RAND()', 'RAND(%d)');
+
+ /**
+ * COUNT string
+ *
+ * @used-by CI_DB_driver::count_all()
+ * @used-by CI_DB_query_builder::count_all_results()
+ *
+ * @var string
*/
protected $_count_string = 'SELECT COUNT(*) AS ';
+ // --------------------------------------------------------------------
+
/**
- * Constructor
+ * Class constructor
*
- * @param array
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -304,8 +565,9 @@ abstract class CI_DB_driver {
* FALSE upon failure, and if the $db_debug variable is set to TRUE
* will raise an error.
*
- * @param string An SQL query string
- * @param array An array of binding data
+ * @param string $sql
+ * @param array $binds = FALSE An array of binding data
+ * @param bool $return_object = NULL
* @return mixed
*/
public function query($sql, $binds = FALSE, $return_object = NULL)
@@ -430,7 +692,7 @@ abstract class CI_DB_driver {
// resource ID won't be any good once we've cached the
// result object, so we'll have to compile the data
// and save it)
- $CR = new CI_DB_result();
+ $CR = new CI_DB_result($this);
$CR->result_object = $RES->result_object();
$CR->result_array = $RES->result_array();
$CR->num_rows = $RES->num_rows();
@@ -508,6 +770,7 @@ abstract class CI_DB_driver {
* If strict mode is disabled, each group is treated autonomously, meaning
* a failure of one group will not affect any others
*
+ * @param bool $mode = TRUE
* @return void
*/
public function trans_strict($mode = TRUE)
@@ -520,6 +783,7 @@ abstract class CI_DB_driver {
/**
* Start Transaction
*
+ * @param bool $test_mode = FALSE
* @return void
*/
public function trans_start($test_mode = FALSE)
@@ -631,7 +895,7 @@ abstract class CI_DB_driver {
// Make sure not to replace a chunk inside a string that happens to match the bind marker
if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
{
- $c = preg_match_all('/'.preg_quote($this->bind_marker).'/i',
+ $c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i',
str_replace($matches[0],
str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]),
$sql, $c),
@@ -643,7 +907,7 @@ abstract class CI_DB_driver {
return $sql;
}
}
- elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker).'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
+ elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
{
return $sql;
}
@@ -668,7 +932,7 @@ abstract class CI_DB_driver {
*/
public function is_write_type($sql)
{
- return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+ return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
}
// --------------------------------------------------------------------
@@ -721,7 +985,7 @@ abstract class CI_DB_driver {
*/
public function escape($str)
{
- if (is_string($str) OR method_exists($str, '__toString'))
+ if (is_string($str) OR (is_object($str) && method_exists($str, '__toString')))
{
return "'".$this->escape_str($str)."'";
}
@@ -804,6 +1068,7 @@ abstract class CI_DB_driver {
/**
* Returns an array of table names
*
+ * @param string $constrain_by_prefix = FALSE
* @return array
*/
public function list_tables($constrain_by_prefix = FALSE)
@@ -858,6 +1123,7 @@ abstract class CI_DB_driver {
/**
* Determine if a particular table exists
*
+ * @param string $table_name
* @return bool
*/
public function table_exists($table_name)
@@ -970,7 +1236,7 @@ abstract class CI_DB_driver {
*/
public function escape_identifiers($item)
{
- if ($this->_escape_char === '' OR empty($item))
+ if ($this->_escape_char === '' OR empty($item) OR in_array($item, $this->_reserved_identifiers))
{
return $item;
}
@@ -984,7 +1250,7 @@ abstract class CI_DB_driver {
return $item;
}
// Avoid breaking functions and literal values inside queries
- elseif (ctype_digit($item) OR $item[0] === "'" OR strpos($item, '(') !== FALSE)
+ elseif (ctype_digit($item) OR $item[0] === "'" OR ($this->_escape_char !== '"' && $item[0] === '"') OR strpos($item, '(') !== FALSE)
{
return $item;
}
@@ -996,13 +1262,13 @@ abstract class CI_DB_driver {
if (is_array($this->_escape_char))
{
$preg_ec = array(
- preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]),
+ preg_quote($this->_escape_char[0], '/'), preg_quote($this->_escape_char[1], '/'),
$this->_escape_char[0], $this->_escape_char[1]
);
}
else
{
- $preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+ $preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char, '/');
$preg_ec[2] = $preg_ec[3] = $this->_escape_char;
}
}
@@ -1069,44 +1335,20 @@ abstract class CI_DB_driver {
*/
public function update_string($table, $data, $where)
{
- if ($where === '')
+ if (empty($where))
{
return FALSE;
}
+ $this->where($where);
+
$fields = array();
foreach ($data as $key => $val)
{
$fields[$this->protect_identifiers($key)] = $this->escape($val);
}
- if ( ! is_array($where))
- {
- $dest = array($where);
- }
- else
- {
- $dest = array();
- foreach ($where as $key => $val)
- {
- $prefix = (count($dest) === 0) ? '' : ' AND ';
- $key = $this->protect_identifiers($key);
-
- if ($val !== '')
- {
- if ( ! $this->_has_operator($key))
- {
- $key .= ' =';
- }
-
- $val = ' '.$this->escape($val);
- }
-
- $dest[] = $prefix.$key.$val;
- }
- }
-
- return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
+ return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields);
}
// --------------------------------------------------------------------
@@ -1118,30 +1360,19 @@ abstract class CI_DB_driver {
*
* @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
- * @param array the like clause
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
foreach ($values as $key => $val)
{
$valstr[] = $key.' = '.$val;
}
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
- .($limit ? ' LIMIT '.$limit : '');
+ .$this->_compile_wh('qb_where')
+ .$this->_compile_order_by()
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -1154,7 +1385,7 @@ abstract class CI_DB_driver {
*/
protected function _has_operator($str)
{
- return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
+ return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
}
// --------------------------------------------------------------------
@@ -1167,8 +1398,30 @@ abstract class CI_DB_driver {
*/
protected function _get_operator($str)
{
- return preg_match('/(=|!|<|>| IS NULL| IS NOT NULL| BETWEEN)/i', $str, $match)
- ? $match[1] : FALSE;
+ static $_operators;
+
+ if (empty($_operators))
+ {
+ $_les = ($this->_like_escape_str !== '')
+ ? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)), '/')
+ : '';
+ $_operators = array(
+ '\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
+ '\s*<>?\s*', // <, <>
+ '\s*>\s*', // >
+ '\s+IS NULL', // IS NULL
+ '\s+IS NOT NULL', // IS NOT NULL
+ '\s+BETWEEN\s+\S+\s+AND\s+\S+', // BETWEEN value AND value
+ '\s+IN\s*\([^\)]+\)', // IN(list)
+ '\s+NOT IN\s*\([^\)]+\)', // NOT IN (list)
+ '\s+LIKE\s+\S+'.$_les, // LIKE 'expr'[ ESCAPE '%s']
+ '\s+NOT LIKE\s+\S+'.$_les // NOT LIKE 'expr'[ ESCAPE '%s']
+ );
+
+ }
+
+ return preg_match('/'.implode('|', $_operators).'/i', $str, $match)
+ ? $match[0] : FALSE;
}
// --------------------------------------------------------------------
@@ -1176,8 +1429,7 @@ abstract class CI_DB_driver {
/**
* Enables a native PHP function to be run, using a platform agnostic wrapper.
*
- * @param string the function name
- * @param mixed any parameters needed by the function
+ * @param string $function Function name
* @return mixed
*/
public function call_function($function)
@@ -1241,6 +1493,8 @@ abstract class CI_DB_driver {
/**
* Delete the cache files associated with a particular URI
*
+ * @param string $segment_one = ''
+ * @param string $segment_two = ''
* @return bool
*/
public function cache_delete($segment_one = '', $segment_two = '')
@@ -1342,7 +1596,7 @@ abstract class CI_DB_driver {
}
else
{
- $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
+ $message = is_array($error) ? $error : array(str_replace('%s', $swap, $LANG->line($error)));
}
// Find the most likely culprit of the error by going through
@@ -1351,12 +1605,21 @@ abstract class CI_DB_driver {
$trace = debug_backtrace();
foreach ($trace as $call)
{
- if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
+ if (isset($call['file'], $call['class']))
{
- // Found it - use a relative path for safety
- $message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
- $message[] = 'Line Number: '.$call['line'];
- break;
+ // We'll need this on Windows, as APPPATH and BASEPATH will always use forward slashes
+ if (DIRECTORY_SEPARATOR !== '/')
+ {
+ $call['file'] = str_replace('\\', '/', $call['file']);
+ }
+
+ if (strpos($call['file'], BASEPATH.'database') === FALSE && strpos($call['class'], 'Loader') === FALSE)
+ {
+ // Found it - use a relative path for safety
+ $message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
+ $message[] = 'Line Number: '.$call['line'];
+ break;
+ }
}
}
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index 91f9d560c..59c3baf8b 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Forge Class
@@ -34,22 +35,127 @@
*/
abstract class CI_DB_forge {
+ /**
+ * Database object
+ *
+ * @var object
+ */
+ protected $db;
+
+ /**
+ * Fields data
+ *
+ * @var array
+ */
public $fields = array();
+
+ /**
+ * Keys data
+ *
+ * @var array
+ */
public $keys = array();
+
+ /**
+ * Primary Keys data
+ *
+ * @var array
+ */
public $primary_keys = array();
- public $db_char_set = '';
- // Platform specific SQL strings
+ /**
+ * Database character set
+ *
+ * @var string
+ */
+ public $db_char_set = '';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
protected $_create_database = 'CREATE DATABASE %s';
+
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
protected $_drop_database = 'DROP DATABASE %s';
- protected $_drop_table = 'DROP TABLE IF EXISTS %s';
- protected $_rename_table = 'ALTER TABLE %s RENAME TO %s';
- public function __construct()
+ /**
+ * CREATE TABLE statement
+ *
+ * @var string
+ */
+ protected $_create_table = "%s %s (%s\n)";
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
+
+ /**
+ * CREATE TABLE keys flag
+ *
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
+ */
+ protected $_create_table_keys = FALSE;
+
+ /**
+ * DROP TABLE IF EXISTS statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * RENAME TABLE statement
+ *
+ * @var string
+ */
+ protected $_rename_table = 'ALTER TABLE %s RENAME TO %s;';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = TRUE;
+
+ /**
+ * NULL value representatin in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = '';
+
+ /**
+ * DEFAULT value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_default = ' DEFAULT ';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
{
- // Assign the main database object to $this->db
- $CI =& get_instance();
- $this->db =& $CI->db;
+ $this->db =& $db;
log_message('debug', 'Database Forge Class Initialized');
}
@@ -58,14 +164,14 @@ abstract class CI_DB_forge {
/**
* Create database
*
- * @param string the database name
+ * @param string $db_name
* @return bool
*/
public function create_database($db_name)
{
if ($this->_create_database === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat)))
{
@@ -85,7 +191,7 @@ abstract class CI_DB_forge {
/**
* Drop database
*
- * @param string the database name
+ * @param string $db_name
* @return bool
*/
public function drop_database($db_name)
@@ -97,7 +203,7 @@ abstract class CI_DB_forge {
}
elseif ($this->_drop_database === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name)))
{
@@ -121,25 +227,25 @@ abstract class CI_DB_forge {
/**
* Add Key
*
- * @param string key
- * @param string type
+ * @param string $key
+ * @param bool $primary
* @return object
*/
public function add_key($key = '', $primary = FALSE)
{
- if (is_array($key))
+ if (empty($key))
+ {
+ show_error('Key information is required for that operation.');
+ }
+
+ if ($primary === TRUE && is_array($key))
{
foreach ($key as $one)
{
$this->add_key($one, $primary);
}
- return;
- }
-
- if ($key === '')
- {
- show_error('Key information is required for that operation.');
+ return $this;
}
if ($primary === TRUE)
@@ -159,12 +265,12 @@ abstract class CI_DB_forge {
/**
* Add Field
*
- * @param string collation
+ * @param array $field
* @return object
*/
public function add_field($field = '')
{
- if ($field === '')
+ if (empty($field))
{
show_error('Field information is required.');
}
@@ -206,7 +312,8 @@ abstract class CI_DB_forge {
/**
* Create Table
*
- * @param string the table name
+ * @param string $table Table name
+ * @param bool $if_not_exists Whether to add IF NOT EXISTS condition
* @return bool
*/
public function create_table($table = '', $if_not_exists = FALSE)
@@ -215,51 +322,129 @@ abstract class CI_DB_forge {
{
show_error('A table name is required for that operation.');
}
+ else
+ {
+ $table = $this->db->dbprefix.$table;
+ }
if (count($this->fields) === 0)
{
show_error('Field information is required.');
}
- $sql = $this->_create_table($this->db->dbprefix.$table, $this->fields, $this->primary_keys, $this->keys, $if_not_exists);
- $this->_reset();
+ $sql = $this->_create_table($table, $if_not_exists);
if (is_bool($sql))
{
- return $sql;
+ $this->_reset();
+ if ($sql === FALSE)
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
}
- if (($result = $this->db->query($sql)) !== FALSE && ! empty($this->db->data_cache['table_names']))
+ if (($result = $this->db->query($sql)) !== FALSE)
{
- $this->db->data_cache['table_names'][] = $this->db->dbprefix.$table;
+ empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table;
+
+ // Most databases don't support creating indexes from within the CREATE TABLE statement
+ if ( ! empty($this->keys))
+ {
+ for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
+ {
+ $this->db->query($sqls[$i]);
+ }
+ }
}
+ $this->_reset();
return $result;
}
// --------------------------------------------------------------------
/**
+ * Create Table
+ *
+ * @param string $table Table name
+ * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition
+ * @return mixed
+ */
+ protected function _create_table($table, $if_not_exists)
+ {
+ if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
+ {
+ if ($this->db->table_exists($table))
+ {
+ return TRUE;
+ }
+ else
+ {
+ $if_not_exists = FALSE;
+ }
+ }
+
+ $sql = ($if_not_exists)
+ ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
+ : 'CREATE TABLE';
+
+ $columns = $this->_process_fields(TRUE);
+ for ($i = 0, $c = count($columns); $i < $c; $i++)
+ {
+ $columns[$i] = ($columns[$i]['_literal'] !== FALSE)
+ ? "\n\t".$columns[$i]['_literal']
+ : "\n\t".$this->_process_column($columns[$i]);
+ }
+
+ $columns = implode(',', $columns)
+ .$this->_process_primary_keys($table);
+
+ // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
+ if ($this->_create_table_keys === TRUE)
+ {
+ $columns .= $this->_process_indexes($table);
+ }
+
+ // _create_table will usually have the following format: "%s %s (%s\n)"
+ $sql = sprintf($this->_create_table.';',
+ $sql,
+ $this->db->escape_identifiers($table),
+ $columns
+ );
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Drop Table
*
- * @param string the table name
+ * @param string $table_name Table name
+ * @param bool $if_exists Whether to add an IF EXISTS condition
* @return bool
*/
- public function drop_table($table_name)
+ public function drop_table($table_name, $if_exists = FALSE)
{
if ($table_name === '')
{
return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
}
- elseif ($this->_drop_table === FALSE)
+
+ $query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists);
+ if ($query === FALSE)
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+ elseif ($query === TRUE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return TRUE;
}
- $result = $this->db->query(sprintf($this->_drop_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name)));
+ $query = $this->db->query($query);
// Update table list cache
- if ($result && ! empty($this->db->data_cache['table_names']))
+ if ($query && ! empty($this->db->data_cache['table_names']))
{
$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
if ($key !== FALSE)
@@ -268,7 +453,40 @@ abstract class CI_DB_forge {
}
}
- return $result;
+ return $query;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Drop Table
+ *
+ * Generates a platform-specific DROP TABLE string
+ *
+ * @param string $table Table name
+ * @param bool $if_exists Whether to add an IF EXISTS condition
+ * @return string
+ */
+ protected function _drop_table($table, $if_exists)
+ {
+ $sql = 'DROP TABLE';
+
+ if ($if_exists)
+ {
+ if ($this->_drop_table_if === FALSE)
+ {
+ if ( ! $this->db->table_exists($table))
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
+ }
+ }
+
+ return $sql.' '.$this->db->escape_identifiers($table);
}
// --------------------------------------------------------------------
@@ -276,8 +494,8 @@ abstract class CI_DB_forge {
/**
* Rename Table
*
- * @param string the old table name
- * @param string the new table name
+ * @param string $table_name Old table name
+ * @param string $new_table_name New table name
* @return bool
*/
public function rename_table($table_name, $new_table_name)
@@ -289,7 +507,7 @@ abstract class CI_DB_forge {
}
elseif ($this->_rename_table === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$result = $this->db->query(sprintf($this->_rename_table,
@@ -314,33 +532,46 @@ abstract class CI_DB_forge {
/**
* Column Add
*
- * @param string the table name
- * @param string the column name
- * @param string the column definition
+ * @todo Remove deprecated $_after option in 3.1+
+ * @param string $table Table name
+ * @param array $field Column definition
+ * @param string $_after Column for AFTER clause (deprecated)
* @return bool
*/
- public function add_column($table = '', $field = array(), $after_field = '')
+ public function add_column($table = '', $field = array(), $_after = NULL)
{
if ($table === '')
{
show_error('A table name is required for that operation.');
}
- // add field info into field array, but we can only do one at a time
- // so we cycle through
- foreach (array_keys($field) as $k)
+ // Work-around for literal column definitions
+ if ( ! is_array($field))
{
- $this->add_field(array($k => $field[$k]));
+ $field = array($field);
+ }
- if (count($this->fields) === 0)
+ foreach (array_keys($field) as $k)
+ {
+ // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
+ if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
{
- show_error('Field information is required.');
+ $field[$k]['after'] = $_after;
}
- $sql = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->fields, $after_field);
- $this->_reset();
+ $this->add_field(array($k => $field[$k]));
+ }
+
+ $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
+ $this->_reset();
+ if ($sqls === FALSE)
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
- if ($this->db->query($sql) === FALSE)
+ for ($i = 0, $c = count($sqls); $i < $c; $i++)
+ {
+ if ($this->db->query($sqls[$i]) === FALSE)
{
return FALSE;
}
@@ -354,8 +585,8 @@ abstract class CI_DB_forge {
/**
* Column Drop
*
- * @param string the table name
- * @param string the column name
+ * @param string $table Table name
+ * @param string $column_name Column name
* @return bool
*/
public function drop_column($table = '', $column_name = '')
@@ -370,7 +601,13 @@ abstract class CI_DB_forge {
show_error('A column name is required for that operation.');
}
- return $this->db->query($this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name));
+ $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
+ if ($sql === FALSE)
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+ return $this->db->query($sql);
}
// --------------------------------------------------------------------
@@ -378,9 +615,8 @@ abstract class CI_DB_forge {
/**
* Column Modify
*
- * @param string the table name
- * @param string the column name
- * @param string the column definition
+ * @param string $table Table name
+ * @param string $field Column definition
* @return bool
*/
public function modify_column($table = '', $field = array())
@@ -390,32 +626,374 @@ abstract class CI_DB_forge {
show_error('A table name is required for that operation.');
}
- // add field info into field array, but we can only do one at a time
- // so we cycle through
+ // Work-around for literal column definitions
+ if ( ! is_array($field))
+ {
+ $field = array($field);
+ }
+
foreach (array_keys($field) as $k)
{
- // If no name provided, use the current name
- if ( ! isset($field[$k]['name']))
+ $this->add_field(array($k => $field[$k]));
+ }
+
+ if (count($this->fields) === 0)
+ {
+ show_error('Field information is required.');
+ }
+
+ $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
+ $this->_reset();
+ if ($sqls === FALSE)
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+ for ($i = 0, $c = count($sqls); $i < $c; $i++)
+ {
+ if ($this->db->query($sqls[$i]) === FALSE)
{
- $field[$k]['name'] = $k;
+ return FALSE;
}
+ }
- $this->add_field(array($k => $field[$k]));
- if (count($this->fields) === 0)
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
+
+ // DROP has everything it needs now.
+ if ($alter_type === 'DROP')
+ {
+ return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
+ }
+
+ $sqls = array();
+ for ($i = 0, $c = count($field), $sql .= $alter_type.' COLUMN '; $i < $c; $i++)
+ {
+ $sqls[] = $sql
+ .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process fields
+ *
+ * @param bool $create_table
+ * @return array
+ */
+ protected function _process_fields($create_table = FALSE)
+ {
+ $fields = array();
+
+ foreach ($this->fields as $key => $attributes)
+ {
+ if (is_int($key) && ! is_array($attributes))
{
- show_error('Field information is required.');
+ $fields[] = array('_literal' => $attributes);
+ continue;
}
- $sql = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->fields);
- $this->_reset();
+ $attributes = array_change_key_case($attributes, CASE_UPPER);
- if ($this->db->query($sql) === FALSE)
+ if ($create_table === TRUE && empty($attributes['TYPE']))
{
- return FALSE;
+ continue;
+ }
+
+ if (isset($attributes['TYPE']))
+ {
+ $this->_attr_type($attributes);
+ $this->_attr_unsigned($attributes, $field);
}
+
+ $field = array(
+ 'name' => $key,
+ 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
+ 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
+ 'length' => '',
+ 'unsigned' => '',
+ 'null' => '',
+ 'unique' => '',
+ 'default' => '',
+ 'auto_increment' => '',
+ '_literal' => FALSE
+ );
+
+ $this->_attr_default($attributes, $field);
+
+ if (isset($attributes['NULL']))
+ {
+ if ($attributes['NULL'] === TRUE)
+ {
+ $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
+ }
+ elseif ($create_table === TRUE)
+ {
+ $field['null'] = ' NOT NULL';
+ }
+ }
+
+ $this->_attr_auto_increment($attributes, $field);
+ $this->_attr_unique($attributes, $field);
+
+ if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'ENUM':
+ case 'SET':
+ $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
+ default:
+ $field['length'] = is_array($attributes['CONSTRAINT'])
+ ? "('".implode("','", $attributes['CONSTRAINT'])."')"
+ : '('.$attributes['CONSTRAINT'].')';
+ break;
+ }
+ }
+
+ $fields[] = $field;
}
- return TRUE;
+ return $fields;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['default']
+ .$field['null']
+ .$field['auto_increment']
+ .$field['unique'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ // Usually overriden by drivers
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute UNSIGNED
+ *
+ * Depending on the _unsigned property value:
+ *
+ * - TRUE will always set $field['unsigned'] to 'UNSIGNED'
+ * - FALSE will always set $field['unsigned'] to ''
+ * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
+ * if $attributes['TYPE'] is found in the array
+ * - array(TYPE => UTYPE) will change $field['type'],
+ * from TYPE to UTYPE in case of a match
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_unsigned(&$attributes, &$field)
+ {
+ if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
+ {
+ return;
+ }
+
+ // Reset the attribute in order to avoid issues if we do type conversion
+ $attributes['UNSIGNED'] = FALSE;
+
+ if (is_array($this->_unsigned))
+ {
+ foreach (array_keys($this->_unsigned) as $key)
+ {
+ if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
+ {
+ $field['unsigned'] = ' UNSIGNED';
+ return;
+ }
+ elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
+ {
+ $field['type'] = $key;
+ return;
+ }
+ }
+
+ return;
+ }
+
+ $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute DEFAULT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_default(&$attributes, &$field)
+ {
+ if ($this->_default === FALSE)
+ {
+ return;
+ }
+
+ if (array_key_exists('DEFAULT', $attributes))
+ {
+ if ($attributes['DEFAULT'] === NULL)
+ {
+ $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
+
+ // Override the NULL attribute if that's our default
+ $attributes['NULL'] = NULL;
+ $field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
+ }
+ else
+ {
+ $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute UNIQUE
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_unique(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+ {
+ $field['unique'] = ' UNIQUE';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' AUTO_INCREMENT';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process primary keys
+ *
+ * @param string $table Table name
+ * @return string
+ */
+ protected function _process_primary_keys($table)
+ {
+ $sql = '';
+
+ for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
+ {
+ if ( ! isset($this->fields[$this->primary_keys[$i]]))
+ {
+ unset($this->primary_keys[$i]);
+ }
+ }
+
+ if (count($this->primary_keys) > 0)
+ {
+ $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
+ .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process indexes
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _process_indexes($table)
+ {
+ $table = $this->db->escape_identifiers($table);
+ $sqls = array();
+
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
+ {
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ON '.$this->db->escape_identifiers($table)
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
+ }
+
+ return $sqls;
}
// --------------------------------------------------------------------
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 479b7f24a..b0e86ed2c 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Query Builder Class
@@ -39,44 +40,213 @@
abstract class CI_DB_query_builder extends CI_DB_driver {
+ /**
+ * Return DELETE SQL flag
+ *
+ * @var bool
+ */
protected $return_delete_sql = FALSE;
+
+ /**
+ * Reset DELETE data flag
+ *
+ * @var bool
+ */
protected $reset_delete_data = FALSE;
+ /**
+ * QB SELECT data
+ *
+ * @var array
+ */
protected $qb_select = array();
+
+ /**
+ * QB DISTINCT flag
+ *
+ * @var bool
+ */
protected $qb_distinct = FALSE;
+
+ /**
+ * QB FROM data
+ *
+ * @var array
+ */
protected $qb_from = array();
+
+ /**
+ * QB JOIN data
+ *
+ * @var array
+ */
protected $qb_join = array();
+
+ /**
+ * QB WHERE data
+ *
+ * @var array
+ */
protected $qb_where = array();
- protected $qb_like = array();
+
+ /**
+ * QB GROUP BY data
+ *
+ * @var array
+ */
protected $qb_groupby = array();
+
+ /**
+ * QB HAVING data
+ *
+ * @var array
+ */
protected $qb_having = array();
+
+ /**
+ * QB keys
+ *
+ * @var array
+ */
protected $qb_keys = array();
+
+ /**
+ * QB LIMIT data
+ *
+ * @var int
+ */
protected $qb_limit = FALSE;
+
+ /**
+ * QB OFFSET data
+ *
+ * @var int
+ */
protected $qb_offset = FALSE;
+
+ /**
+ * QB ORDER BY data
+ *
+ * @var array
+ */
protected $qb_orderby = array();
+
+ /**
+ * QB data sets
+ *
+ * @var array
+ */
protected $qb_set = array();
- protected $qb_wherein = array();
+
+ /**
+ * QB aliased tables list
+ *
+ * @var array
+ */
protected $qb_aliased_tables = array();
- protected $qb_store_array = array();
+
+ /**
+ * QB WHERE group started flag
+ *
+ * @var bool
+ */
protected $qb_where_group_started = FALSE;
+
+ /**
+ * QB WHERE group count
+ *
+ * @var int
+ */
protected $qb_where_group_count = 0;
// Query Builder Caching variables
+
+ /**
+ * QB Caching flag
+ *
+ * @var bool
+ */
protected $qb_caching = FALSE;
+
+ /**
+ * QB Cache exists list
+ *
+ * @var array
+ */
protected $qb_cache_exists = array();
+
+ /**
+ * QB Cache SELECT data
+ *
+ * @var array
+ */
protected $qb_cache_select = array();
+
+ /**
+ * QB Cache FROM data
+ *
+ * @var array
+ */
protected $qb_cache_from = array();
+
+ /**
+ * QB Cache JOIN data
+ *
+ * @var array
+ */
protected $qb_cache_join = array();
+
+ /**
+ * QB Cache WHERE data
+ *
+ * @var array
+ */
protected $qb_cache_where = array();
- protected $qb_cache_like = array();
+
+ /**
+ * QB Cache GROUP BY data
+ *
+ * @var array
+ */
protected $qb_cache_groupby = array();
+
+ /**
+ * QB Cache HAVING data
+ *
+ * @var array
+ */
protected $qb_cache_having = array();
+
+ /**
+ * QB Cache ORDER BY data
+ *
+ * @var array
+ */
protected $qb_cache_orderby = array();
+
+ /**
+ * QB Cache data sets
+ *
+ * @var array
+ */
protected $qb_cache_set = array();
+ /**
+ * QB No Escape data
+ *
+ * @var array
+ */
protected $qb_no_escape = array();
+
+ /**
+ * QB Cache No Escape data
+ *
+ * @var array
+ */
protected $qb_cache_no_escape = array();
+ // --------------------------------------------------------------------
+
/**
* Select
*
@@ -184,15 +354,16 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Processing Function for the four functions above:
+ * SELECT [MAX|MIN|AVG|SUM]()
*
- * select_max()
- * select_min()
- * select_avg()
- * select_sum()
+ * @used-by select_max()
+ * @used-by select_min()
+ * @used-by select_avg()
+ * @used-by select_sum()
*
- * @param string the field
- * @param string an alias
+ * @param string $select Field name
+ * @param string $alias
+ * @param string $type
* @return object
*/
protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
@@ -233,7 +404,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Determines the alias name based on the table
*
- * @param string
+ * @param string $item
* @return string
*/
protected function _create_alias_from_table($item)
@@ -254,7 +425,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Sets a flag which tells the query string compiler to add DISTINCT
*
- * @param bool
+ * @param bool $val
* @return object
*/
public function distinct($val = TRUE)
@@ -270,7 +441,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Generates the FROM portion of the query
*
- * @param mixed can be a string or array
+ * @param mixed $from can be a string or array
* @return object
*/
public function from($from)
@@ -317,7 +488,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Join
+ * JOIN
*
* Generates the JOIN portion of the query
*
@@ -405,10 +576,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE
*
- * Generates the WHERE portion of the query. Separates
- * multiple calls with AND
+ * Generates the WHERE portion of the query.
+ * Separates multiple calls with 'AND'.
*
* @param mixed
* @param mixed
@@ -417,16 +588,16 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*/
public function where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
/**
- * OR Where
+ * OR WHERE
*
- * Generates the WHERE portion of the query. Separates
- * multiple calls with OR
+ * Generates the WHERE portion of the query.
+ * Separates multiple calls with 'OR'.
*
* @param mixed
* @param mixed
@@ -435,24 +606,30 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*/
public function or_where($key, $value = NULL, $escape = NULL)
{
- return $this->_where($key, $value, 'OR ', $escape);
+ return $this->_wh('qb_where', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
- * Where
+ * WHERE, HAVING
*
- * Called by where() or or_where()
+ * @used-by where()
+ * @used-by or_where()
+ * @used-by having()
+ * @used-by or_having()
*
- * @param mixed
- * @param mixed
- * @param string
- * @param mixed
+ * @param string $qb_key 'qb_where' or 'qb_having'
+ * @param mixed $key
+ * @param mixed $value
+ * @param string $type
+ * @param bool $escape
* @return object
*/
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+ protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL)
{
+ $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where';
+
if ( ! is_array($key))
{
$key = array($key => $value);
@@ -463,23 +640,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
foreach ($key as $k => $v)
{
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0)
? $this->_group_get_type('')
: $this->_group_get_type($type);
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
- if (is_null($v) && ! $this->_has_operator($k))
- {
- // value appears not to have been set, assign the test to IS NULL
- $k .= ' IS NULL';
- }
-
if ( ! is_null($v))
{
if ($escape === TRUE)
@@ -492,12 +656,17 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$k .= ' = ';
}
}
+ elseif ( ! $this->_has_operator($k))
+ {
+ // value appears not to have been set, assign the test to IS NULL
+ $k .= ' IS NULL';
+ }
- $this->qb_where[] = $prefix.$k.$v;
+ $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
+ $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape);
+ $this->qb_cache_exists[] = substr($qb_key, 3);
}
}
@@ -508,13 +677,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_in
+ * WHERE IN
*
- * Generates a WHERE field IN ('item', 'item') SQL query joined with
- * AND if appropriate
+ * Generates a WHERE field IN('item', 'item') SQL query,
+ * joined with 'AND' if appropriate.
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key The field to search
+ * @param array $values The values searched on
+ * @param bool $escape
* @return object
*/
public function where_in($key = NULL, $values = NULL, $escape = NULL)
@@ -525,13 +695,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_in_or
+ * OR WHERE IN
*
- * Generates a WHERE field IN ('item', 'item') SQL query joined with
- * OR if appropriate
+ * Generates a WHERE field IN('item', 'item') SQL query,
+ * joined with 'OR' if appropriate.
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key The field to search
+ * @param array $values The values searched on
+ * @param bool $escape
* @return object
*/
public function or_where_in($key = NULL, $values = NULL, $escape = NULL)
@@ -542,13 +713,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_not_in
+ * WHERE NOT IN
*
- * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
- * with AND if appropriate
+ * Generates a WHERE field NOT IN('item', 'item') SQL query,
+ * joined with 'AND' if appropriate.
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key The field to search
+ * @param array $values The values searched on
+ * @param bool $escape
* @return object
*/
public function where_not_in($key = NULL, $values = NULL, $escape = NULL)
@@ -559,13 +731,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_not_in_or
+ * OR WHERE NOT IN
*
- * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
- * with OR if appropriate
+ * Generates a WHERE field NOT IN('item', 'item') SQL query,
+ * joined with 'OR' if appropriate.
*
- * @param string The field to search
- * @param array The values searched on
+ * @param string $key The field to search
+ * @param array $values The values searched on
+ * @param bool $escape
* @return object
*/
public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL)
@@ -576,14 +749,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Where_in
+ * Internal WHERE IN
*
- * Called by where_in, where_in_or, where_not_in, where_not_in_or
+ * @used-by where_in()
+ * @used-by or_where_in()
+ * @used-by where_not_in()
+ * @used-by or_where_not_in()
*
- * @param string The field to search
- * @param array The values searched on
- * @param bool If the statement would be IN or NOT IN
- * @param string
+ * @param string $key The field to search
+ * @param array $values The values searched on
+ * @param bool $not If the statement would be IN or NOT IN
+ * @param string $type
+ * @param bool $escape
* @return object
*/
protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL)
@@ -602,153 +779,167 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$not = ($not) ? ' NOT' : '';
+ $where_in = array();
foreach ($values as $value)
{
- $this->qb_wherein[] = $this->escape($value);
- }
-
- if ($escape === TRUE)
- {
- $key = $this->escape_identifiers(trim($key));
+ $where_in[] = $this->escape($value);
}
$prefix = (count($this->qb_where) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
- $this->qb_where[] = $where_in = $prefix.$key.$not.' IN ('.implode(', ', $this->qb_wherein).') ';
+ $where_in = array(
+ 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')',
+ 'escape' => $escape
+ );
+ $this->qb_where[] = $where_in;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_where[] = $where_in;
$this->qb_cache_exists[] = 'where';
}
- // reset the array for multiple calls
- $this->qb_wherein = array();
return $this;
}
// --------------------------------------------------------------------
/**
- * Like
+ * LIKE
*
- * Generates a %LIKE% portion of the query. Separates
- * multiple calls with AND
+ * Generates a %LIKE% portion of the query.
+ * Separates multiple calls with 'AND'.
*
- * @param mixed
- * @param mixed
+ * @param mixed $field
+ * @param string $match
+ * @param string $side
+ * @param bool $escape
* @return object
*/
- public function like($field, $match = '', $side = 'both')
+ public function like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side);
+ return $this->_like($field, $match, 'AND ', $side, '', $escape);
}
// --------------------------------------------------------------------
/**
- * Not Like
+ * NOT LIKE
*
- * Generates a NOT LIKE portion of the query. Separates
- * multiple calls with AND
+ * Generates a NOT LIKE portion of the query.
+ * Separates multiple calls with 'AND'.
*
- * @param mixed
- * @param mixed
+ * @param mixed $field
+ * @param string $match
+ * @param string $side
+ * @param bool $escape
* @return object
*/
- public function not_like($field, $match = '', $side = 'both')
+ public function not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'AND ', $side, 'NOT');
+ return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
/**
- * OR Like
+ * OR LIKE
*
- * Generates a %LIKE% portion of the query. Separates
- * multiple calls with OR
+ * Generates a %LIKE% portion of the query.
+ * Separates multiple calls with 'OR'.
*
- * @param mixed
- * @param mixed
+ * @param mixed $field
+ * @param string $match
+ * @param string $side
+ * @param bool $escape
* @return object
*/
- public function or_like($field, $match = '', $side = 'both')
+ public function or_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side);
+ return $this->_like($field, $match, 'OR ', $side, '', $escape);
}
// --------------------------------------------------------------------
/**
- * OR Not Like
+ * OR NOT LIKE
*
- * Generates a NOT LIKE portion of the query. Separates
- * multiple calls with OR
+ * Generates a NOT LIKE portion of the query.
+ * Separates multiple calls with 'OR'.
*
- * @param mixed
- * @param mixed
+ * @param mixed $field
+ * @param string $match
+ * @param string $side
+ * @param bool $escape
* @return object
*/
- public function or_not_like($field, $match = '', $side = 'both')
+ public function or_not_like($field, $match = '', $side = 'both', $escape = NULL)
{
- return $this->_like($field, $match, 'OR ', $side, 'NOT');
+ return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape);
}
// --------------------------------------------------------------------
/**
- * Like
+ * Internal LIKE
*
- * Called by like() or orlike()
+ * @used-by like()
+ * @used-by or_like()
+ * @used-by not_like()
+ * @used-by or_not_like()
*
- * @param mixed
- * @param mixed
- * @param string
+ * @param mixed $field
+ * @param string $match
+ * @param string $type
+ * @param string $side
+ * @param string $not
+ * @param bool $escape
* @return object
*/
- protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
+ protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL)
{
if ( ! is_array($field))
{
$field = array($field => $match);
}
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+
foreach ($field as $k => $v)
{
- $k = $this->protect_identifiers($k);
- $prefix = (count($this->qb_like) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type);
+ $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
+ ? $this->_group_get_type('') : $this->_group_get_type($type);
+
$v = $this->escape_like_str($v);
if ($side === 'none')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}'";
}
elseif ($side === 'before')
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}'";
}
elseif ($side === 'after')
{
- $like_statement = "{$prefix} $k $not LIKE '{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}%'";
}
else
{
- $like_statement = "{$prefix} $k $not LIKE '%{$v}%'";
+ $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}%'";
}
// some platforms require an escape sequence definition for LIKE wildcards
if ($this->_like_escape_str !== '')
{
- $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ $like_statement .= sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
- $this->qb_like[] = $like_statement;
+ $this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_like[] = $like_statement;
- $this->qb_cache_exists[] = 'like';
+ $this->qb_cache_where[] = $like_statement;
+ $this->qb_cache_exists[] = 'where';
}
-
}
return $this;
@@ -759,8 +950,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Starts a query group.
*
- * @param string (Internal use only)
- * @param string (Internal use only)
+ * @param string $not (Internal use only)
+ * @param string $type (Internal use only)
* @return object
*/
public function group_start($not = '', $type = 'AND ')
@@ -769,11 +960,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->qb_where_group_started = TRUE;
$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
- $this->qb_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (';
+ $where = array(
+ 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -825,11 +1020,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
public function group_end()
{
$this->qb_where_group_started = FALSE;
- $this->qb_where[] = $value = str_repeat(' ', $this->qb_where_group_count--) . ')';
+ $where = array(
+ 'condition' => str_repeat(' ', $this->qb_where_group_count--).')',
+ 'escape' => FALSE
+ );
+ $this->qb_where[] = $where;
if ($this->qb_caching)
{
- $this->qb_cache_where[] = $value;
+ $this->qb_cache_where[] = $where;
}
return $this;
@@ -840,9 +1039,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Group_get_type
*
- * Called by group_start(), _like(), _where() and _where_in()
+ * @used-by group_start()
+ * @used-by _like()
+ * @used-by _wh()
+ * @used-by _where_in()
*
- * @param string
+ * @param string $type
* @return string
*/
protected function _group_get_type($type)
@@ -861,14 +1063,19 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* GROUP BY
*
- * @param string
+ * @param string $by
+ * @param bool $escape
* @return object
*/
- public function group_by($by)
+ public function group_by($by, $escape = NULL)
{
+ is_bool($escape) OR $escape = $this->_protect_identifiers;
+
if (is_string($by))
{
- $by = explode(',', $by);
+ $by = ($escape === TRUE)
+ ? explode(',', $by)
+ : array($by);
}
foreach ($by as $val)
@@ -877,8 +1084,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
if ($val !== '')
{
- $this->qb_groupby[] = $val = $this->protect_identifiers($val);
+ $val = array('field' => $val, 'escape' => $escape);
+ $this->qb_groupby[] = $val;
if ($this->qb_caching === TRUE)
{
$this->qb_cache_groupby[] = $val;
@@ -893,142 +1101,90 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Sets the HAVING value
+ * HAVING
*
- * Separates multiple calls with AND
+ * Separates multiple calls with 'AND'.
*
- * @param string
- * @param string
- * @param bool
+ * @param string $key
+ * @param string $value
+ * @param bool $escape
* @return object
*/
- public function having($key, $value = '', $escape = NULL)
+ public function having($key, $value = NULL, $escape = NULL)
{
- return $this->_having($key, $value, 'AND ', $escape);
+ return $this->_wh('qb_having', $key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
/**
- * Sets the OR HAVING value
+ * OR HAVING
*
- * Separates multiple calls with OR
+ * Separates multiple calls with 'OR'.
*
- * @param string
- * @param string
- * @param bool
+ * @param string $key
+ * @param string $value
+ * @param bool $escape
* @return object
*/
- public function or_having($key, $value = '', $escape = NULL)
+ public function or_having($key, $value = NULL, $escape = NULL)
{
- return $this->_having($key, $value, 'OR ', $escape);
+ return $this->_wh('qb_having', $key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
- * Sets the HAVING values
- *
- * Called by having() or or_having()
+ * ORDER BY
*
- * @param string
- * @param string
- * @param string
- * @param bool
+ * @param string $orderby
+ * @param string $direction ASC or DESC
+ * @param bool $escape
* @return object
*/
- protected function _having($key, $value = '', $type = 'AND ', $escape = NULL)
+ public function order_by($orderby, $direction = '', $escape = NULL)
{
- if ( ! is_array($key))
- {
- $key = array($key => $value);
- }
-
- is_bool($escape) OR $escape = $this->_protect_identifiers;
+ $direction = strtoupper(trim($direction));
- foreach ($key as $k => $v)
+ if ($direction === 'RANDOM')
{
- $prefix = (count($this->qb_having) === 0) ? '' : $type;
-
- $k = $this->_has_operator($k)
- ? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
- : $this->protect_identifiers($k, FALSE, $escape);
+ $direction = '';
- if ( ! $this->_has_operator($k))
- {
- $k .= ' = ';
- }
-
- if ($v !== '')
- {
- $v = ' '.$this->escape($v);
- }
-
- $this->qb_having[] = $prefix.$k.$v;
- if ($this->qb_caching === TRUE)
- {
- $this->qb_cache_having[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'having';
- }
+ // Do we have a seed value?
+ $orderby = ctype_digit((string) $orderby)
+ ? $orderby = sprintf($this->_random_keyword[1], $orderby)
+ : $this->_random_keyword[0];
}
-
- return $this;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Sets the ORDER BY value
- *
- * @param string
- * @param string direction: asc or desc
- * @param bool enable field name escaping
- * @return object
- */
- public function order_by($orderby, $direction = '', $escape = NULL)
- {
- if (strtolower($direction) === 'random')
+ elseif (empty($orderby))
{
- $orderby = ''; // Random results want or don't need a field name
- $direction = $this->_random_keyword;
+ return $this;
}
- elseif (trim($direction) !== '')
+ elseif ($direction !== '')
{
- $direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
+ $direction = in_array($direction, array('ASC', 'DESC'), TRUE) ? ' '.$direction : '';
}
is_bool($escape) OR $escape = $this->_protect_identifiers;
- if ($escape === TRUE && strpos($orderby, ',') !== FALSE)
+ if ($escape === FALSE)
{
- $temp = array();
- foreach (explode(',', $orderby) as $part)
- {
- $part = trim($part);
- if ( ! in_array($part, $this->qb_aliased_tables))
- {
- $part = preg_match('/^(.+)\s+(ASC|DESC)$/i', $part, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($part);
- }
-
- $temp[] = $part;
- }
-
- $orderby = implode(', ', $temp);
+ $qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE);
}
- elseif ($direction !== $this->_random_keyword && $escape === TRUE)
+ else
{
- $orderby = preg_match('/^(.+)\s+(ASC|DESC)$/i', $orderby, $matches)
- ? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
- : $this->protect_identifiers($orderby);
+ $qb_orderby = array();
+ foreach (explode(',', $orderby) as $field)
+ {
+ $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE))
+ ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE)
+ : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE);
+ }
}
- $this->qb_orderby[] = $orderby_statement = $orderby.$direction;
-
+ $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby);
if ($this->qb_caching === TRUE)
{
- $this->qb_cache_orderby[] = $orderby_statement;
+ $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby);
$this->qb_cache_exists[] = 'orderby';
}
@@ -1038,13 +1194,13 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Sets the LIMIT value
+ * LIMIT
*
- * @param int the limit value
- * @param int the offset value
+ * @param int $value LIMIT value
+ * @param int $offset OFFSET value
* @return object
*/
- public function limit($value, $offset = NULL)
+ public function limit($value, $offset = FALSE)
{
is_null($value) OR $this->qb_limit = (int) $value;
empty($offset) OR $this->qb_offset = (int) $offset;
@@ -1057,7 +1213,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
/**
* Sets the OFFSET value
*
- * @param int the offset value
+ * @param int $offset OFFSET value
* @return object
*/
public function offset($offset)
@@ -1069,18 +1225,16 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT string
*
- * Generates a platform-specific LIMIT clause
+ * Generates a platform-specific LIMIT clause.
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.($offset ? $offset.', ' : '').$limit;
+ return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').$this->qb_limit;
}
// --------------------------------------------------------------------
@@ -1194,7 +1348,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->from($table);
}
- $result = $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
+ $result = ($this->qb_distinct === TRUE)
+ ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results")
+ : $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
$this->_reset_select();
if ($result->num_rows() === 0)
@@ -1213,9 +1369,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Allows the where clause, limit and offset to be added directly
*
- * @param string the where clause
- * @param string the limit clause
- * @param string the offset clause
+ * @param string $table
+ * @param string $where
+ * @param int $limit
+ * @param int $offset
* @return object
*/
public function get_where($table = '', $where = NULL, $limit = NULL, $offset = NULL)
@@ -1247,25 +1404,22 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* Compiles batch insert strings and runs the queries
*
- * @param string the table to retrieve the results from
- * @param array an associative array of insert values
- * @return object
+ * @param string $table Table to insert into
+ * @param array $set An associative array of insert values
+ * @param bool $escape Whether to escape values and identifiers
+ * @return int Number of rows inserted or FALSE on failure
*/
- public function insert_batch($table = '', $set = NULL)
+ public function insert_batch($table = '', $set = NULL, $escape = NULL)
{
if ( ! is_null($set))
{
- $this->set_insert_batch($set);
+ $this->set_insert_batch($set, '', $escape);
}
if (count($this->qb_set) === 0)
{
- if ($this->db_debug)
- {
- // No valid data array. Folds in cases where keys and values did not match up
- return $this->display_error('db_must_use_set');
- }
- return FALSE;
+ // No valid data array. Folds in cases where keys and values did not match up
+ return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
}
if ($table === '')
@@ -1279,25 +1433,27 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
// Batch this baby
+ $affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
- $this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
+ $this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
+ $affected_rows += $this->affected_rows();
}
$this->_reset_write();
- return TRUE;
+ return $affected_rows;
}
// --------------------------------------------------------------------
/**
- * Insert_batch statement
+ * Insert batch statement
*
* Generates a platform-specific insert string from the supplied data.
*
- * @param string the table name
- * @param array the insert keys
- * @param array the insert values
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
* @return string
*/
protected function _insert_batch($table, $keys, $values)
@@ -1352,7 +1508,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$row = $clean;
}
- $this->qb_set[] = '('.implode(',', $row).')';
+ $this->qb_set[] = '('.implode(',', $row).')';
}
foreach ($keys as $k)
@@ -1406,13 +1562,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*
* @param string the table to insert data into
* @param array an associative array of insert values
+ * @param bool $escape Whether to escape values and identifiers
* @return object
*/
- public function insert($table = '', $set = NULL)
+ public function insert($table = '', $set = NULL, $escape = NULL)
{
if ( ! is_null($set))
{
- $this->set($set);
+ $this->set($set, '', $escape);
}
if ($this->_validate_insert($table) === FALSE)
@@ -1422,7 +1579,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$sql = $this->_insert(
$this->protect_identifiers(
- $this->qb_from[0], TRUE, NULL, FALSE
+ $this->qb_from[0], TRUE, $escape, FALSE
),
array_keys($this->qb_set),
array_values($this->qb_set)
@@ -1522,19 +1679,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * From Tables
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
*
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * Note: This is only used (and overriden) by MySQL and CUBRID.
*
- * @param array
- * @return string
+ * @return string
*/
- protected function _from_tables($tables)
+ protected function _from_tables()
{
- is_array($tables) OR $tables = array($tables);
-
- return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
@@ -1558,7 +1714,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
return FALSE;
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit);
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
if ($reset === TRUE)
{
@@ -1571,13 +1727,14 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * Update
+ * UPDATE
*
- * Compiles an update string and runs the query
+ * Compiles an update string and runs the query.
*
- * @param string the table to retrieve the results from
- * @param array an associative array of update values
- * @param mixed the where clause
+ * @param string $table
+ * @param array $set An associative array of update values
+ * @param mixed $where
+ * @param int $limit
* @return object
*/
public function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
@@ -1605,8 +1762,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->limit($limit);
}
- $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit, $this->qb_like);
-
+ $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set);
$this->_reset_write();
return $this->query($sql);
}
@@ -1652,7 +1808,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param string the table to retrieve the results from
* @param array an associative array of update values
* @param string the where key
- * @return bool
+ * @return int number of rows affected or FALSE on failure
*/
public function update_batch($table = '', $set = NULL, $index = NULL)
{
@@ -1685,13 +1841,15 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
}
// Batch this baby
+ $affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
- $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index), $this->qb_where));
+ $this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index)));
+ $affected_rows += $this->affected_rows();
}
$this->_reset_write();
- return TRUE;
+ return $affected_rows;
}
// --------------------------------------------------------------------
@@ -1852,7 +2010,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* @param mixed the where clause
* @param mixed the limit clause
* @param bool
- * @return object
+ * @return mixed
*/
public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
{
@@ -1872,10 +2030,8 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
{
foreach ($table as $single_table)
{
- $this->delete($single_table, $where, $limit, FALSE);
+ $this->delete($single_table, $where, $limit, $reset_data);
}
-
- $this->_reset_write();
return;
}
else
@@ -1893,12 +2049,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->limit($limit);
}
- if (count($this->qb_where) === 0 && count($this->qb_wherein) === 0 && count($this->qb_like) === 0)
+ if (count($this->qb_where) === 0)
{
return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE;
}
- $sql = $this->_delete($table, $this->qb_where, $this->qb_like, $this->qb_limit);
+ $sql = $this->_delete($table);
if ($reset_data)
{
$this->_reset_write();
@@ -1915,21 +2071,12 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Generates a platform-specific delete string from the supplied data
*
* @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table
- .(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '')
- .($limit ? ' LIMIT '.(int) $limit : '');
+ return 'DELETE FROM '.$table.$this->_compile_wh('qb_where')
+ .($this->qb_limit ? ' LIMIT '.$this->qb_limit : '');
}
// --------------------------------------------------------------------
@@ -2018,8 +2165,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
* Compile the SELECT statement
*
* Generates a query string based on which functions were used.
- * Should not be called directly. The get() function calls it.
+ * Should not be called directly.
*
+ * @param bool $select_override
* @return string
*/
protected function _compile_select($select_override = FALSE)
@@ -2058,7 +2206,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// Write the "FROM" portion of the query
if (count($this->qb_from) > 0)
{
- $sql .= "\nFROM ".$this->_from_tables($this->qb_from);
+ $sql .= "\nFROM ".$this->_from_tables();
}
// Write the "JOIN" portion of the query
@@ -2067,50 +2215,156 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$sql .= "\n".implode("\n", $this->qb_join);
}
- // Write the "WHERE" portion of the query
- if (count($this->qb_where) > 0 OR count($this->qb_like) > 0)
+ $sql .= $this->_compile_wh('qb_where')
+ .$this->_compile_group_by()
+ .$this->_compile_wh('qb_having')
+ .$this->_compile_order_by(); // ORDER BY
+
+ // LIMIT
+ if ($this->qb_limit)
{
- $sql .= "\nWHERE ";
+ return $this->_limit($sql."\n");
}
- $sql .= implode("\n", $this->qb_where);
+ return $sql;
+ }
- // Write the "LIKE" portion of the query
- if (count($this->qb_like) > 0)
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile WHERE, HAVING statements
+ *
+ * Escapes identifiers in WHERE and HAVING statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * where(), or_where(), having(), or_having are called prior to from(),
+ * join() and dbprefix is added only if needed.
+ *
+ * @param string $qb_key 'qb_where' or 'qb_having'
+ * @return string SQL statement
+ */
+ protected function _compile_wh($qb_key)
+ {
+ if (count($this->$qb_key) > 0)
{
- if (count($this->qb_where) > 0)
+ for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
{
- $sql .= "\nAND ";
+ if ($this->{$qb_key}[$i]['escape'] === FALSE)
+ {
+ $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
+ continue;
+ }
+
+ // Split multiple conditions
+ $conditions = preg_split(
+ '/(\s*AND\s+|\s*OR\s+)/i',
+ $this->{$qb_key}[$i]['condition'],
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
+ );
+
+ for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++)
+ {
+ if (($op = $this->_get_operator($conditions[$ci])) === FALSE
+ OR ! preg_match('/^(\(?)(.*)('.preg_quote($op, '/').')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches))
+ {
+ continue;
+ }
+
+ // $matches = array(
+ // 0 => '(test <= foo)', /* the whole thing */
+ // 1 => '(', /* optional */
+ // 2 => 'test', /* the field name */
+ // 3 => ' <= ', /* $op */
+ // 4 => 'foo', /* optional, if $op is e.g. 'IS NULL' */
+ // 5 => ')' /* optional */
+ // );
+
+ if ( ! empty($matches[4]))
+ {
+ $this->_is_literal($matches[4]) OR $matches[4] = $this->protect_identifiers(trim($matches[4]));
+ $matches[4] = ' '.$matches[4];
+ }
+
+ $conditions[$ci] = $matches[1].$this->protect_identifiers(trim($matches[2]))
+ .' '.trim($matches[3]).$matches[4].$matches[5];
+ }
+
+ $this->{$qb_key}[$i] = implode('', $conditions);
}
- $sql .= implode("\n", $this->qb_like);
+ return ($qb_key === 'qb_having' ? "\nHAVING " : "\nWHERE ")
+ .implode("\n", $this->$qb_key);
}
- // Write the "GROUP BY" portion of the query
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile GROUP BY
+ *
+ * Escapes identifiers in GROUP BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * group_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_group_by()
+ {
if (count($this->qb_groupby) > 0)
{
- $sql .= "\nGROUP BY ".implode(', ', $this->qb_groupby);
- }
+ for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
+ {
+ $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field']))
+ ? $this->qb_groupby[$i]['field']
+ : $this->protect_identifiers($this->qb_groupby[$i]['field']);
+ }
- // Write the "HAVING" portion of the query
- if (count($this->qb_having) > 0)
- {
- $sql .= "\nHAVING ".implode("\n", $this->qb_having);
+ return "\nGROUP BY ".implode(', ', $this->qb_groupby);
}
- // Write the "ORDER BY" portion of the query
- if (count($this->qb_orderby) > 0)
+ return '';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile ORDER BY
+ *
+ * Escapes identifiers in ORDER BY statements at execution time.
+ *
+ * Required so that aliases are tracked properly, regardless of wether
+ * order_by() is called prior to from(), join() and dbprefix is added
+ * only if needed.
+ *
+ * @return string SQL statement
+ */
+ protected function _compile_order_by()
+ {
+ if (is_array($this->qb_orderby) && count($this->qb_orderby) > 0)
{
- $sql .= "\nORDER BY ".implode(', ', $this->qb_orderby);
- }
+ for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
+ {
+ if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field']))
+ {
+ $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']);
+ }
- // Write the "LIMIT" portion of the query
- if (is_numeric($this->qb_limit))
+ $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
+ }
+
+ return $this->qb_orderby = "\nORDER BY ".implode(', ', $this->qb_orderby);
+ }
+ elseif (is_string($this->qb_orderby))
{
- return $this->_limit($sql."\n", $this->qb_limit, $this->qb_offset);
+ return $this->qb_orderby;
}
- return $sql;
+ return '';
}
// --------------------------------------------------------------------
@@ -2224,7 +2478,6 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
'qb_cache_from' => array(),
'qb_cache_join' => array(),
'qb_cache_where' => array(),
- 'qb_cache_like' => array(),
'qb_cache_groupby' => array(),
'qb_cache_having' => array(),
'qb_cache_orderby' => array(),
@@ -2260,8 +2513,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
{
continue;
}
-
- $this->$qb_variable = array_unique(array_merge($this->$qb_cache_var, $this->$qb_variable));
+ $this->$qb_variable = array_merge($this->$qb_variable, array_diff($this->$qb_cache_var, $this->$qb_variable));
}
// If we are "protecting identifiers" we need to examine the "from"
@@ -2271,7 +2523,37 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
$this->_track_aliases($this->qb_from);
}
- $this->qb_no_escape = $this->qb_cache_no_escape;
+ $this->qb_no_escape = array_merge($this->qb_no_escape, array_diff($this->qb_cache_no_escape, $this->qb_no_escape));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Is literal
+ *
+ * Determines if a string represents a literal value or a field name
+ *
+ * @param string $str
+ * @return bool
+ */
+ protected function _is_literal($str)
+ {
+ $str = trim($str);
+
+ if (empty($str) OR ctype_digit($str) OR (string) (float) $str === $str OR in_array(strtoupper($str), array('TRUE', 'FALSE'), TRUE))
+ {
+ return TRUE;
+ }
+
+ static $_str;
+
+ if (empty($_str))
+ {
+ $_str = ($this->_escape_char !== '"')
+ ? array('"', "'") : array("'");
+ }
+
+ return in_array($str[0], $_str, TRUE);
}
// --------------------------------------------------------------------
@@ -2301,10 +2583,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
{
foreach ($qb_reset_items as $item => $default_value)
{
- if ( ! in_array($item, $this->qb_store_array))
- {
- $this->$item = $default_value;
- }
+ $this->$item = $default_value;
}
}
@@ -2322,11 +2601,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
'qb_from' => array(),
'qb_join' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_groupby' => array(),
'qb_having' => array(),
'qb_orderby' => array(),
- 'qb_wherein' => array(),
'qb_aliased_tables' => array(),
'qb_no_escape' => array(),
'qb_distinct' => FALSE,
@@ -2351,7 +2628,6 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
'qb_set' => array(),
'qb_from' => array(),
'qb_where' => array(),
- 'qb_like' => array(),
'qb_orderby' => array(),
'qb_keys' => array(),
'qb_limit' => FALSE
diff --git a/system/database/DB_result.php b/system/database/DB_result.php
index 94782b291..e1ef341a5 100644
--- a/system/database/DB_result.php
+++ b/system/database/DB_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Result Class
@@ -38,19 +39,68 @@
*/
class CI_DB_result {
+ /**
+ * Connection ID
+ *
+ * @var resource|object
+ */
public $conn_id;
+
+ /**
+ * Result ID
+ *
+ * @var resource|object
+ */
public $result_id;
+
+ /**
+ * Result Array
+ *
+ * @var array[]
+ */
public $result_array = array();
+
+ /**
+ * Result Object
+ *
+ * @var object[]
+ */
public $result_object = array();
+
+ /**
+ * Custom Result Object
+ *
+ * @var object[]
+ */
public $custom_result_object = array();
+
+ /**
+ * Current Row index
+ *
+ * @var int
+ */
public $current_row = 0;
+
+ /**
+ * Number of rows
+ *
+ * @var int
+ */
public $num_rows;
+
+ /**
+ * Row data
+ *
+ * @var array
+ */
public $row_data;
+ // --------------------------------------------------------------------
+
/**
* Constructor
*
- * @param object
+ * @param object $driver_object
* @return void
*/
public function __construct(&$driver_object)
@@ -89,7 +139,7 @@ class CI_DB_result {
/**
* Query result. Acts as a wrapper function for the following functions.
*
- * @param string 'object', 'array' or a custom class name
+ * @param string $type 'object', 'array' or a custom class name
* @return array
*/
public function result($type = 'object')
@@ -113,8 +163,8 @@ class CI_DB_result {
/**
* Custom query result.
*
- * @param string A string that represents the type of object you want back
- * @return array of objects
+ * @param string $class_name
+ * @return array
*/
public function custom_result_object($class_name)
{
@@ -144,7 +194,7 @@ class CI_DB_result {
{
$this->custom_result_object[$class_name][$i] = new $class_name();
- foreach ($this->$_data as $key => $value)
+ foreach ($this->{$_data}[$i] as $key => $value)
{
$this->custom_result_object[$class_name][$i]->$key = $value;
}
@@ -153,7 +203,7 @@ class CI_DB_result {
return $this->custom_result_object[$class_name];
}
- $this->_data_seek(0);
+ $this->data_seek(0);
$this->custom_result_object[$class_name] = array();
while ($row = $this->_fetch_object($class_name))
@@ -196,7 +246,7 @@ class CI_DB_result {
return $this->result_object;
}
- $this->_data_seek(0);
+ $this->data_seek(0);
while ($row = $this->_fetch_object())
{
$this->result_object[] = $row;
@@ -237,7 +287,7 @@ class CI_DB_result {
return $this->result_array;
}
- $this->_data_seek(0);
+ $this->data_seek(0);
while ($row = $this->_fetch_assoc())
{
$this->result_array[] = $row;
@@ -249,29 +299,28 @@ class CI_DB_result {
// --------------------------------------------------------------------
/**
- * Query result. Acts as a wrapper function for the following functions.
+ * Row
+ *
+ * A wrapper method.
*
- * @param string
- * @param string can be "object" or "array"
- * @return mixed either a result object or array
+ * @param mixed $n
+ * @param string $type 'object' or 'array'
+ * @return mixed
*/
public function row($n = 0, $type = 'object')
{
if ( ! is_numeric($n))
{
// We cache the row data for subsequent uses
- if ( ! is_array($this->row_data))
- {
- $this->row_data = $this->row_array(0);
- }
+ is_array($this->row_data) OR $this->row_data = $this->row_array(0);
- // array_key_exists() instead of isset() to allow for MySQL NULL values
- if (array_key_exists($n, $this->row_data))
+ // array_key_exists() instead of isset() to allow for NULL values
+ if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data))
{
- return $this->row_data[$n];
+ return NULL;
}
- // reset the $n variable if the result was not achieved
- $n = 0;
+
+ return $this->row_data[$n];
}
if ($type === 'object') return $this->row_object($n);
@@ -284,6 +333,8 @@ class CI_DB_result {
/**
* Assigns an item into a particular column slot
*
+ * @param mixed $key
+ * @param mixed $value
* @return void
*/
public function set_row($key, $value = NULL)
@@ -314,6 +365,8 @@ class CI_DB_result {
/**
* Returns a single result row - custom object version
*
+ * @param int $n
+ * @param string $type
* @return object
*/
public function custom_row_object($n, $type)
@@ -338,6 +391,7 @@ class CI_DB_result {
/**
* Returns a single result row - object version
*
+ * @param int $n
* @return object
*/
public function row_object($n = 0)
@@ -361,6 +415,7 @@ class CI_DB_result {
/**
* Returns a single result row - array version
*
+ * @param int $n
* @return array
*/
public function row_array($n = 0)
@@ -384,7 +439,8 @@ class CI_DB_result {
/**
* Returns the "first" row
*
- * @return object
+ * @param string $type
+ * @return mixed
*/
public function first_row($type = 'object')
{
@@ -397,7 +453,8 @@ class CI_DB_result {
/**
* Returns the "last" row
*
- * @return object
+ * @param string $type
+ * @return mixed
*/
public function last_row($type = 'object')
{
@@ -410,7 +467,8 @@ class CI_DB_result {
/**
* Returns the "next" row
*
- * @return object
+ * @param string $type
+ * @return mixed
*/
public function next_row($type = 'object')
{
@@ -433,7 +491,8 @@ class CI_DB_result {
/**
* Returns the "previous" row
*
- * @return object
+ * @param string $type
+ * @return mixed
*/
public function previous_row($type = 'object')
{
@@ -455,8 +514,8 @@ class CI_DB_result {
/**
* Returns an unbuffered row and move pointer to next row
*
- * @param string 'array', 'object' or a custom class name
- * @return mixed either a result object or array
+ * @param string $type 'array', 'object' or a custom class name
+ * @return mixed
*/
public function unbuffered_row($type = 'object')
{
@@ -475,7 +534,7 @@ class CI_DB_result {
// --------------------------------------------------------------------
/**
- * The following functions are normally overloaded by the identically named
+ * The following methods are normally overloaded by the identically named
* methods in the platform-specific driver -- except when query caching
* is used. When caching is enabled we do not load the other driver.
* These functions are primarily here to prevent undefined function errors
@@ -483,13 +542,118 @@ class CI_DB_result {
* operational due to the unavailability of the database resource IDs with
* cached results.
*/
- public function num_fields() { return 0; }
- public function list_fields() { return array(); }
- public function field_data() { return array(); }
- public function free_result() { $this->result_id = FALSE; }
- protected function _data_seek() { return FALSE; }
- protected function _fetch_assoc() { return array(); }
- protected function _fetch_object() { return array(); }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Number of fields in the result set
+ *
+ * Overriden by driver result classes.
+ *
+ * @return int
+ */
+ public function num_fields()
+ {
+ return 0;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fetch Field Names
+ *
+ * Generates an array of column names.
+ *
+ * Overriden by driver result classes.
+ *
+ * @return array
+ */
+ public function list_fields()
+ {
+ return array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field data
+ *
+ * Generates an array of objects containing field meta-data.
+ *
+ * Overriden by driver result classes.
+ *
+ * @return array
+ */
+ public function field_data()
+ {
+ return array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Free the result
+ *
+ * Overriden by driver result classes.
+ *
+ * @return void
+ */
+ public function free_result()
+ {
+ $this->result_id = FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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.
+ *
+ * Overriden by driver result classes.
+ *
+ * @param int $n
+ * @return bool
+ */
+ public function data_seek($n = 0)
+ {
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - associative array
+ *
+ * Returns the result set as an array.
+ *
+ * Overriden by driver result classes.
+ *
+ * @return array
+ */
+ protected function _fetch_assoc()
+ {
+ return array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - object
+ *
+ * Returns the result set as an object.
+ *
+ * Overriden by driver result classes.
+ *
+ * @param string $class_name
+ * @return object
+ */
+ protected function _fetch_object($class_name = 'stdClass')
+ {
+ return array();
+ }
}
diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php
index 6a3b40779..c4140aef3 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Utility Class
@@ -32,20 +33,49 @@
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/database/
*/
-abstract class CI_DB_utility extends CI_DB_forge {
+abstract class CI_DB_utility {
- public $db;
+ /**
+ * Database object
+ *
+ * @var object
+ */
+ protected $db;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
+ protected $_list_databases = FALSE;
- // Platform specific SQL strings
- // Just setting those defaults to FALSE as they are mostly MySQL-specific
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = FALSE;
+
+ /**
+ * REPAIR TABLE statement
+ *
+ * @var string
+ */
protected $_repair_table = FALSE;
- public function __construct()
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
{
- // Assign the main database object to $this->db
- $CI =& get_instance();
- $this->db =& $CI->db;
+ $this->db =& $db;
log_message('debug', 'Database Utility Class Initialized');
}
@@ -65,7 +95,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
}
elseif ($this->_list_databases === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$this->db->data_cache['db_names'] = array();
@@ -76,9 +106,9 @@ abstract class CI_DB_utility extends CI_DB_forge {
return $this->db->data_cache['db_names'];
}
- for ($i = 0, $c = count($query); $i < $c; $i++)
+ for ($i = 0, $query = $query->result_array(), $c = count($query); $i < $c; $i++)
{
- $this->db->data_cache['db_names'] = current($query[$i]);
+ $this->db->data_cache['db_names'][] = current($query[$i]);
}
return $this->db->data_cache['db_names'];
@@ -89,7 +119,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Determine if a particular database exists
*
- * @param string
+ * @param string $database_name
* @return bool
*/
public function database_exists($database_name)
@@ -102,21 +132,21 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Optimize Table
*
- * @param string the table name
+ * @param string $table_name
* @return mixed
*/
public function optimize_table($table_name)
{
if ($this->_optimize_table === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
if ($query !== FALSE)
{
$query = $query->result_array();
- return current($res);
+ return current($query);
}
return FALSE;
@@ -133,7 +163,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
{
if ($this->_optimize_table === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$result = array();
@@ -163,14 +193,14 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Repair Table
*
- * @param string the table name
+ * @param string $table_name
* @return mixed
*/
public function repair_table($table_name)
{
if ($this->_repair_table === FALSE)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name)));
@@ -188,10 +218,10 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Generate CSV from a query result object
*
- * @param object The query result object
- * @param string The delimiter - comma by default
- * @param string The newline character - \n by default
- * @param string The enclosure - double quote by default
+ * @param object $query Query result object
+ * @param string $delim Delimiter (default: ,)
+ * @param string $newline Newline character (default: \n)
+ * @param string $enclosure Enclosure (default: ")
* @return string
*/
public function csv_from_result($query, $delim = ',', $newline = "\n", $enclosure = '"')
@@ -228,8 +258,8 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Generate XML data from a query result object
*
- * @param object The query result object
- * @param array Any preferences
+ * @param object $query Query result object
+ * @param array $params Any preferences
* @return string
*/
public function xml_from_result($query, $params = array())
@@ -275,6 +305,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
/**
* Database Backup
*
+ * @param array $params
* @return void
*/
public function backup($params = array())
@@ -287,8 +318,6 @@ abstract class CI_DB_utility extends CI_DB_forge {
$params = array('tables' => $params);
}
- // ------------------------------------------------------
-
// Set up our default preferences
$prefs = array(
'tables' => array(),
@@ -332,7 +361,7 @@ abstract class CI_DB_utility extends CI_DB_forge {
{
if ($this->db->db_debug)
{
- return $this->db->display_error('db_unsuported_compression');
+ return $this->db->display_error('db_unsupported_compression');
}
$prefs['format'] = 'txt';
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index a3d0287f5..21994b093 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Database Adapter Class
@@ -40,20 +41,44 @@
*/
class CI_DB_cubrid_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'cubrid';
- // The character used for escaping - no need in CUBRID
- protected $_escape_char = '`';
+ /**
+ * Auto-commit flag
+ *
+ * @var bool
+ */
+ public $auto_commit = TRUE;
- // clause and character used for LIKE escape sequences - not used in CUBRID
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '';
+ // --------------------------------------------------------------------
- protected $_random_keyword = ' RAND()'; // database specific random keyword
+ /**
+ * Identifier escape character
+ *
+ * @var string
+ */
+ protected $_escape_char = '`';
- // CUBRID-specific properties
- public $auto_commit = TRUE;
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM(%d)');
+
+ // --------------------------------------------------------------------
+ /**
+ * Class constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -72,6 +97,8 @@ class CI_DB_cubrid_driver extends CI_DB {
}
}
+ // --------------------------------------------------------------------
+
/**
* Non-persistent database connection
*
@@ -109,7 +136,7 @@ class CI_DB_cubrid_driver extends CI_DB {
* Except for determining if a persistent connection should be used,
* the rest of the logic is the same for db_connect() and db_pconnect().
*
- * @param bool
+ * @param bool $persistent
* @return resource
*/
protected function _cubrid_connect($persistent = FALSE)
@@ -159,9 +186,18 @@ class CI_DB_cubrid_driver extends CI_DB {
*/
public function version()
{
- return isset($this->data_cache['version'])
- ? $this->data_cache['version']
- : $this->data_cache['version'] = cubrid_get_server_info($this->conn_id);
+ if (isset($this->data_cache['version']))
+ {
+ return $this->data_cache['version'];
+ }
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
+
+ return ( ! $this->conn_id OR ($version = cubrid_get_server_info($this->conn_id)) === FALSE)
+ ? FALSE
+ : $this->data_cache['version'] = $version;
}
// --------------------------------------------------------------------
@@ -169,7 +205,7 @@ class CI_DB_cubrid_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -182,6 +218,7 @@ class CI_DB_cubrid_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -260,8 +297,8 @@ class CI_DB_cubrid_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -327,7 +364,7 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -349,7 +386,7 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -360,16 +397,40 @@ class CI_DB_cubrid_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT * FROM '.$table.' LIMIT 1';
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->Field;
+
+ sscanf($query[$i]->Type, '%[a-z](%d)',
+ $retval[$i]->type,
+ $retval[$i]->max_length
+ );
+
+ $retval[$i]->default = $query[$i]->Default;
+ $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -394,12 +455,12 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* Generates a platform-specific batch update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -423,9 +484,29 @@ class CI_DB_cubrid_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index d328aa241..db1ce5f70 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Forge Class
@@ -34,181 +35,182 @@
*/
class CI_DB_cubrid_forge extends CI_DB_forge {
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
protected $_create_database = FALSE;
- protected $_drop_database = FALSE;
/**
- * Process Fields
+ * CREATE TABLE keys flag
*
- * @param mixed the fields
- * @return string
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
*/
- protected function _process_fields($fields)
- {
- $current_field_count = 0;
- $sql = '';
+ protected $_create_table_keys = TRUE;
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field);
-
- empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
-
- if ( ! empty($attributes['TYPE']))
- {
- $sql .= ' '.$attributes['TYPE'];
-
- if ( ! empty($attributes['CONSTRAINT']))
- {
- switch (strtolower($attributes['TYPE']))
- {
- case 'decimal':
- case 'float':
- case 'numeric':
- $sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
- break;
- case 'enum':
- // Will be supported in the future as part a part of
- // MySQL compatibility features.
- break;
- case 'set':
- $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
- break;
- default:
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
- }
- }
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
+ protected $_drop_database = FALSE;
- /* As of version 8.4.1 CUBRID does not support UNSIGNED INTEGER data type.
- * Will be supported in the next release as a part of MySQL Compatibility.
- *
- if (isset($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
- */
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = FALSE;
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SHORT' => 'INTEGER',
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INTEGER' => 'BIGINT',
+ 'BIGINT' => 'NUMERIC',
+ 'FLOAT' => 'DOUBLE',
+ 'REAL' => 'DOUBLE'
+ );
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ // --------------------------------------------------------------------
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
- if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
- {
- $sql .= ' UNIQUE';
- }
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ $sqls[] = $sql.' CHANGE '.$field[$i]['_literal'];
}
-
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
+ else
{
- $sql .= ',';
+ $alter_type = empty($field[$i]['new_name']) ? ' MODIFY ' : ' CHANGE ';
+ $sqls[] = $sql.$alter_type.$this->_process_column($field[$i]);
}
}
- return $sql;
+ return $sqls;
}
// --------------------------------------------------------------------
/**
- * Create Table
+ * Process column
*
- * @param string the table name
- * @param mixed the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @param array $field
+ * @return string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _process_column($field)
{
- $sql = 'CREATE TABLE ';
+ $extra_clause = isset($field['after'])
+ ? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
- /* As of version 8.4.1 CUBRID does not support this SQL syntax.
- if ($if_not_exists === TRUE)
+ if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
{
- $sql .= 'IF NOT EXISTS ';
+ $extra_clause = ' FIRST';
}
- */
- $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
+ return $this->db->escape_identifiers($field['name'])
+ .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['null']
+ .$field['default']
+ .$field['auto_increment']
+ .$field['unique']
+ .$extra_clause;
+ }
- // If there is a PK defined
- if (count($primary_keys) > 0)
- {
- $key_name = $this->db->escape_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
- $sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
- }
+ // --------------------------------------------------------------------
- if (is_array($keys) && count($keys) > 0)
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
{
- foreach ($keys as $key)
- {
- if (is_array($key))
- {
- $key_name = $this->db->escape_identifiers('idx_'.$table.implode('_', $key));
- $key = $this->db->escape_identifiers($key);
- }
- else
- {
- $key_name = $this->db->escape_identifiers('idx_'.$table.$key);
- $key = array($key_name);
- }
-
- $sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')';
- }
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ default: return;
}
-
- return $sql."\n);";
}
// --------------------------------------------------------------------
/**
- * Alter table query
- *
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Process indexes
*
- * @param string the ALTER type (ADD, DROP, CHANGE)
- * @param string the column name
- * @param array fields
- * @param string the field after which we should add the new field
+ * @param string $table (ignored)
* @return string
*/
- protected function _alter_table($alter_type, $table, $fields, $after_field = '')
+ protected function _process_indexes($table)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
+ $sql = '';
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
{
- return $sql.$this->db->escape_identifiers($fields);
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
}
- return $sql.$this->_process_fields($fields)
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ $this->keys = array();
+
+ return $sql;
}
}
diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php
index 4a06a2d39..793b35b74 100644
--- a/system/database/drivers/cubrid/cubrid_result.php
+++ b/system/database/drivers/cubrid/cubrid_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Result Class
@@ -87,20 +88,14 @@ class CI_DB_cubrid_result extends CI_DB_result {
public function field_data()
{
$retval = array();
- $i = 0;
- while ($field = cubrid_fetch_field($this->result_id))
+ for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
{
$retval[$i] = new stdClass();
- $retval[$i]->name = $field->name;
- // CUBRID returns type as e.g. varchar(100),
- // so we need to remove all digits and brackets.
- $retval[$i]->type = preg_replace('/[\d()]/', '', $field->type);
- $retval[$i]->default = $field->def;
- // Use CUBRID's native API to obtain column's max_length,
- // otherwise $field->max_length has incorrect info
+ $retval[$i]->name = cubrid_field_name($this->result_id, $i);
+ $retval[$i]->type = cubrid_field_type($this->result_id, $i);
$retval[$i]->max_length = cubrid_field_len($this->result_id, $i);
- $retval[$i++]->primary_key = $field->primary_key;
+ $retval[$i]->primary_key = (int) (strpos(cubrid_field_flags($this->result_id, $i), 'primary_key') !== FALSE);
}
return $retval;
@@ -130,11 +125,12 @@ class CI_DB_cubrid_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return cubrid_data_seek($this->result_id, $n);
}
@@ -160,7 +156,7 @@ class CI_DB_cubrid_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php
index ea8feb4e2..d76eca432 100644
--- a/system/database/drivers/cubrid/cubrid_utility.php
+++ b/system/database/drivers/cubrid/cubrid_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Utility Class
@@ -62,7 +63,7 @@ class CI_DB_cubrid_utility extends CI_DB_utility {
// No SQL based support in CUBRID as of version 8.4.0. Database or
// table backup can be performed using CUBRID Manager
// database administration tool.
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index c9027670d..15c2a4630 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 3.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Firebird/Interbase Database Adapter Class
@@ -40,19 +41,30 @@
*/
class CI_DB_ibase_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'ibase';
- // The character used to escape with
- protected $_escape_char = '"';
+ // --------------------------------------------------------------------
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RAND()', 'RAND()');
- protected $_random_keyword = ' Random()'; // database specific random keyword
+ /**
+ * IBase Transaction status flag
+ *
+ * @var resource
+ */
+ protected $_ibase_trans;
- // Keeps track of the resource for the current transaction
- protected $trans;
+ // --------------------------------------------------------------------
/**
* Non-persistent database connection
@@ -107,7 +119,7 @@ class CI_DB_ibase_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -120,6 +132,7 @@ class CI_DB_ibase_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -135,7 +148,7 @@ class CI_DB_ibase_driver extends CI_DB {
// even if the queries produce a successful result.
$this->_trans_failure = ($test_mode === TRUE);
- $this->trans = @ibase_trans($this->conn_id);
+ $this->_ibase_trans = @ibase_trans($this->conn_id);
return TRUE;
}
@@ -155,7 +168,7 @@ class CI_DB_ibase_driver extends CI_DB {
return TRUE;
}
- return @ibase_commit($this->trans);
+ return @ibase_commit($this->_ibase_trans);
}
// --------------------------------------------------------------------
@@ -173,7 +186,7 @@ class CI_DB_ibase_driver extends CI_DB {
return TRUE;
}
- return @ibase_rollback($this->trans);
+ return @ibase_rollback($this->_ibase_trans);
}
// --------------------------------------------------------------------
@@ -181,8 +194,8 @@ class CI_DB_ibase_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -242,7 +255,7 @@ class CI_DB_ibase_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -265,7 +278,7 @@ class CI_DB_ibase_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -276,16 +289,46 @@ class CI_DB_ibase_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return $this->_limit('SELECT * FROM '.$this->protect_identifiers($table), 1, NULL);
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name",
+ CASE "fields"."RDB$FIELD_TYPE"
+ WHEN 7 THEN \'SMALLINT\'
+ WHEN 8 THEN \'INTEGER\'
+ WHEN 9 THEN \'QUAD\'
+ WHEN 10 THEN \'FLOAT\'
+ WHEN 11 THEN \'DFLOAT\'
+ WHEN 12 THEN \'DATE\'
+ WHEN 13 THEN \'TIME\'
+ WHEN 14 THEN \'CHAR\'
+ WHEN 16 THEN \'INT64\'
+ WHEN 27 THEN \'DOUBLE\'
+ WHEN 35 THEN \'TIMESTAMP\'
+ WHEN 37 THEN \'VARCHAR\'
+ WHEN 40 THEN \'CSTRING\'
+ WHEN 261 THEN \'BLOB\'
+ ELSE NULL
+ END AS "type",
+ "fields"."RDB$FIELD_LENGTH" AS "max_length",
+ "rfields"."RDB$DEFAULT_VALUE" AS "default"
+ FROM "RDB$RELATION_FIELDS" "rfields"
+ JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME"
+ WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).'
+ ORDER BY "rfields"."RDB$FIELD_POSITION"';
+
+ return (($query = $this->query($sql)) !== FALSE)
+ ? $query->result_object()
+ : FALSE;
}
// --------------------------------------------------------------------
@@ -306,51 +349,18 @@ class CI_DB_ibase_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
- * @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 (ignored)
- * @param array the like clause
+ * @param string $table
+ * @param array $values
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
- .$where
- .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -360,10 +370,10 @@ class CI_DB_ibase_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
@@ -378,46 +388,37 @@ class CI_DB_ibase_driver extends CI_DB {
*
* Generates a platform-specific delete string from the supplied data
*
- * @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
+ * @param string $table
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT
*
* Generates a platform-specific LIMIT clause
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
- $select = 'FIRST '. (int) $limit
- .($offset ? ' SKIP '. (int) $offset : '');
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
- .($offset ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+ .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
diff --git a/system/database/drivers/ibase/ibase_forge.php b/system/database/drivers/ibase/ibase_forge.php
index da75eb9c3..39c782816 100644
--- a/system/database/drivers/ibase/ibase_forge.php
+++ b/system/database/drivers/ibase/ibase_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 3.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Forge Class
@@ -34,12 +35,51 @@
*/
class CI_DB_ibase_forge extends CI_DB_forge {
- protected $_drop_table = 'DROP TABLE %s';
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = FALSE;
+
+ /**
+ * RENAME TABLE statement
+ *
+ * @var string
+ */
+ protected $_rename_table = FALSE;
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = FALSE;
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SMALLINT' => 'INTEGER',
+ 'INTEGER' => 'INT64',
+ 'FLOAT' => 'DOUBLE PRECISION'
+ );
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
/**
* Create database
*
- * @param string the database name
+ * @param string $db_name
* @return string
*/
public function create_database($db_name)
@@ -57,8 +97,7 @@ class CI_DB_ibase_forge extends CI_DB_forge {
/**
* Drop database
*
- * @param string the database name
- * - not used in this driver, the current db is dropped
+ * @param string $db_name (ignored)
* @return bool
*/
public function drop_database($db_name = '')
@@ -82,110 +121,120 @@ class CI_DB_ibase_forge extends CI_DB_forge {
// --------------------------------------------------------------------
/**
- * Create Table
+ * ALTER TABLE
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return string
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = 'CREATE TABLE ';
-
- $sql .= $this->db->escape_identifiers($table).'(';
- $current_field_count = 0;
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
- foreach ($fields as $field => $attributes)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- // 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
+ if ($field[$i]['_literal'] !== FALSE)
{
- $sql .= "\n\t".$attributes;
+ return FALSE;
}
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
-
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
+ if (isset($field[$i]['type']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identififers($field[$i]['name'])
+ .' TYPE '.$field[$i]['type'].$field[$i]['length'];
}
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
+ if ( ! empty($field[$i]['default']))
{
- $sql .= ',';
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' SET DEFAULT '.$field[$i]['default'];
}
- }
- if (count($primary_keys) > 0)
- {
- $primary_keys = $this->db->escape_identifiers($primary_keys);
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
- }
-
- if (is_array($keys) && count($keys) > 0)
- {
- foreach ($keys as $key)
+ if (isset($field[$i]['null']))
{
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
+ $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = '
+ .($field[$i]['null'] === TRUE ? 'NULL' : '1')
+ .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name'])
+ .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table);
+ }
- $sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
+ if ( ! empty($field[$i]['new_name']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TO '.$this->db->escape_identifiers($field[$i]['new_name']);
}
}
- return $sql."\n)";
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type'].$field['length']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute TYPE
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Performs a data type mapping between different databases.
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INT':
+ $attributes['TYPE'] = 'INTEGER';
+ return;
+ case 'BIGINT':
+ $attributes['TYPE'] = 'INT64';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_auto_increment(&$attributes, &$field)
{
- return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
- .' '.$column_definition
- .($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ // Not supported
}
}
diff --git a/system/database/drivers/ibase/ibase_result.php b/system/database/drivers/ibase/ibase_result.php
index 95e55710b..4f5637a72 100644
--- a/system/database/drivers/ibase/ibase_result.php
+++ b/system/database/drivers/ibase/ibase_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Result Class
@@ -88,8 +89,6 @@ class CI_DB_ibase_result extends CI_DB_result {
$retval[$i]->name = $info['name'];
$retval[$i]->type = $info['type'];
$retval[$i]->max_length = $info['length'];
- $retval[$i]->primary_key = 0;
- $retval[$i]->default = '';
}
return $retval;
@@ -128,7 +127,7 @@ class CI_DB_ibase_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/ibase/ibase_utility.php b/system/database/drivers/ibase/ibase_utility.php
index d0e84a7b2..5eb209ae1 100644
--- a/system/database/drivers/ibase/ibase_utility.php
+++ b/system/database/drivers/ibase/ibase_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 3.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Utility Class
@@ -34,10 +35,8 @@
*/
class CI_DB_ibase_utility extends CI_DB_utility {
- protected $_list_databases = FALSE;
-
/**
- * Interbase/Firebird Export
+ * Export
*
* @param string $filename
* @return mixed
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 1714704a8..d3e439d69 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Database Adapter Class
@@ -40,26 +41,40 @@
*/
class CI_DB_mssql_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'mssql';
- // The character used for escaping
- protected $_escape_char = '"';
-
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ // --------------------------------------------------------------------
- protected $_random_keyword = ' NEWID()';
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('NEWID()', 'RAND(%d)');
- // MSSQL-specific properties
+ /**
+ * Quoted identifier flag
+ *
+ * Whether to use SQL-92 standard quoted identifier
+ * (double quotes) or brackets for identifier escaping.
+ *
+ * @var bool
+ */
protected $_quoted_identifier = TRUE;
- /*
- * Constructor
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
*
* Appends the port number to the hostname, if needed.
*
- * @param array
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -77,7 +92,7 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Non-persistent database connection
*
- * @param bool
+ * @param bool $persistent
* @return resource
*/
public function db_connect($persistent = FALSE)
@@ -117,7 +132,7 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Select the database
*
- * @param string database name
+ * @param string $database
* @return bool
*/
public function db_select($database = '')
@@ -143,7 +158,7 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return mixed resource if rows are returned, bool otherwise
*/
protected function _execute($sql)
@@ -156,6 +171,7 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -215,8 +231,8 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -282,6 +298,19 @@ class CI_DB_mssql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Set client character set
+ *
+ * @param string $charset
+ * @return bool
+ */
+ protected function _db_set_charset($charset)
+ {
+ return (@ini_set('mssql.charset', $charset) !== FALSE);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Version number query string
*
* @return string
@@ -298,7 +327,7 @@ class CI_DB_mssql_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -323,27 +352,52 @@ class CI_DB_mssql_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
- return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
+ return 'SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
}
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+ $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -366,49 +420,19 @@ class CI_DB_mssql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
+ * @param string $table
+ * @param array $values
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -418,10 +442,10 @@ class CI_DB_mssql_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
@@ -436,61 +460,65 @@ class CI_DB_mssql_driver extends CI_DB {
*
* Generates a platform-specific delete string from the supplied data
*
- * @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
+ * @param string $table
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT
*
* Generates a platform-specific LIMIT clause
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- // As of SQL Server 2012 (11.0.*) OFFSET is supported
- if (version_compare($this->version(), '11', '>='))
- {
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
- }
-
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
- if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
@@ -499,6 +527,29 @@ class CI_DB_mssql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Insert batch statement
+ *
+ * Generates a platform-specific insert string from the supplied data.
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string|bool
+ */
+ protected function _insert_batch($table, $keys, $values)
+ {
+ // Multiple-value inserts are only supported as of SQL Server 2008
+ if (version_compare($this->version(), '10', '>='))
+ {
+ return parent::_insert_batch($table, $keys, $values);
+ }
+
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index 3a3528f7b..5eebedbf7 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Forge Class
@@ -34,124 +35,99 @@
*/
class CI_DB_mssql_forge extends CI_DB_forge {
- protected $_drop_table = 'DROP TABLE %s';
-
/**
- * Create Table
+ * CREATE TABLE IF statement
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return string
+ * @var string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = ($if_not_exists === TRUE)
- ? "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'".$table."') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\n"
- : '';
-
- $sql .= 'CREATE TABLE '.$this->db->escape_identifiers($table).' (';
-
- $current_field_count = 0;
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
- {
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
+ protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE";
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE";
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT' => 'SMALLINT',
+ 'SMALLINT' => 'INT',
+ 'INT' => 'BIGINT',
+ 'REAL' => 'FLOAT'
+ );
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ // --------------------------------------------------------------------
- if (count($primary_keys) > 0)
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
{
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+ return parent::_alter_table($alter_type, $table, $field);
}
- if (is_array($keys) && count($keys) > 0)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN ';
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
- }
+ $sqls[] = $sql.$this->_process_column($field[$i]);
}
- return $sql."\n)";
+ return $sqls;
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute TYPE
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Performs a data type mapping between different databases.
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_type(&$attributes)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
+ switch (strtoupper($attributes['TYPE']))
{
- return $sql;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INTEGER':
+ $attributes['TYPE'] = 'INT';
+ return;
+ default: return;
}
+ }
- return $sql.' '.$column_definition
- .($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' IDENTITY(1,1)';
+ }
}
}
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index aeede3f4b..ca222aed4 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MSSQL Result Class
@@ -93,16 +94,14 @@ class CI_DB_mssql_result extends CI_DB_result {
public function field_data()
{
$retval = array();
- while ($field = mssql_fetch_field($this->result_id))
+ for ($i = 0, $c = $this->num_field(); $i < $c; $i++)
{
- $F = new stdClass();
- $F->name = $field->name;
- $F->type = $field->type;
- $F->max_length = $field->max_length;
- $F->primary_key = 0;
- $F->default = '';
-
- $retval[] = $F;
+ $field = mssql_fetch_field($this->result_id, $i);
+
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $field->name;
+ $retval[$i]->type = $field->type;
+ $retval[$i]->max_length = $field->max_length;
}
return $retval;
@@ -131,11 +130,12 @@ class CI_DB_mssql_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return mssql_data_seek($this->result_id, $n);
}
@@ -161,7 +161,7 @@ class CI_DB_mssql_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php
index 69fcec5f6..76c7cb9c2 100644
--- a/system/database/drivers/mssql/mssql_utility.php
+++ b/system/database/drivers/mssql/mssql_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Utility Class
@@ -34,19 +35,30 @@
*/
class CI_DB_mssql_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases
+
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = 'ALTER INDEX all ON %s REORGANIZE';
/**
- * MSSQL Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return bool
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 29db90408..5af44371c 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQL Database Adapter Class
@@ -40,28 +41,46 @@
*/
class CI_DB_mysql_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'mysql';
- // The character used for escaping
- protected $_escape_char = '`';
-
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
- protected $_random_keyword = ' RAND()'; // database specific random keyword
+ /**
+ * Compression flag
+ *
+ * @var bool
+ */
+ public $compress = FALSE;
/**
+ * DELETE hack flag
+ *
* Whether to use the MySQL "delete hack" which allows the number
* of affected rows to be shown. Uses a preg_replace when enabled,
* adding a bit more processing to all queries.
+ *
+ * @var bool
*/
public $delete_hack = TRUE;
+ // --------------------------------------------------------------------
+
+ /**
+ * Identifier escape character
+ *
+ * @var string
+ */
+ protected $_escape_char = '`';
+
+ // --------------------------------------------------------------------
+
/**
- * Constructor
+ * Class constructor
*
- * @param array
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -79,11 +98,21 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Non-persistent database connection
*
+ * @param bool $persistent
* @return resource
*/
- public function db_connect()
+ public function db_connect($persistent = FALSE)
{
- return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ $client_flags = ($this->compress === FALSE) ? 0 : MYSQL_CLIENT_COMPRESS;
+
+ if ($this->encrypt === TRUE)
+ {
+ $client_flags = $client_flags | MYSQL_CLIENT_SSL;
+ }
+
+ return ($persistent === TRUE)
+ ? @mysql_pconnect($this->hostname, $this->username, $this->password, $client_flags)
+ : @mysql_connect($this->hostname, $this->username, $this->password, TRUE, $client_flags);
}
// --------------------------------------------------------------------
@@ -95,7 +124,7 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ return $this->db_connect(TRUE);
}
// --------------------------------------------------------------------
@@ -121,7 +150,7 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Select the database
*
- * @param string database name
+ * @param string $database
* @return bool
*/
public function db_select($database = '')
@@ -145,7 +174,7 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Set client character set
*
- * @param string
+ * @param string $charset
* @return bool
*/
protected function _db_set_charset($charset)
@@ -162,9 +191,21 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function version()
{
- return isset($this->data_cache['version'])
- ? $this->data_cache['version']
- : $this->data_cache['version'] = @mysql_get_server_info($this->conn_id);
+ if (isset($this->data_cache['version']))
+ {
+ return $this->data_cache['version'];
+ }
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
+
+ if ( ! $this->conn_id OR ($version = @mysql_get_server_info($this->conn_id)) === FALSE)
+ {
+ return FALSE;
+ }
+
+ return $this->data_cache['version'] = $version;
}
// --------------------------------------------------------------------
@@ -172,7 +213,7 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return mixed
*/
protected function _execute($sql)
@@ -187,7 +228,7 @@ class CI_DB_mysql_driver extends CI_DB {
*
* If needed, each database adapter can prep the query string
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return string
*/
protected function _prep_query($sql)
@@ -207,6 +248,7 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -272,8 +314,8 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -281,12 +323,12 @@ class CI_DB_mysql_driver extends CI_DB {
if (is_array($str))
{
foreach ($str as $key => $val)
- {
+ {
$str[$key] = $this->escape_str($val, $like);
- }
+ }
- return $str;
- }
+ return $str;
+ }
$str = is_resource($this->conn_id) ? mysql_real_escape_string($str, $this->conn_id) : addslashes($str);
@@ -332,7 +374,7 @@ class CI_DB_mysql_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -354,7 +396,7 @@ class CI_DB_mysql_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -367,8 +409,8 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Returns an object with field data
*
- * @param string the table name
- * @return object
+ * @param string $table
+ * @return array
*/
public function field_data($table = '')
{
@@ -377,19 +419,24 @@ class CI_DB_mysql_driver extends CI_DB {
return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
}
- $query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+ if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
+ {
+ return FALSE;
+ }
$query = $query->result_object();
$retval = array();
for ($i = 0, $c = count($query); $i < $c; $i++)
{
- preg_match('/([a-z]+)(\(\d+\))?/', $query[$i]->Type, $matches);
-
$retval[$i] = new stdClass();
$retval[$i]->name = $query[$i]->Field;
- $retval[$i]->type = empty($matches[1]) ? NULL : $matches[1];
+
+ sscanf($query[$i]->Type, '%[a-z](%d)',
+ $retval[$i]->type,
+ $retval[$i]->max_length
+ );
+
$retval[$i]->default = $query[$i]->Default;
- $retval[$i]->max_length = empty($matches[2]) ? NULL : preg_replace('/[^\d]/', '', $matches[2]);
$retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
}
@@ -418,12 +465,12 @@ class CI_DB_mysql_driver extends CI_DB {
*
* Generates a platform-specific batch update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -434,7 +481,7 @@ class CI_DB_mysql_driver extends CI_DB {
{
if ($field !== $index)
{
- $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
+ $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
}
}
}
@@ -447,9 +494,29 @@ class CI_DB_mysql_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index 2ac75bad2..f4394c685 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQL Forge Class
@@ -34,165 +35,178 @@
*/
class CI_DB_mysql_forge extends CI_DB_forge {
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s';
/**
- * Process Fields
+ * CREATE TABLE keys flag
*
- * @param mixed the fields
- * @return string
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
*/
- protected function _process_fields($fields)
- {
- $current_field_count = 0;
- $sql = '';
-
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field);
-
- empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
-
- if ( ! empty($attributes['TYPE']))
- {
- $sql .= ' '.$attributes['TYPE'];
-
- if ( ! empty($attributes['CONSTRAINT']))
- {
- switch (strtolower($attributes['TYPE']))
- {
- case 'decimal':
- case 'float':
- case 'numeric':
- $sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
- break;
- case 'enum':
- case 'set':
- $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
- break;
- default:
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
- }
- }
+ protected $_create_table_keys = TRUE;
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT',
+ 'SMALLINT',
+ 'MEDIUMINT',
+ 'INT',
+ 'INTEGER',
+ 'BIGINT',
+ 'REAL',
+ 'DOUBLE',
+ 'DOUBLE PRECISION',
+ 'FLOAT',
+ 'DECIMAL',
+ 'NUMERIC'
+ );
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ // --------------------------------------------------------------------
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
- return $sql;
+ $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat;
}
// --------------------------------------------------------------------
/**
- * Create Table
+ * ALTER TABLE
*
- * @param string the table name
- * @param mixed the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _alter_table($alter_type, $table, $field)
{
- $sql = 'CREATE TABLE ';
-
- if ($if_not_exists === TRUE)
- {
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
-
- if (count($primary_keys) > 0)
+ if ($alter_type === 'DROP')
{
- $key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
- $sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+ return parent::_alter_table($alter_type, $table, $field);
}
- if (is_array($keys) && count($keys) > 0)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- foreach ($keys as $key)
+ if ($field[$i]['_literal'] !== FALSE)
{
- if (is_array($key))
+ $field[$i] = ($alter_type === 'ADD')
+ ? "\n\tADD ".$field[$i]['_literal']
+ : "\n\tMODIFY ".$field[$i]['_literal'];
+ }
+ else
+ {
+ if ($alter_type === 'ADD')
{
- $key_name = $this->db->escape_identifiers(implode('_', $key));
- $key = $this->db->escape_identifiers($key);
+ $field[$i]['_literal'] = "\n\tADD ";
}
else
{
- $key_name = $this->db->escape_identifiers($key);
- $key = array($key_name);
+ $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE ";
}
- $sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')';
+ $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]);
}
}
- return $sql."\n) DEFAULT CHARACTER SET ".$this->db->char_set.' COLLATE '.$this->db->dbcollat.';';
+ return array($sql.implode(',', $field));
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Process column
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column() and column_alter()
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ $extra_clause = isset($field['after'])
+ ? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
+
+ if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
+ {
+ $extra_clause = ' FIRST';
+ }
+
+ return $this->db->escape_identifiers($field['name'])
+ .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['null']
+ .$field['default']
+ .$field['auto_increment']
+ .$field['unique']
+ .$extra_clause;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process indexes
*
- * @param string the ALTER type (ADD, DROP, CHANGE)
- * @param string the column name
- * @param array fields
- * @param string the field after which we should add the new field
+ * @param string $table (ignored)
* @return string
*/
- protected function _alter_table($alter_type, $table, $fields, $after_field = '')
+ protected function _process_indexes($table)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
+ $sql = '';
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
{
- return $sql.$this->db->escape_identifiers($fields);
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
}
- return $sql.$this->_process_fields($fields)
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ $this->keys = array();
+
+ return $sql;
}
}
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 7fbb65496..293980e97 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQL Result Class
@@ -38,9 +39,9 @@
class CI_DB_mysql_result extends CI_DB_result {
/**
- * Constructor
+ * Class constructor
*
- * @param object
+ * @param object &$driver_object
* @return void
*/
public function __construct(&$driver_object)
@@ -114,8 +115,7 @@ class CI_DB_mysql_result extends CI_DB_result {
$retval[$i]->name = mysql_field_name($this->result_id, $i);
$retval[$i]->type = mysql_field_type($this->result_id, $i);
$retval[$i]->max_length = mysql_field_len($this->result_id, $i);
- $retval[$i]->primary_key = (strpos(mysql_field_flags($this->result_id, $i), 'primary_key') === FALSE) ? 0 : 1;
- $retval[$i]->default = '';
+ $retval[$i]->primary_key = (int) (strpos(mysql_field_flags($this->result_id, $i), 'primary_key') !== FALSE);
}
return $retval;
@@ -144,11 +144,12 @@ class CI_DB_mysql_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return $this->num_rows
? @mysql_data_seek($this->result_id, $n)
@@ -176,7 +177,7 @@ class CI_DB_mysql_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index f0bbc665e..8aa051755 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQL Utility Class
@@ -34,14 +35,33 @@
*/
class CI_DB_mysql_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'SHOW DATABASES';
+
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = 'OPTIMIZE TABLE %s';
+
+ /**
+ * REPAIR TABLE statement
+ *
+ * @var string
+ */
protected $_repair_table = 'REPAIR TABLE %s';
+ // --------------------------------------------------------------------
+
/**
- * MySQL Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index be61aab20..17f025f61 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQLi Database Adapter Class
@@ -40,34 +41,60 @@
*/
class CI_DB_mysqli_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'mysqli';
- // The character used for escaping
- protected $_escape_char = '`';
-
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
- protected $_random_keyword = ' RAND()'; // database specific random keyword
+ /**
+ * Compression flag
+ *
+ * @var bool
+ */
+ public $compress = FALSE;
/**
+ * DELETE hack flag
+ *
* Whether to use the MySQL "delete hack" which allows the number
* of affected rows to be shown. Uses a preg_replace when enabled,
* adding a bit more processing to all queries.
+ *
+ * @var bool
*/
public $delete_hack = TRUE;
+ // --------------------------------------------------------------------
+
/**
- * Non-persistent database connection
+ * Identifier escape character
*
+ * @var string
+ */
+ protected $_escape_char = '`';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database connection
+ *
+ * @param bool $persistent
* @return object
+ * @todo SSL support
*/
- public function db_connect()
+ public function db_connect($persistent = FALSE)
{
- return empty($this->port)
- ? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
- : @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
+ // Persistent connection support was added in PHP 5.3.0
+ $hostname = ($persistent === TRUE && is_php('5.3'))
+ ? 'p:'.$this->hostname : $this->hostname;
+ $port = empty($this->port) ? NULL : $this->port;
+ $client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0;
+ $mysqli = mysqli_init();
+
+ return @$mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, NULL, $client_flags)
+ ? $mysqli : FALSE;
}
// --------------------------------------------------------------------
@@ -79,15 +106,7 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function db_pconnect()
{
- // Persistent connection support was added in PHP 5.3.0
- if ( ! is_php('5.3'))
- {
- return $this->db_connect();
- }
-
- return empty($this->port)
- ? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
- : @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
+ return $this->db_connect(TRUE);
}
// --------------------------------------------------------------------
@@ -113,7 +132,7 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Select the database
*
- * @param string database name
+ * @param string $database
* @return bool
*/
public function db_select($database = '')
@@ -137,7 +156,7 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Set client character set
*
- * @param string
+ * @param string $charset
* @return bool
*/
protected function _db_set_charset($charset)
@@ -154,9 +173,16 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function version()
{
- return isset($this->data_cache['version'])
- ? $this->data_cache['version']
- : $this->data_cache['version'] = $this->conn_id->server_info;
+ if (isset($this->data_cache['version']))
+ {
+ return $this->data_cache['version'];
+ }
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
+
+ return $this->data_cache['version'] = $this->conn_id->server_info;
}
// --------------------------------------------------------------------
@@ -164,7 +190,7 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return mixed
*/
protected function _execute($sql)
@@ -179,7 +205,7 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* If needed, each database adapter can prep the query string
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return string
*/
protected function _prep_query($sql)
@@ -199,6 +225,7 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -264,8 +291,8 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -324,7 +351,7 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -346,7 +373,7 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -359,8 +386,8 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Returns an object with field data
*
- * @param string the table name
- * @return object
+ * @param string $table
+ * @return array
*/
public function field_data($table = '')
{
@@ -369,19 +396,24 @@ class CI_DB_mysqli_driver extends CI_DB {
return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
}
- $query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+ if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
+ {
+ return FALSE;
+ }
$query = $query->result_object();
$retval = array();
for ($i = 0, $c = count($query); $i < $c; $i++)
{
- preg_match('/([a-z]+)(\(\d+\))?/', $query[$i]->Type, $matches);
-
$retval[$i] = new stdClass();
$retval[$i]->name = $query[$i]->Field;
- $retval[$i]->type = empty($matches[1]) ? NULL : $matches[1];
+
+ sscanf($query[$i]->Type, '%[a-z](%d)',
+ $retval[$i]->type,
+ $retval[$i]->max_length
+ );
+
$retval[$i]->default = $query[$i]->Default;
- $retval[$i]->max_length = empty($matches[2]) ? NULL : preg_replace('/[^\d]/', '', $matches[2]);
$retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
}
@@ -400,6 +432,14 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function error()
{
+ if ( ! empty($this->conn_id->connect_errno))
+ {
+ return array(
+ 'code' => $this->conn_id->connect_errno,
+ 'message' => is_php('5.2.9') ? $this->conn_id->connect_error : mysqli_connect_error()
+ );
+ }
+
return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error);
}
@@ -410,12 +450,12 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* Generates a platform-specific batch update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -426,7 +466,7 @@ class CI_DB_mysqli_driver extends CI_DB {
{
if ($field !== $index)
{
- $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
+ $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
}
}
}
@@ -439,11 +479,29 @@ class CI_DB_mysqli_driver extends CI_DB {
.'ELSE '.$k.' END, ';
}
- $where = ($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index b74c775b2..f29ea5ade 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQLi Forge Class
@@ -34,165 +35,178 @@
*/
class CI_DB_mysqli_forge extends CI_DB_forge {
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s';
/**
- * Process Fields
+ * CREATE TABLE keys flag
*
- * @param mixed the fields
- * @return string
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
*/
- protected function _process_fields($fields)
- {
- $current_field_count = 0;
- $sql = '';
-
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field);
-
- empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
-
- if ( ! empty($attributes['TYPE']))
- {
- $sql .= ' '.$attributes['TYPE'];
-
- if ( ! empty($attributes['CONSTRAINT']))
- {
- switch (strtolower($attributes['TYPE']))
- {
- case 'decimal':
- case 'float':
- case 'numeric':
- $sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
- break;
- case 'enum':
- case 'set':
- $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
- break;
- default:
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
- }
- }
+ protected $_create_table_keys = TRUE;
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT',
+ 'SMALLINT',
+ 'MEDIUMINT',
+ 'INT',
+ 'INTEGER',
+ 'BIGINT',
+ 'REAL',
+ 'DOUBLE',
+ 'DOUBLE PRECISION',
+ 'FLOAT',
+ 'DECIMAL',
+ 'NUMERIC'
+ );
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ // --------------------------------------------------------------------
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
- return $sql;
+ $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat;
}
// --------------------------------------------------------------------
/**
- * Create Table
+ * ALTER TABLE
*
- * @param string the table name
- * @param mixed the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _alter_table($alter_type, $table, $field)
{
- $sql = 'CREATE TABLE ';
-
- if ($if_not_exists === TRUE)
- {
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
-
- if (count($primary_keys) > 0)
+ if ($alter_type === 'DROP')
{
- $key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
- $sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+ return parent::_alter_table($alter_type, $table, $field);
}
- if (is_array($keys) && count($keys) > 0)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- foreach ($keys as $key)
+ if ($field[$i]['_literal'] !== FALSE)
{
- if (is_array($key))
+ $field[$i] = ($alter_type === 'ADD')
+ ? "\n\tADD ".$field[$i]['_literal']
+ : "\n\tMODIFY ".$field[$i]['_literal'];
+ }
+ else
+ {
+ if ($alter_type === 'ADD')
{
- $key_name = $this->db->escape_identifiers(implode('_', $key));
- $key = $this->db->escape_identifiers($key);
+ $field[$i]['_literal'] = "\n\tADD ";
}
else
{
- $key_name = $this->db->escape_identifiers($key);
- $key = array($key_name);
+ $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE ";
}
- $sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')';
+ $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]);
}
}
- return $sql."\n) DEFAULT CHARACTER SET ".$this->db->char_set.' COLLATE '.$this->db->dbcollat.';';
+ return array($sql.implode(',', $field));
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Process column
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ $extra_clause = isset($field['after'])
+ ? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
+
+ if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
+ {
+ $extra_clause = ' FIRST';
+ }
+
+ return $this->db->escape_identifiers($field['name'])
+ .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['null']
+ .$field['default']
+ .$field['auto_increment']
+ .$field['unique']
+ .$extra_clause;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process indexes
*
- * @param string the ALTER type (ADD, DROP, CHANGE)
- * @param string the column name
- * @param array fields
- * @param string the field after which we should add the new field
+ * @param string $table (ignored)
* @return string
*/
- protected function _alter_table($alter_type, $table, $fields, $after_field = '')
+ protected function _process_indexes($table)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
+ $sql = '';
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
{
- return $sql.$this->db->escape_identifiers($fields);
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
}
- return $sql.$this->_process_fields($fields)
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ $this->keys = array();
+
+ return $sql;
}
}
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index c1ec4da76..ac0f1a8d1 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQLi Result Class
@@ -101,7 +102,7 @@ class CI_DB_mysqli_result extends CI_DB_result {
$retval[$i]->type = $field_data[$i]->type;
$retval[$i]->max_length = $field_data[$i]->max_length;
$retval[$i]->primary_key = (int) ($field_data[$i]->flags & 2);
- $retval[$i]->default = '';
+ $retval[$i]->default = $field_data[$i]->def;
}
return $retval;
@@ -130,11 +131,12 @@ class CI_DB_mysqli_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return $this->result_id->data_seek($n);
}
@@ -160,7 +162,7 @@ class CI_DB_mysqli_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php
index 5d2bdbce0..345691e84 100644
--- a/system/database/drivers/mysqli/mysqli_utility.php
+++ b/system/database/drivers/mysqli/mysqli_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQLi Utility Class
@@ -34,14 +35,33 @@
*/
class CI_DB_mysqli_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'SHOW DATABASES';
+
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = 'OPTIMIZE TABLE %s';
+
+ /**
+ * REPAIR TABLE statement
+ *
+ * @var string
+ */
protected $_repair_table = 'REPAIR TABLE %s';
+ // --------------------------------------------------------------------
+
/**
- * MySQLi Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 691247fee..706211a01 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* oci8 Database Adapter Class
@@ -49,36 +50,80 @@
*/
class CI_DB_oci8_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'oci8';
- // The character used for excaping
- protected $_escape_char = '"';
+ /**
+ * Statement ID
+ *
+ * @var resource
+ */
+ public $stmt_id;
+
+ /**
+ * Cursor ID
+ *
+ * @var resource
+ */
+ public $curs_id;
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ /**
+ * Commit mode flag
+ *
+ * @var int
+ */
+ public $commit_mode = OCI_COMMIT_ON_SUCCESS;
/**
- * 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.
+ * Limit used flag
+ *
+ * If we use LIMIT, we'll add a field that will
+ * throw off num_fields later.
+ *
+ * @var bool
*/
- protected $_count_string = 'SELECT COUNT(1) AS ';
- protected $_random_keyword = ' ASC'; // not currently supported
+ public $limit_used;
+
+ // --------------------------------------------------------------------
+ /**
+ * List of reserved identifiers
+ *
+ * Identifiers that must NOT be escaped.
+ *
+ * @var string[]
+ */
protected $_reserved_identifiers = array('*', 'rownum');
- // Set "auto commit" by default
- public $commit_mode = OCI_COMMIT_ON_SUCCESS;
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('ASC', 'ASC'); // not currently supported
- // need to track statement id and cursor id
- public $stmt_id;
- public $curs_id;
+ /**
+ * COUNT string
+ *
+ * @used-by CI_DB_driver::count_all()
+ * @used-by CI_DB_query_builder::count_all_results()
+ *
+ * @var string
+ */
+ protected $_count_string = 'SELECT COUNT(1) AS ';
- // if we use a limit, we will add a field that will
- // throw off num_fields later
- public $limit_used;
+ // --------------------------------------------------------------------
+ /**
+ * Class constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -195,9 +240,21 @@ class CI_DB_oci8_driver extends CI_DB {
*/
public function version()
{
- return isset($this->data_cache['version'])
- ? $this->data_cache['version']
- : $this->data_cache['version'] = oci_server_version($this->conn_id);
+ if (isset($this->data_cache['version']))
+ {
+ return $this->data_cache['version'];
+ }
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
+
+ if ( ! $this->conn_id OR ($version = oci_server_version($this->conn_id)) === FALSE)
+ {
+ return FALSE;
+ }
+
+ return $this->data_cache['version'] = $version;
}
// --------------------------------------------------------------------
@@ -205,7 +262,7 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -224,7 +281,7 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Generate a statement ID
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return void
*/
protected function _set_stmt_id($sql)
@@ -304,7 +361,7 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Bind parameters
*
- * @param array
+ * @param array $params
* @return void
*/
protected function _bind_params($params)
@@ -333,7 +390,7 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -406,8 +463,8 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -467,7 +524,7 @@ class CI_DB_oci8_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -490,27 +547,83 @@ class CI_DB_oci8_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
- return 'SELECT "COLUMN_NAME" FROM "all_tab_columns" WHERE "TABLE_NAME" = '.$this->escape($table);
+ if (strpos($table, '.') !== FALSE)
+ {
+ sscanf($table, '%[^.].%s', $owner, $table);
+ }
+ else
+ {
+ $owner = $this->username;
+ }
+
+ return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS
+ WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
+ AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
}
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT * FROM '.$this->protect_identifiers($table).' WHERE rownum = 1';
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+ elseif (strpos($table, '.') !== FALSE)
+ {
+ sscanf($table, '%[^.].%s', $owner, $table);
+ }
+ else
+ {
+ $owner = $this->username;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHAR_LENGTH, DATA_PRECISION, DATA_LENGTH, DATA_DEFAULT, NULLABLE
+ FROM ALL_TAB_COLUMNS
+ WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
+ AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+
+ $length = ($query[$i]->CHAR_LENGTH > 0)
+ ? $query[$i]->CHAR_LENGTH : $query[$i]->DATA_PRECISION;
+ if ($length === NULL)
+ {
+ $length = $query[$i]->DATA_LENGTH;
+ }
+ $retval[$i]->max_length = $length;
+
+ $default = $query[$i]->DATA_DEFAULT;
+ if ($default === NULL && $query[$i]->NULLABLE === 'N')
+ {
+ $default = '';
+ }
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -547,29 +660,13 @@ class CI_DB_oci8_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Insert_batch statement
+ * Insert batch statement
*
* Generates a platform-specific insert string from the supplied data
*
- * @param string the table name
- * @param array the insert keys
- * @param array the insert values
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
* @return string
*/
protected function _insert_batch($table, $keys, $values)
@@ -592,10 +689,10 @@ class CI_DB_oci8_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
@@ -610,40 +707,35 @@ class CI_DB_oci8_driver extends CI_DB {
*
* Generates a platform-specific delete string from the supplied data
*
- * @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
+ * @param string $table
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
- empty($limit) OR $conditions[] = 'rownum <= '.$limit;
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT
*
* Generates a platform-specific LIMIT clause
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
$this->limit_used = TRUE;
- return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit + 1).')'
- .($offset ? ' WHERE rnum >= '.($offset + 1): '');
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 92e8c02ed..a0efa95ea 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Oracle Forge Class
@@ -34,122 +35,96 @@
*/
class CI_DB_oci8_forge extends CI_DB_forge {
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
protected $_create_database = FALSE;
+
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
protected $_drop_database = FALSE;
- protected $_drop_table = 'DROP TABLE %s';
/**
- * Create Table
+ * DROP TABLE IF statement
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return string
+ * @var string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = 'CREATE TABLE ';
+ protected $_drop_table_if = FALSE;
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
- if ($if_not_exists === TRUE)
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'DROP')
{
- $sql .= 'IF NOT EXISTS ';
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+ elseif ($alter_type === 'CHANGE')
+ {
+ $alter_type = 'MODIFY';
}
- $sql .= $this->db->escape_identifiers($table).' (';
- $current_field_count = 0;
-
- foreach ($fields as $field => $attributes)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- // 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
+ if ($field[$i]['_literal'] !== FALSE)
{
- $sql .= "\n\t".$attributes;
+ $field[$i] = "\n\t".$field[$i]['_literal'];
}
else
{
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- if (isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE)
+ $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]);
+ if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name']))
{
- $sql .= ' UNSIGNED';
+ $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' '.$this->db->escape_identifiers($field[$i]['new_name']);
}
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= (isset($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? '' : ' NOT NULL';
-
- empty($attributes['CONSTRAINT']) OR ' CONSTRAINT '.$attributes['CONSTRAINT'];
- }
-
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
}
}
- if (count($primary_keys) > 0)
- {
- $sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
- }
+ $sql .= ' '.$alter_type.' ';
+ $sql .= (count($field) === 1)
+ ? $field[0]
+ : '('.implode(',', $field).')';
- if (is_array($keys) && count($keys) > 0)
- {
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')';
- }
- }
-
- return $sql."\n)";
+ // RENAME COLUMN must be executed after MODIFY
+ array_unshift($sqls, $sql);
+ return $sql;
}
// --------------------------------------------------------------------
/**
- * Alter table query
- *
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Field attribute AUTO_INCREMENT
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_auto_increment(&$attributes, &$field)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
- {
- return $sql;
- }
-
- return $sql.' '.$column_definition
- .($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
-
+ // Not supported - sequences and triggers must be used instead
}
}
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index a2b600e6c..84d46f82a 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* oci8 Result Class
@@ -37,15 +38,40 @@
*/
class CI_DB_oci8_result extends CI_DB_result {
+ /**
+ * Statement ID
+ *
+ * @var resource
+ */
public $stmt_id;
+
+ /**
+ * Cursor ID
+ *
+ * @var resource
+ */
public $curs_id;
+
+ /**
+ * Limit used flag
+ *
+ * @var bool
+ */
public $limit_used;
+
+ /**
+ * Commit mode flag
+ *
+ * @var int
+ */
public $commit_mode;
+ // --------------------------------------------------------------------
+
/**
- * Constructor
+ * Class constructor
*
- * @param object
+ * @param object &$driver_object
* @return void
*/
public function __construct(&$driver_object)
@@ -157,7 +183,7 @@ class CI_DB_oci8_result extends CI_DB_result {
protected function _fetch_assoc()
{
$id = ($this->curs_id) ? $this->curs_id : $this->stmt_id;
- return oci_fetch_assoc($id);
+ return @oci_fetch_assoc($id);
}
// --------------------------------------------------------------------
@@ -167,7 +193,7 @@ class CI_DB_oci8_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
@@ -190,63 +216,6 @@ class CI_DB_oci8_result extends CI_DB_result {
return $class_name;
}
- // --------------------------------------------------------------------
-
- /**
- * 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.
- *
- * Oracle's PHP extension doesn't have an easy way of doing this
- * and the only workaround is to (re)execute the statement or cursor
- * in order to go to the first (zero) index of the result set.
- * Then, we would need to "dummy" fetch ($n - 1) rows to get to the
- * right one.
- *
- * This is as ridiculous as it sounds and it's the reason why every
- * other method that is fetching data tries to use an already "cached"
- * result set. Keeping this just in case it becomes needed at
- * some point in the future, but it will only work for resetting the
- * pointer to zero.
- *
- * @return bool
- */
- protected function _data_seek()
- {
- /* The PHP manual says that if OCI_NO_AUTO_COMMIT mode
- * is used, and oci_rollback() and/or oci_commit() are
- * not subsequently called - this will cause an unnecessary
- * rollback to be triggered at the end of the script execution.
- *
- * Therefore we'll try to avoid using that mode flag
- * if we're not currently in the middle of a transaction.
- */
- if ($this->commit_mode !== OCI_COMMIT_ON_SUCCESS)
- {
- $result = @oci_execute($this->stmt_id, $this->commit_mode);
- }
- else
- {
- $result = @oci_execute($this->stmt_id);
- }
-
- if ($result && $this->curs_id)
- {
- if ($this->commit_mode !== OCI_COMMIT_ON_SUCCESS)
- {
- return @oci_execute($this->curs_id, $this->commit_mode);
- }
- else
- {
- return @oci_execute($this->curs_id);
- }
- }
-
- return $result;
- }
-
}
/* End of file oci8_result.php */
diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php
index 0183eda26..d15537fdf 100644
--- a/system/database/drivers/oci8/oci8_utility.php
+++ b/system/database/drivers/oci8/oci8_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Oracle Utility Class
@@ -34,18 +35,23 @@
*/
class CI_DB_oci8_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'SELECT username FROM dba_users'; // Schemas are actual usernames
/**
- * Oracle Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 8f0a474b0..29b2281cc 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* ODBC Database Adapter Class
@@ -40,23 +41,57 @@
*/
class CI_DB_odbc_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'odbc';
- // the character used to excape - not necessary for ODBC
+ /**
+ * Database schema
+ *
+ * @var string
+ */
+ public $schema = 'public';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Identifier escape character
+ *
+ * Must be empty for ODBC.
+ *
+ * @var string
+ */
protected $_escape_char = '';
- // clause and character used for LIKE escape sequences
+ /**
+ * ESCAPE statement string
+ *
+ * @var string
+ */
protected $_like_escape_str = " {escape '%s'} ";
- protected $_like_escape_chr = '!';
- protected $_random_keyword;
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RND()', 'RND(%d)');
+
+ // --------------------------------------------------------------------
+ /**
+ * Class constructor
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
- $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
-
// Legacy support for DSN in the hostname field
if (empty($this->dsn))
{
@@ -64,6 +99,8 @@ class CI_DB_odbc_driver extends CI_DB {
}
}
+ // --------------------------------------------------------------------
+
/**
* Non-persistent database connection
*
@@ -91,7 +128,7 @@ class CI_DB_odbc_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -104,6 +141,7 @@ class CI_DB_odbc_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -167,8 +205,8 @@ class CI_DB_odbc_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -217,7 +255,7 @@ class CI_DB_odbc_driver extends CI_DB {
*/
public function insert_id()
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
@@ -227,17 +265,17 @@ class CI_DB_odbc_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
- $sql = 'SHOW TABLES FROM '.$this->database;
+ $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'";
if ($prefix_limit !== FALSE && $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 $sql." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
return $sql;
@@ -250,7 +288,7 @@ class CI_DB_odbc_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -265,7 +303,7 @@ class CI_DB_odbc_driver extends CI_DB {
*
* Generates a platform-specific query so that the column data can be retrieved
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _field_data($table)
@@ -291,17 +329,19 @@ class CI_DB_odbc_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
+ * Update statement
*
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * Generates a platform-specific update string from the supplied data
*
- * @param array
+ * @param string $table
+ * @param array $values
* @return string
*/
- protected function _from_tables($tables)
+ protected function _update($table, $values)
{
- return is_array($tables) ? implode(', ', $tables) : $tables;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -311,10 +351,10 @@ class CI_DB_odbc_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
@@ -325,6 +365,22 @@ class CI_DB_odbc_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index b074c5884..fb16ca5cf 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* ODBC Forge Class
@@ -34,125 +35,39 @@
*/
class CI_DB_odbc_forge extends CI_DB_forge {
- protected $_drop_database = 'DROP DATABASE %s';
- protected $_drop_table = 'DROP TABLE %s';
-
/**
- * Create Table
+ * CREATE TABLE IF statement
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @var string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = 'CREATE TABLE ';
-
- if ($if_not_exists === TRUE)
- {
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' (';
- $current_field_count = 0;
-
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
-
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
-
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ protected $_create_table_if = FALSE;
- if (count($primary_keys) > 0)
- {
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->escape_identifiers($primary_keys)).')';
- }
-
- if (is_array($keys) && count($keys) > 0)
- {
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
- }
- }
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = FALSE;
- return $sql."\n)";
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute AUTO_INCREMENT
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
- *
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_auto_increment(&$attributes, &$field)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
- {
- return $sql;
- }
-
- return $sql.' '.$column_definition
- .($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ // Not supported (in most databases at least)
}
}
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index 48dc48dd9..2c50c255b 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* ODBC Result Class
@@ -165,7 +166,7 @@ class CI_DB_odbc_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
@@ -198,11 +199,11 @@ if ( ! function_exists('odbc_fetch_array'))
* Emulates the native odbc_fetch_array() function when
* it is not available (odbc_fetch_array() requires unixODBC)
*
- * @param resource
- * @param int
+ * @param resource &$result
+ * @param int $rownumber
* @return array
*/
- function odbc_fetch_array(& $result, $rownumber = 1)
+ function odbc_fetch_array(&$result, $rownumber = 1)
{
$rs = array();
if ( ! odbc_fetch_into($result, $rs, $rownumber))
@@ -231,11 +232,11 @@ if ( ! function_exists('odbc_fetch_object'))
* Emulates the native odbc_fetch_object() function when
* it is not available.
*
- * @param resource
- * @param int
+ * @param resource &$result
+ * @param int $rownumber
* @return object
*/
- function odbc_fetch_object(& $result, $rownumber = 1)
+ function odbc_fetch_object(&$result, $rownumber = 1)
{
$rs = array();
if ( ! odbc_fetch_into($result, $rs, $rownumber))
diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php
index 224d48d2b..908674a9d 100644
--- a/system/database/drivers/odbc/odbc_utility.php
+++ b/system/database/drivers/odbc/odbc_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* ODBC Utility Class
@@ -34,18 +35,16 @@
*/
class CI_DB_odbc_utility extends CI_DB_utility {
- protected $_list_databases = FALSE;
-
/**
- * ODBC Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 38a9fec80..d2dfa8bf0 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PDO Database Adapter Class
@@ -40,21 +41,37 @@
*/
class CI_DB_pdo_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'pdo';
- // the character used to excape - not necessary for PDO
- protected $_escape_char = '';
-
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
- protected $_random_keyword;
+ /**
+ * Transaction enabled flag
+ *
+ * @var bool
+ */
+ public $trans_enabled = FALSE;
- // need to track the pdo driver and options
- public $pdodriver;
+ /**
+ * PDO Options
+ *
+ * @var array
+ */
public $options = array();
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Validates the DSN string and/or detects the subdriver.
+ *
+ * @param array $params
+ * @return void
+ */
public function __construct($params)
{
parent::__construct($params);
@@ -63,172 +80,54 @@ class CI_DB_pdo_driver extends CI_DB {
{
// 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);
+ $this->subdriver = $match[1];
+ return;
}
- else
+ // Legacy support for DSN specified in the hostname field
+ elseif (preg_match('/([^;]+):/', $this->hostname, $match) && count($match) === 2)
{
- // Try to build a complete DSN string from params
- $this->_connect_string($params);
+ $this->dsn = $this->hostname;
+ $this->hostname = NULL;
+ $this->subdriver = $match[1];
+ return;
}
-
- // clause and character used for LIKE escape sequences
- // this one depends on the driver being used
- if ($this->pdodriver === 'mysql')
+ elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE))
{
- $this->_escape_char = '`';
- $this->_like_escape_str = '';
- $this->_like_escape_chr = '\\';
+ $this->subdriver = 'dblib';
}
- elseif ($this->pdodriver === 'odbc')
+ elseif ($this->subdriver === '4D')
{
- $this->_like_escape_str = " {escape '%s'} ";
+ $this->subdriver = '4d';
}
- elseif ( ! in_array($this->pdodriver, array('sqlsrv', 'mssql', 'dblib', 'sybase')))
+ elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', 'sqlite', 'sqlsrv'), TRUE))
{
- $this->_escape_char = '"';
- }
-
- $this->trans_enabled = FALSE;
- $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
- }
+ log_message('error', 'PDO: Invalid or non-existent subdriver');
- /**
- * Connection String
- *
- * @param array
- * @return void
- */
- protected function _connect_string($params)
- {
- 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))
+ if ($this->db_debug)
{
- $this->dsn .= rtrim($this->hostname, ';').';';
+ show_error('Invalid or non-existent PDO subdriver');
}
}
- else
- {
- // Invalid DSN, display an error
- if ( ! array_key_exists('pdodriver', $params))
- {
- show_error('Invalid DB Connection String for PDO');
- }
- // 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.';';
- }
-
- // 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.';';
- }
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Non-persistent database connection
- *
- * @return object
- */
- public function db_connect()
- {
- return $this->_pdo_connect();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Persistent database connection
- *
- * @return object
- */
- public function db_pconnect()
- {
- return $this->_pdo_connect(TRUE);
+ $this->dsn = NULL;
}
// --------------------------------------------------------------------
/**
- * PDO connection
+ * Database connection
*
- * @param bool
+ * @param bool $persistent
* @return object
*/
- protected function _pdo_connect($persistent = FALSE)
+ public function db_connect($persistent = FALSE)
{
- $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->pdodriver === '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."'" : '');
- }
+ $this->options[PDO::ATTR_PERSISTENT] = $persistent;
// Connecting...
try
{
- return new PDO($this->dsn, $this->username, $this->password, $this->options);
+ return @new PDO($this->dsn, $this->username, $this->password, $this->options);
}
catch (PDOException $e)
{
@@ -244,6 +143,18 @@ class CI_DB_pdo_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Persistent database connection
+ *
+ * @return object
+ */
+ public function db_pconnect()
+ {
+ return $this->db_connect(TRUE);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Database version number
*
* @return string
@@ -254,6 +165,10 @@ class CI_DB_pdo_driver extends CI_DB {
{
return $this->data_cache['version'];
}
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
// Not all subdrivers support the getAttribute() method
try
@@ -271,7 +186,7 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql SQL query
* @return mixed
*/
protected function _execute($sql)
@@ -284,6 +199,7 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -343,8 +259,8 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -363,7 +279,7 @@ class CI_DB_pdo_driver extends CI_DB {
$str = $this->conn_id->quote($str);
// If there are duplicated quotes, trim them away
- if (strpos($str, "'") === 0)
+ if ($str[0] === "'")
{
$str = substr($str, 1, -1);
}
@@ -396,100 +312,27 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Insert ID
*
- * @param string
+ * @param string $name
* @return int
*/
public function insert_id($name = NULL)
{
- if ($this->pdodriver === 'pgsql' && $name === NULL && $this->version() >= '8.1')
- {
- $query = $this->query('SELECT LASTVAL() AS ins_id');
- $query = $query->row();
- return $query->ins_id;
- }
-
return $this->conn_id->lastInsertId($name);
}
// --------------------------------------------------------------------
/**
- * Show table query
- *
- * Generates a platform-specific query string so that the table names can be fetched
- *
- * @param bool
- * @return string
- */
- protected function _list_tables($prefix_limit = FALSE)
- {
- 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 !== '')
- {
- return FALSE;
- }
-
- return $sql;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Show column query
- *
- * Generates a platform-specific query string so that the column names can be fetched
- *
- * @param string the table name
- * @return string
- */
- protected function _list_columns($table = '')
- {
- return 'SHOW COLUMNS FROM '.$this->escape_identifiers($table);
- }
-
- // --------------------------------------------------------------------
-
- /**
* Field data query
*
* Generates a platform-specific query so that the column data can be retrieved
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _field_data($table)
{
- 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).')';
- }
-
- return 'SELECT TOP 1 FROM '.$this->escape_identifiers($table);
+ return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
}
// --------------------------------------------------------------------
@@ -528,16 +371,14 @@ class CI_DB_pdo_driver extends CI_DB {
*
* Generates a platform-specific batch update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
- $ids = array();
- $where = ($where !== '' && count($where) >=1) ? implode(" ", $where).' AND ' : '';
-
+ $ids = array();
foreach ($values as $key => $val)
{
$ids[] = $val[$index];
@@ -546,14 +387,12 @@ class CI_DB_pdo_driver extends CI_DB {
{
if ($field !== $index)
{
- $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
+ $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
}
}
}
- $sql = 'UPDATE '.$table.' SET ';
$cases = '';
-
foreach ($final as $k => $v)
{
$cases .= $k.' = CASE '."\n";
@@ -566,10 +405,9 @@ class CI_DB_pdo_driver extends CI_DB {
$cases .= 'ELSE '.$k.' END, ';
}
- $sql .= substr($cases, 0, -2);
- $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
- return $sql;
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -579,37 +417,15 @@ class CI_DB_pdo_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
{
- return 'DELETE FROM '.$table;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Limit string
- *
- * Generates a platform-specific LIMIT clause
- *
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
- * @return string
- */
- protected function _limit($sql, $limit, $offset)
- {
- if ($this->pdodriver === 'pgsql')
- {
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
- }
-
- return $sql.' LIMIT '.($offset ? $offset.', ' : '').$limit;
+ return 'TRUNCATE TABLE '.$table;
}
}
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index 02ceb74fe..130d3667e 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PDO Forge Class
@@ -34,134 +35,19 @@
*/
class CI_DB_pdo_forge extends CI_DB_forge {
- protected $_drop_database = 'DROP DATABASE %s';
- protected $_drop_table = 'DROP TABLE %s';
-
/**
- * Create Table
+ * CREATE TABLE IF statement
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @var string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = 'CREATE TABLE ';
-
- if ($if_not_exists === TRUE)
- {
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' (';
- $current_field_count = 0;
-
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
- $numeric = array('SERIAL', 'INTEGER');
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- if ( ! empty($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 ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
-
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
-
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
-
- if (count($primary_keys) > 0)
- {
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
- }
-
- if (is_array($keys) && count($keys) > 0)
- {
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
- }
- }
-
- return $sql."\n)";
- }
-
- // --------------------------------------------------------------------
+ protected $_create_table_if = 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(),
+ * DROP TABLE IF statement
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @var string
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
- {
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
- {
- return $sql;
- }
-
- return $sql .' '.$column_definition
- .($default_value !== '' ? " DEFAULT '".$default_value."'" : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
- }
+ protected $_drop_table_if = FALSE;
}
diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php
index 444406986..25cf87be8 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PDO Result Class
@@ -108,61 +109,28 @@ class CI_DB_pdo_result extends CI_DB_result {
*/
public function field_data()
{
- $data = array();
-
try
{
- 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
+ $retval = array();
+
+ for ($i = 0, $c = $this->num_fields(); $i < $c; $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;
- }
+ $field = $this->result_id->getColumnMeta($i);
+
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $field['name'];
+ $retval[$i]->type = $field['native_type'];
+ $retval[$i]->max_length = ($field['len'] > 0) ? $field['len'] : NULL;
+ $retval[$i]->primary_key = (int) ( ! empty($field['flags']) && in_array('primary_key', $field['flags'], TRUE));
}
- return $data;
+ return $retval;
}
catch (Exception $e)
{
if ($this->db->db_debug)
{
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
return FALSE;
@@ -205,7 +173,7 @@ class CI_DB_pdo_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php
index 930842118..86f2b120a 100644
--- a/system/database/drivers/pdo/pdo_utility.php
+++ b/system/database/drivers/pdo/pdo_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PDO Utility Class
@@ -34,18 +35,16 @@
*/
class CI_DB_pdo_utility extends CI_DB_utility {
- protected $_list_databases = FALSE;
-
/**
- * PDO Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/pdo/subdrivers/index.html b/system/database/drivers/pdo/subdrivers/index.html
new file mode 100644
index 000000000..c942a79ce
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
new file mode 100644
index 000000000..6ebd92a9b
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO 4D Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = '4d';
+
+ /**
+ * Identifier escape character
+ *
+ * @var string[]
+ */
+ protected $_escape_char = array('[', ']');
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = '4D:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ empty($this->port) OR $this->dsn .= ';port='.$this->port;
+ empty($this->database) OR $this->dsn .= ';dbname='.$this->database;
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ }
+ elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 3) === FALSE)
+ {
+ $this->dsn .= ';charset='.$this->char_set;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT '.$this->escape_identifiers('TABLE_NAME').' FROM '.$this->escape_identifiers('_USER_TABLES');
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ $sql .= ' WHERE '.$this->escape_identifiers('TABLE_NAME')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT '.$this->escape_identifiers('COLUMN_NAME').' FROM '.$this->escape_identifiers('_USER_COLUMNS')
+ .' WHERE '.$this->escape_identifiers('TABLE_NAME').' = '.$this->escape($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field data query
+ *
+ * Generates a platform-specific query so that the column data can be retrieved
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _field_data($table)
+ {
+ return 'SELECT * FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' LIMIT 1';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
+ }
+
+}
+
+/* End of file pdo_4d_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_4d_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php b/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php
new file mode 100644
index 000000000..231ad53a4
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO 4D Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_4d_forge extends CI_DB_4d_forge {
+
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
+ protected $_create_database = 'CREATE SCHEMA %s';
+
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
+ protected $_drop_database = 'DROP SCHEMA %s';
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
+
+ /**
+ * RENAME TABLE statement
+ *
+ * @var string
+ */
+ protected $_rename_table = FALSE;
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'INT16' => 'INT',
+ 'SMALLINT' => 'INT',
+ 'INT' => 'INT64',
+ 'INT32' => 'INT64'
+ );
+
+ /**
+ * DEFAULT value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_default = FALSE;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
+ {
+ return parent::_alter_table($alter_table, $table, $field);
+ }
+
+ // No method of modifying columns is supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type'].$field['length']
+ .$field['null']
+ .$field['unique']
+ .$field['auto_increment'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INTEGER':
+ $attributes['TYPE'] = 'INT';
+ return;
+ case 'BIGINT':
+ $attribites['TYPE'] = 'INT64';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute UNIQUE
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_unique(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+ {
+ $field['unique'] = ' UNIQUE';
+
+ // UNIQUE must be used with NOT NULL
+ $field['null'] = ' NOT NULL';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+ {
+ if (stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' AUTO_INCREMENT';
+ }
+ elseif (strcasecmp($field['type'], 'UUID') === 0)
+ {
+ $field['auto_increment'] = ' AUTO_GENERATE';
+ }
+ }
+ }
+
+}
+
+/* End of file pdo_4d_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_4d_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
new file mode 100644
index 000000000..7e703e7b5
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO CUBRID Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'cubrid';
+
+ /**
+ * Identifier escape character
+ *
+ * @var string
+ */
+ protected $_escape_char = '`';
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM(%d)');
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'cubrid:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ empty($this->port) OR $this->dsn .= ';port='.$this->port;
+ empty($this->database) OR $this->dsn .= ';dbname='.$this->database;
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SHOW TABLES';
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->Field;
+
+ sscanf($query[$i]->Type, '%[a-z](%d)',
+ $retval[$i]->type,
+ $retval[$i]->max_length
+ );
+
+ $retval[$i]->default = $query[$i]->Default;
+ $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update_Batch statement
+ *
+ * Generates a platform-specific batch update string from the supplied data
+ *
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
+ * @return string
+ */
+ protected function _update_batch($table, $values, $index)
+ {
+ $ids = array();
+ foreach ($values as $key => $val)
+ {
+ $ids[] = $val[$index];
+
+ foreach (array_keys($val) as $field)
+ {
+ if ($field !== $index)
+ {
+ $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
+ }
+ }
+ }
+
+ $cases = '';
+ foreach ($final as $k => $v)
+ {
+ $cases .= $k." = CASE \n"
+ .implode("\n", $v)."\n"
+ .'ELSE '.$k.' END), ';
+ }
+
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'TRUNCATE '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
+}
+
+/* End of file pdo_cubrid_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php
new file mode 100644
index 000000000..ebf4b15d6
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php
@@ -0,0 +1,219 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO CUBRID Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_cubrid_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
+ protected $_create_database = FALSE;
+
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
+ protected $_drop_database = FALSE;
+
+ /**
+ * CREATE TABLE keys flag
+ *
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
+ */
+ protected $_create_table_keys = TRUE;
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SHORT' => 'INTEGER',
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INTEGER' => 'BIGINT',
+ 'BIGINT' => 'NUMERIC',
+ 'FLOAT' => 'DOUBLE',
+ 'REAL' => 'DOUBLE'
+ );
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ $sqls[] = $sql.' CHANGE '.$field[$i]['_literal'];
+ }
+ else
+ {
+ $alter_type = empty($field[$i]['new_name']) ? ' MODIFY ' : ' CHANGE ';
+ $sqls[] = $sql.$alter_type.$this->_process_column($field[$i]);
+ }
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ $extra_clause = isset($field['after'])
+ ? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
+
+ if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
+ {
+ $extra_clause = ' FIRST';
+ }
+
+ return $this->db->escape_identifiers($field['name'])
+ .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['null']
+ .$field['default']
+ .$field['auto_increment']
+ .$field['unique']
+ .$extra_clause;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process indexes
+ *
+ * @param string $table (ignored)
+ * @return string
+ */
+ protected function _process_indexes($table)
+ {
+ $sql = '';
+
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
+ {
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
+ }
+
+ $this->keys = array();
+
+ return $sql;
+ }
+
+}
+
+/* End of file pdo_cubrid_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
new file mode 100644
index 000000000..cf049b61d
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
@@ -0,0 +1,329 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO DBLIB Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'dblib';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('NEWID()', 'RAND(%d)');
+
+ /**
+ * Quoted identifier flag
+ *
+ * Whether to use SQL-92 standard quoted identifier
+ * (double quotes) or brackets for identifier escaping.
+ *
+ * @var bool
+ */
+ protected $_quoted_identifier;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = $params['subdriver'].':host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ if ( ! empty($this->port))
+ {
+ $this->dsn .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
+ }
+
+ empty($this->database) OR $this->dsn .= ';dbname='.$this->database;
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ empty($this->appname) OR $this->dsn .= ';appname='.$this->appname;
+ }
+ else
+ {
+ if ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE)
+ {
+ $this->dsn .= ';charset='.$this->char_set;
+ }
+
+ $this->subdriver = 'dblib';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database connection
+ *
+ * @param bool $persistent
+ * @return object
+ */
+ public function db_connect($persistent = FALSE)
+ {
+ $this->conn_id = parent::db_connect($persistent);
+
+ if ( ! is_object($this->conn_id))
+ {
+ return $this->conn_id;
+ }
+
+ // Determine how identifiers are escaped
+ $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+ $query = $query->row_array();
+ $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
+ $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+ return $this->conn_id;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ return 'SELECT '.$this->escape_identifiers('name')
+ .' FROM '.$this->escape_identifiers('sysobjects')
+ .' WHERE '.$this->escape_identifiers('type')." = 'U'";
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql.' ORDER BY '.$this->escape_identifiers('name');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+ $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
+
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ $limit = $this->qb_offset + $this->qb_limit;
+
+ // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
+ // however an ORDER BY clause is required for it to work
+ if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
+ {
+ $orderby = $this->_compile_order_by();
+
+ // We have to strip the ORDER BY clause
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
+
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
+ }
+
+ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert batch statement
+ *
+ * Generates a platform-specific insert string from the supplied data.
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string|bool
+ */
+ protected function _insert_batch($table, $keys, $values)
+ {
+ // Multiple-value inserts are only supported as of SQL Server 2008
+ if (version_compare($this->version(), '10', '>='))
+ {
+ return parent::_insert_batch($table, $keys, $values);
+ }
+
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+}
+
+/* End of file pdo_dblib_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php
new file mode 100644
index 000000000..236e1cce2
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO DBLIB Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_dblib_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE";
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE";
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT' => 'SMALLINT',
+ 'SMALLINT' => 'INT',
+ 'INT' => 'BIGINT',
+ 'REAL' => 'FLOAT'
+ );
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN ';
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ $sqls[] = $sql.$this->_process_column($field[$i]);
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INTEGER':
+ $attributes['TYPE'] = 'INT';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' IDENTITY(1,1)';
+ }
+ }
+
+}
+
+/* End of file pdo_dblib_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
new file mode 100644
index 000000000..adac03880
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
@@ -0,0 +1,260 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Firebird Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'firebird';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RAND()', 'RAND()');
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'firebird:';
+
+ if ( ! empty($this->database))
+ {
+ $this->dsn .= 'dbname='.$this->database;
+ }
+ elseif ( ! empty($this->hostname))
+ {
+ $this->dsn .= 'dbname='.$this->hostname;
+ }
+
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ empty($this->role) OR $this->dsn .= ';role='.$this->role;
+ }
+ elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 9) === FALSE)
+ {
+ $this->dsn .= ';charset='.$this->char_set;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\'';
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name",
+ CASE "fields"."RDB$FIELD_TYPE"
+ WHEN 7 THEN \'SMALLINT\'
+ WHEN 8 THEN \'INTEGER\'
+ WHEN 9 THEN \'QUAD\'
+ WHEN 10 THEN \'FLOAT\'
+ WHEN 11 THEN \'DFLOAT\'
+ WHEN 12 THEN \'DATE\'
+ WHEN 13 THEN \'TIME\'
+ WHEN 14 THEN \'CHAR\'
+ WHEN 16 THEN \'INT64\'
+ WHEN 27 THEN \'DOUBLE\'
+ WHEN 35 THEN \'TIMESTAMP\'
+ WHEN 37 THEN \'VARCHAR\'
+ WHEN 40 THEN \'CSTRING\'
+ WHEN 261 THEN \'BLOB\'
+ ELSE NULL
+ END AS "type",
+ "fields"."RDB$FIELD_LENGTH" AS "max_length",
+ "rfields"."RDB$DEFAULT_VALUE" AS "default"
+ FROM "RDB$RELATION_FIELDS" "rfields"
+ JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME"
+ WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).'
+ ORDER BY "rfields"."RDB$FIELD_POSITION"';
+
+ return (($query = $this->query($sql)) !== FALSE)
+ ? $query->result_object()
+ : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'DELETE FROM '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ // Limit clause depends on if Interbase or Firebird
+ if (stripos($this->version(), 'firebird') !== FALSE)
+ {
+ $select = 'FIRST '.$this->qb_limit
+ .($this->qb_offset > 0 ? ' SKIP '.$this->qb_offset : '');
+ }
+ else
+ {
+ $select = 'ROWS '
+ .($this->qb_offset > 0 ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
+ }
+
+ return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
+ }
+
+}
+
+/* End of file pdo_firebird_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php
new file mode 100644
index 000000000..7b86de97f
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Firebird Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_firebird_forge extends CI_DB_pdo_forge {
+
+ /**
+ * RENAME TABLE statement
+ *
+ * @var string
+ */
+ protected $_rename_table = FALSE;
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SMALLINT' => 'INTEGER',
+ 'INTEGER' => 'INT64',
+ 'FLOAT' => 'DOUBLE PRECISION'
+ );
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Create database
+ *
+ * @param string $db_name
+ * @return string
+ */
+ public function create_database($db_name)
+ {
+ // Firebird databases are flat files, so a path is required
+
+ // Hostname is needed for remote access
+ empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name;
+
+ return parent::create_database('"'.$db_name.'"');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Drop database
+ *
+ * @param string $db_name (ignored)
+ * @return bool
+ */
+ public function drop_database($db_name = '')
+ {
+ if ( ! ibase_drop_db($this->conn_id))
+ {
+ return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
+ }
+ elseif ( ! empty($this->db->data_cache['db_names']))
+ {
+ $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+ if ($key !== FALSE)
+ {
+ unset($this->db->data_cache['db_names'][$key]);
+ }
+ }
+
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ return FALSE;
+ }
+
+ if (isset($field[$i]['type']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TYPE '.$field[$i]['type'].$field[$i]['length'];
+ }
+
+ if ( ! empty($field[$i]['default']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' SET DEFAULT '.$field[$i]['default'];
+ }
+
+ if (isset($field[$i]['null']))
+ {
+ $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = '
+ .($field[$i]['null'] === TRUE ? 'NULL' : '1')
+ .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name'])
+ .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table);
+ }
+
+ if ( ! empty($field[$i]['new_name']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TO '.$this->db->escape_identifiers($field[$i]['new_name']);
+ }
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type'].$field['length']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INT':
+ $attributes['TYPE'] = 'INTEGER';
+ return;
+ case 'BIGINT':
+ $attributes['TYPE'] = 'INT64';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ // Not supported
+ }
+
+}
+
+/* End of file pdo_firebird_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
new file mode 100644
index 000000000..2ef97cd6e
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO IBM DB2 Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_ibm_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'ibm';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'ibm:';
+
+ // Pre-defined DSN
+ if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT))
+ {
+ if (isset($this->DSN))
+ {
+ $this->dsn .= 'DSN='.$this->DSN;
+ }
+ elseif ( ! empty($this->database))
+ {
+ $this->dsn .= 'DSN='.$this->database;
+ }
+
+ return;
+ }
+
+ $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';';
+
+ if (isset($this->DATABASE))
+ {
+ $this->dsn .= 'DATABASE='.$this->DATABASE.';';
+ }
+ elseif ( ! empty($this->database))
+ {
+ $this->dsn .= 'DATABASE='.$this->database.';';
+ }
+
+ if (isset($this->HOSTNAME))
+ {
+ $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';';
+ }
+ else
+ {
+ $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';');
+ }
+
+ if (isset($this->PORT))
+ {
+ $this->dsn .= 'PORT='.$this->port.';';
+ }
+ elseif ( ! empty($this->port))
+ {
+ $this->dsn .= ';PORT='.$this->port.';';
+ }
+
+ $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;');
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "tabname" FROM "syscat"."tables"
+ WHERE "type" = \'T\' AND LOWER("tabschema") = '.$this->escape(strtolower($this->database));
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ $sql .= ' AND "tabname" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return array
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT "colname" FROM "syscat"."columns"
+ WHERE LOWER("tabschema") = '.$this->escape(strtolower($this->database)).'
+ AND LOWER("tabname") = '.$this->escape(strtolower($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ $sql = 'SELECT "colname" AS "name", "typename" AS "type", "default" AS "default", "length" AS "max_length",
+ CASE "keyseq" WHEN NULL THEN 0 ELSE 1 END AS "primary_key"
+ FROM "syscat"."columns"
+ WHERE LOWER("tabschema") = '.$this->escape(strtolower($this->database)).'
+ AND LOWER("tabname") = '.$this->escape(strtolower($table)).'
+ ORDER BY "colno"';
+
+ return (($query = $this->query($sql)) !== FALSE)
+ ? $query->result_object()
+ : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ $sql .= ' FETCH FIRST '.($this->qb_limit + $this->qb_offset).' ROWS ONLY';
+
+ return ($this->qb_offset)
+ ? 'SELECT * FROM ('.$sql.') WHERE rownum > '.$this->qb_offset
+ : $sql;
+ }
+
+}
+
+/* End of file pdo_ibm_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php
new file mode 100644
index 000000000..f095c717a
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO IBM DB2 Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_ibm_forge extends CI_DB_pdo_forge {
+
+ /**
+ * RENAME TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_rename_table = 'RENAME TABLE %s TO %s';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INTEGER' => 'BIGINT'
+ );
+
+ /**
+ * DEFAULT value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_default = FALSE;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'CHANGE')
+ {
+ $alter_type = 'MODIFY';
+ }
+
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute UNIQUE
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_unique(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+ {
+ $field['unique'] = ' UNIQUE';
+
+ // UNIQUE must be used with NOT NULL
+ $field['null'] = ' NOT NULL';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ // Not supported
+ }
+
+}
+
+/* End of file pdo_ibm_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
new file mode 100644
index 000000000..cfb474eec
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
@@ -0,0 +1,301 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Informix Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'informix';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('ASC', 'ASC'); // Currently not supported
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'informix:';
+
+ // Pre-defined DSN
+ if (empty($this->hostname) && empty($this->host) && empty($this->port) && empty($this->service))
+ {
+ if (isset($this->DSN))
+ {
+ $this->dsn .= 'DSN='.$this->DSN;
+ }
+ elseif ( ! empty($this->database))
+ {
+ $this->dsn .= 'DSN='.$this->database;
+ }
+
+ return;
+ }
+
+ if (isset($this->host))
+ {
+ $this->dsn .= 'host='.$this->host;
+ }
+ else
+ {
+ $this->dsn .= 'host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+ }
+
+ if (isset($this->service))
+ {
+ $this->dsn .= '; service='.$this->service;
+ }
+ elseif ( ! empty($this->port))
+ {
+ $this->dsn .= '; service='.$this->port;
+ }
+
+ empty($this->database) OR $this->dsn .= '; database='.$this->database;
+ empty($this->server) OR $this->dsn .= '; server='.$this->server;
+
+ $this->dsn .= '; protocol='.(isset($this->protocol) ? $this->protocol : 'onsoctcp')
+ .'; EnableScrollableCursors=1';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "tabname" FROM "systables"
+ WHERE "tabid" > 99 AND "tabtype" = \'T\' AND LOWER("owner") = '.$this->escape(strtolower($this->username));
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ $sql .= ' AND "tabname" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ if (strpos($table, '.') !== FALSE)
+ {
+ sscanf($table, '%[^.].%s', $owner, $table);
+ }
+ else
+ {
+ $owner = $this->username;
+ }
+
+ return 'SELECT "colname" FROM "systables", "syscolumns"
+ WHERE "systables"."tabid" = "syscolumns"."tabid"
+ AND "systables"."tabtype" = \'T\'
+ AND LOWER("systables"."owner") = '.$this->escape(strtolower($owner)).'
+ AND LOWER("systables"."tabname") = '.$this->escape(strtolower($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ $sql = 'SELECT "syscolumns"."colname" AS "name",
+ CASE "syscolumns"."coltype"
+ WHEN 0 THEN \'CHAR\'
+ WHEN 1 THEN \'SMALLINT\'
+ WHEN 2 THEN \'INTEGER\'
+ WHEN 3 THEN \'FLOAT\'
+ WHEN 4 THEN \'SMALLFLOAT\'
+ WHEN 5 THEN \'DECIMAL\'
+ WHEN 6 THEN \'SERIAL\'
+ WHEN 7 THEN \'DATE\'
+ WHEN 8 THEN \'MONEY\'
+ WHEN 9 THEN \'NULL\'
+ WHEN 10 THEN \'DATETIME\'
+ WHEN 11 THEN \'BYTE\'
+ WHEN 12 THEN \'TEXT\'
+ WHEN 13 THEN \'VARCHAR\'
+ WHEN 14 THEN \'INTERVAL\'
+ WHEN 15 THEN \'NCHAR\'
+ WHEN 16 THEN \'NVARCHAR\'
+ WHEN 17 THEN \'INT8\'
+ WHEN 18 THEN \'SERIAL8\'
+ WHEN 19 THEN \'SET\'
+ WHEN 20 THEN \'MULTISET\'
+ WHEN 21 THEN \'LIST\'
+ WHEN 22 THEN \'Unnamed ROW\'
+ WHEN 40 THEN \'LVARCHAR\'
+ WHEN 41 THEN \'BLOB/CLOB/BOOLEAN\'
+ WHEN 4118 THEN \'Named ROW\'
+ ELSE "syscolumns"."coltype"
+ END AS "type",
+ "syscolumns"."collength" as "max_length",
+ CASE "sysdefaults"."type"
+ WHEN \'L\' THEN "sysdefaults"."default"
+ ELSE NULL
+ END AS "default"
+ FROM "syscolumns", "systables", "sysdefaults"
+ WHERE "syscolumns"."tabid" = "systables"."tabid"
+ AND "systables"."tabid" = "sysdefaults"."tabid"
+ AND "syscolumns"."colno" = "sysdefaults"."colno"
+ AND "systables"."tabtype" = \'T\'
+ AND LOWER("systables"."owner") = '.$this->escape(strtolower($this->username)).'
+ AND LOWER("systables"."tabname") = '.$this->escape(strtolower($table)).'
+ ORDER BY "syscolumns"."colno"';
+
+ return (($query = $this->query($sql)) !== FALSE)
+ ? $query->result_object()
+ : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'TRUNCATE TABLE ONLY '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql $SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ $select = 'SELECT '.($this->qb_offset ? 'SKIP '.$this->qb_offset : '').'FIRST '.$this->qb_limit.' ';
+ return preg_replace('/^(SELECT\s)/i', $select, $sql, 1);
+ }
+
+}
+
+/* End of file pdo_informix_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_informix_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php b/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php
new file mode 100644
index 000000000..8722dd200
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Informix Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_informix_forge extends CI_DB_pdo_forge {
+
+ /**
+ * RENAME TABLE statement
+ *
+ * @var string
+ */
+ protected $_rename_table = 'RENAME TABLE %s TO %s';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INTEGER' => 'BIGINT',
+ 'REAL' => 'DOUBLE PRECISION',
+ 'SMALLFLOAT' => 'DOUBLE PRECISION'
+ );
+
+ /**
+ * DEFAULT value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_default = ', ';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'CHANGE')
+ {
+ $alter_type = 'MODIFY';
+ }
+
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'BYTE':
+ case 'TEXT':
+ case 'BLOB':
+ case 'CLOB':
+ $attributes['UNIQUE'] = FALSE;
+ if (isset($attributes['DEFAULT']))
+ {
+ unset($attributes['DEFAULT']);
+ }
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute UNIQUE
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_unique(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+ {
+ $field['unique'] = ' UNIQUE CONSTRAINT '.$this->db->escape_identifiers($field['name']);
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ // Not supported
+ }
+
+}
+
+/* End of file pdo_informix_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_informix_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
new file mode 100644
index 000000000..a29397205
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO MySQL Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'mysql';
+
+ /**
+ * Compression flag
+ *
+ * @var bool
+ */
+ public $compress = FALSE;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Identifier escape character
+ *
+ * @var string
+ */
+ protected $_escape_char = '`';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'mysql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ empty($this->port) OR $this->dsn .= ';port='.$this->port;
+ empty($this->database) OR $this->dsn .= ';dbname='.$this->database;
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ }
+ elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE && is_php('5.3.6'))
+ {
+ $this->dsn .= ';charset='.$this->char_set;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database connection
+ *
+ * @param bool $persistent
+ * @return object
+ * @todo SSL support
+ */
+ public function db_connect($persistent = FALSE)
+ {
+ /* 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 ( ! is_php('5.3.6') && ! empty($this->char_set))
+ {
+ $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set
+ .(empty($this->dbcollat) ? '' : ' COLLATE '.$this->dbcollat);
+ }
+
+ if ($this->compress === TRUE)
+ {
+ $this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE;
+ }
+
+ return parent::db_connect($persistent);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SHOW TABLES';
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->Field;
+
+ sscanf($query[$i]->Type, '%[a-z](%d)',
+ $retval[$i]->type,
+ $retval[$i]->max_length
+ );
+
+ $retval[$i]->default = $query[$i]->Default;
+ $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update_Batch statement
+ *
+ * Generates a platform-specific batch update string from the supplied data
+ *
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index UPDATE key
+ * @return string
+ */
+ protected function _update_batch($table, $values, $index)
+ {
+ $ids = array();
+ foreach ($values as $key => $val)
+ {
+ $ids[] = $val[$index];
+
+ foreach (array_keys($val) as $field)
+ {
+ if ($field !== $index)
+ {
+ $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
+ }
+ }
+ }
+
+ $cases = '';
+ foreach ($final as $k => $v)
+ {
+ $cases .= $k." = CASE \n"
+ .implode("\n", $v)."\n"
+ .'ELSE '.$k.' END), ';
+ }
+
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'TRUNCATE '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
+}
+
+/* End of file pdo_mysql_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php
new file mode 100644
index 000000000..5a6de6b2d
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO MySQL Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_mysql_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
+ protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s';
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
+
+ /**
+ * CREATE TABLE keys flag
+ *
+ * Whether table keys are created from within the
+ * CREATE TABLE statement.
+ *
+ * @var bool
+ */
+ protected $_create_table_keys = TRUE;
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT',
+ 'SMALLINT',
+ 'MEDIUMINT',
+ 'INT',
+ 'INTEGER',
+ 'BIGINT',
+ 'REAL',
+ 'DOUBLE',
+ 'DOUBLE PRECISION',
+ 'FLOAT',
+ 'DECIMAL',
+ 'NUMERIC'
+ );
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
+
+ $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'DROP')
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ $field[$i] = ($alter_type === 'ADD')
+ ? "\n\tADD ".$field[$i]['_literal']
+ : "\n\tMODIFY ".$field[$i]['_literal'];
+ }
+ else
+ {
+ if ($alter_type === 'ADD')
+ {
+ $field[$i]['_literal'] = "\n\tADD ";
+ }
+ else
+ {
+ $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE ";
+ }
+
+ $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]);
+ }
+ }
+
+ return array($sql.implode(',', $field));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ $extra_clause = isset($field['after'])
+ ? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
+
+ if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
+ {
+ $extra_clause = ' FIRST';
+ }
+
+ return $this->db->escape_identifiers($field['name'])
+ .(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
+ .' '.$field['type'].$field['length']
+ .$field['unsigned']
+ .$field['null']
+ .$field['default']
+ .$field['auto_increment']
+ .$field['unique']
+ .$extra_clause;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process indexes
+ *
+ * @param string $table (ignored)
+ * @return string
+ */
+ protected function _process_indexes($table)
+ {
+ $sql = '';
+
+ for ($i = 0, $c = count($this->keys); $i < $c; $i++)
+ {
+ if (is_array($this->keys[$i]))
+ {
+ for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
+ {
+ if ( ! isset($this->fields[$this->keys[$i][$i2]]))
+ {
+ unset($this->keys[$i][$i2]);
+ continue;
+ }
+ }
+ }
+ elseif ( ! isset($this->fields[$this->keys[$i]]))
+ {
+ unset($this->keys[$i]);
+ continue;
+ }
+
+ is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
+
+ $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+ .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
+ }
+
+ $this->keys = array();
+
+ return $sql;
+ }
+
+}
+
+/* End of file pdo_mysql_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
new file mode 100644
index 000000000..57df558ad
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
@@ -0,0 +1,291 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Oracle Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'oci';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * List of reserved identifiers
+ *
+ * Identifiers that must NOT be escaped.
+ *
+ * @var string[]
+ */
+ protected $_reserved_identifiers = array('*', 'rownum');
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('ASC', 'ASC'); // Currently not supported
+
+ /**
+ * COUNT string
+ *
+ * @used-by CI_DB_driver::count_all()
+ * @used-by CI_DB_query_builder::count_all_results()
+ *
+ * @var string
+ */
+ protected $_count_string = 'SELECT COUNT(1) AS ';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'oci:dbname=';
+
+ // Oracle has a slightly different PDO DSN format (Easy Connect),
+ // which also supports pre-defined DSNs.
+ if (empty($this->hostname) && empty($this->port))
+ {
+ $this->dsn .= $this->database;
+ }
+ else
+ {
+ $this->dsn .= '//'.(empty($this->hostname) ? '127.0.0.1' : $this->hostname)
+ .(empty($this->port) ? '' : ':'.$this->port).'/';
+
+ empty($this->database) OR $this->dsn .= $this->database;
+ }
+
+ empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set;
+ }
+ elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 4) === FALSE)
+ {
+ $this->dsn .= ';charset='.$this->char_set;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"';
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql.' WHERE "TABLE_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ if (strpos($table, '.') !== FALSE)
+ {
+ sscanf($table, '%[^.].%s', $owner, $table);
+ }
+ else
+ {
+ $owner = $this->username;
+ }
+
+ return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS
+ WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
+ AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+ elseif (strpos($table, '.') !== FALSE)
+ {
+ sscanf($table, '%[^.].%s', $owner, $table);
+ }
+ else
+ {
+ $owner = $this->username;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHAR_LENGTH, DATA_PRECISION, DATA_LENGTH, DATA_DEFAULT, NULLABLE
+ FROM ALL_TAB_COLUMNS
+ WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
+ AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+
+ $length = ($query[$i]->CHAR_LENGTH > 0)
+ ? $query[$i]->CHAR_LENGTH : $query[$i]->DATA_PRECISION;
+ if ($length === NULL)
+ {
+ $length = $query[$i]->DATA_LENGTH;
+ }
+ $retval[$i]->max_length = $length;
+
+ $default = $query[$i]->DATA_DEFAULT;
+ if ($default === NULL && $query[$i]->NULLABLE === 'N')
+ {
+ $default = '';
+ }
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert batch statement
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string
+ */
+ protected function _insert_batch($table, $keys, $values)
+ {
+ $keys = implode(', ', $keys);
+ $sql = "INSERT ALL\n";
+
+ for ($i = 0, $c = count($values); $i < $c; $i++)
+ {
+ $sql .= ' INTO '.$table.' ('.$keys.') VALUES '.$values[$i]."\n";
+ }
+
+ return $sql.'SELECT * FROM dual';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ if ($this->qb_limit)
+ {
+ $this->where('rownum <= ',$this->qb_limit, FALSE);
+ $this->qb_limit = FALSE;
+ }
+
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
+ .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): '');
+ }
+
+}
+
+/* End of file pdo_oci_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_oci_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php b/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php
new file mode 100644
index 000000000..6d51a14b1
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO Oracle Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_oci_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE DATABASE statement
+ *
+ * @var string
+ */
+ protected $_create_database = FALSE;
+
+ /**
+ * DROP DATABASE statement
+ *
+ * @var string
+ */
+ protected $_drop_database = FALSE;
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'DROP')
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+ elseif ($alter_type === 'CHANGE')
+ {
+ $alter_type = 'MODIFY';
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ $field[$i] = "\n\t".$field[$i]['_literal'];
+ }
+ else
+ {
+ $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]);
+ if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name']))
+ {
+ $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' '.$this->db->escape_identifiers($field[$i]['new_name']);
+ }
+ }
+ }
+
+ $sql .= ' '.$alter_type.' ';
+ $sql .= (count($field) === 1)
+ ? $field[0]
+ : '('.implode(',', $field).')';
+
+ // RENAME COLUMN must be executed after MODIFY
+ array_unshift($sqls, $sql);
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ // Not supported - sequences and triggers must be used instead
+ }
+
+}
+
+/* End of file pdo_oci_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_oci_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
new file mode 100644
index 000000000..c940a7b1f
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO ODBC Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'odbc';
+
+ /**
+ * Database schema
+ *
+ * @var string
+ */
+ public $schema = 'public';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Identifier escape character
+ *
+ * Must be empty for ODBC.
+ *
+ * @var string
+ */
+ protected $_escape_char = '';
+
+ /**
+ * ESCAPE statement string
+ *
+ * @var string
+ */
+ protected $_like_escape_str = " {escape '%s'} ";
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RND()', 'RND(%d)');
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'odbc:';
+
+ // Pre-defined DSN
+ if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT))
+ {
+ if (isset($this->DSN))
+ {
+ $this->dsn .= 'DSN='.$this->DSN;
+ }
+ elseif ( ! empty($this->database))
+ {
+ $this->dsn .= 'DSN='.$this->database;
+ }
+
+ return;
+ }
+
+ // If the DSN is not pre-configured - try to build an IBM DB2 connection string
+ $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';';
+
+ if (isset($this->DATABASE))
+ {
+ $this->dsn .= 'DATABASE='.$this->DATABASE.';';
+ }
+ elseif ( ! empty($this->database))
+ {
+ $this->dsn .= 'DATABASE='.$this->database.';';
+ }
+
+ if (isset($this->HOSTNAME))
+ {
+ $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';';
+ }
+ else
+ {
+ $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';');
+ }
+
+ if (isset($this->PORT))
+ {
+ $this->dsn .= 'PORT='.$this->port.';';
+ }
+ elseif ( ! empty($this->port))
+ {
+ $this->dsn .= ';PORT='.$this->port.';';
+ }
+
+ $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;');
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'";
+
+ if ($prefix_limit !== FALSE && $this->dbprefix !== '')
+ {
+ return $sql." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT column_name FROM information_schema.columns WHERE table_name = '.$this->escape($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'DELETE FROM '.$table;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string the table name
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql);
+ }
+
+}
+
+/* End of file pdo_odbc_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php
new file mode 100644
index 000000000..ab4d2bf84
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO ODBC Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/database/
+ */
+class CI_DB_pdo_odbc_forge extends CI_DB_pdo_forge {
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ // Not supported (in most databases at least)
+ }
+
+}
+
+/* End of file pdo_odbc_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
new file mode 100644
index 000000000..2eb0606b3
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
@@ -0,0 +1,357 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO PostgreSQL Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'pgsql';
+
+ /**
+ * Database schema
+ *
+ * @var string
+ */
+ public $schema = 'public';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM()');
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'pgsql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ empty($this->port) OR $this->dsn .= ';port='.$this->port;
+ empty($this->database) OR $this->dsn .= ';dbname='.$this->database;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database connection
+ *
+ * @param bool $persistent
+ * @return object
+ */
+ public function db_connect($persistent = FALSE)
+ {
+ $this->conn_id = parent::db_connect($persistent);
+
+ if (is_object($this->conn_id) && ! empty($this->schema))
+ {
+ $this->simple_query('SET search_path TO '.$this->schema.',public');
+ }
+
+ return $this->conn_id;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert ID
+ *
+ * @param string $name
+ * @return int
+ */
+ public function insert_id($name = NULL)
+ {
+ if ($name === NULL && version_compare($this->version(), '8.1', '>='))
+ {
+ $query = $this->query('SELECT LASTVAL() AS ins_id');
+ $query = $query->row();
+ return $query->ins_id;
+ }
+
+ return $this->conn_id->lastInsertId($name);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * "Smart" Escape String
+ *
+ * Escapes data based on type
+ *
+ * @param string $str
+ * @return mixed
+ */
+ public function escape($str)
+ {
+ if (is_bool($str))
+ {
+ return ($str) ? 'TRUE' : 'FALSE';
+ }
+
+ return parent::escape($str);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY
+ *
+ * @param string $orderby
+ * @param string $direction ASC or DESC
+ * @param bool $escape
+ * @return object
+ */
+ public function order_by($orderby, $direction = '', $escape = NULL)
+ {
+ $direction = strtoupper(trim($direction));
+ if ($direction === 'RANDOM')
+ {
+ if ( ! is_float($orderby) && ctype_digit((string) $orderby))
+ {
+ $orderby = ($orderby > 1)
+ ? (float) '0.'.$orderby
+ : (float) $orderby;
+ }
+
+ if (is_float($orderby))
+ {
+ $this->simple_query('SET SEED '.$orderby);
+ }
+
+ $orderby = $this->_random_keyword[0];
+ $direction = '';
+ $escape = FALSE;
+ }
+
+ return parent::order_by($orderby, $direction, $escape);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'";
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql.' AND "table_name" LIKE \''
+ .$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * List column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT "column_name"
+ FROM "information_schema"."columns"
+ WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT "column_name", "data_type", "character_maximum_length", "numeric_precision", "column_default"
+ FROM "information_schema"."columns"
+ WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->column_name;
+ $retval[$i]->type = $query[$i]->data_type;
+ $retval[$i]->max_length = ($query[$i]->character_maximum_length > 0) ? $query[$i]->character_maximum_length : $query[$i]->numeric_precision;
+ $retval[$i]->default = $query[$i]->column_default;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update_Batch statement
+ *
+ * Generates a platform-specific batch update string from the supplied data
+ *
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
+ * @return string
+ */
+ protected function _update_batch($table, $values, $index)
+ {
+ $ids = array();
+ foreach ($values as $key => $val)
+ {
+ $ids[] = $val[$index];
+
+ foreach (array_keys($val) as $field)
+ {
+ if ($field !== $index)
+ {
+ $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field];
+ }
+ }
+ }
+
+ $cases = '';
+ foreach ($final as $k => $v)
+ {
+ $cases .= $k.' = (CASE '.$index."\n"
+ .implode("\n", $v)."\n"
+ .'ELSE '.$k.' END), ';
+ }
+
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
+ }
+
+}
+
+/* End of file pdo_pgsql_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php
new file mode 100644
index 000000000..a24c898af
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO PostgreSQL Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_pgsql_forge extends CI_DB_pdo_forge {
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'INT2' => 'INTEGER',
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INT4' => 'BIGINT',
+ 'INTEGER' => 'BIGINT',
+ 'INT8' => 'NUMERIC',
+ 'BIGINT' => 'NUMERIC',
+ 'REAL' => 'DOUBLE PRECISION',
+ 'FLOAT' => 'DOUBLE PRECISION'
+ );
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
+
+ if (version_compare($this->db->version(), '9.0', '>'))
+ {
+ $this->create_table_if = 'CREATE TABLE IF NOT EXISTS';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ return FALSE;
+ }
+
+ if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TYPE '.$field[$i]['type'].$field[$i]['length'];
+ }
+
+ if ( ! empty($field[$i]['default']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' SET DEFAULT '.$field[$i]['default'];
+ }
+
+ if (isset($field[$i]['null']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL');
+ }
+
+ if ( ! empty($field[$i]['new_name']))
+ {
+ $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TO '.$this->db->escape_identifiers($field[$i]['new_name']);
+ }
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ // Reset field lenghts for data types that don't support it
+ if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE)
+ {
+ $attributes['CONSTRAINT'] = NULL;
+ }
+
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+ {
+ $field['type'] = ($field['type'] === 'NUMERIC')
+ ? 'BIGSERIAL'
+ : 'SERIAL';
+ }
+ }
+
+}
+
+/* End of file pdo_pgsql_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php
new file mode 100644
index 000000000..568044e2d
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO SQLite Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_sqlite_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'sqlite';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = ' RANDOM()';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'sqlite:';
+
+ if (empty($this->database) && empty($this->hostname))
+ {
+ $this->database = ':memory:';
+ }
+
+ $this->database = empty($this->database) ? $this->hostname : $this->database;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ $sql = 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\'';
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ return $sql.' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE)
+ {
+ return FALSE;
+ }
+
+ $query = $query->result_array();
+ if (empty($query))
+ {
+ return FALSE;
+ }
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]['name'];
+ $retval[$i]->type = $query[$i]['type'];
+ $retval[$i]->max_length = NULL;
+ $retval[$i]->default = $query[$i]['dflt_value'];
+ $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Replace statement
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string
+ */
+ protected function _replace($table, $keys, $values)
+ {
+ return 'INSERT OR '.parent::_replace($table, $keys, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ *
+ * If the database does not support the TRUNCATE statement,
+ * then this method maps to 'DELETE FROM table'
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return 'DELETE FROM '.$table;
+ }
+
+}
+
+/* End of file pdo_sqlite_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php b/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php
new file mode 100644
index 000000000..da098df31
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO SQLite Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_sqlite_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS';
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = 'DROP TABLE IF EXISTS';
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
+
+ if (version_compare($this->db->version(), '3.3', '<'))
+ {
+ $this->_create_table_if = FALSE;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Create database
+ *
+ * @param string $db_name (ignored)
+ * @return bool
+ */
+ public function create_database($db_name = '')
+ {
+ // In SQLite, a database is created when you connect to the database.
+ // We'll return TRUE so that an error isn't generated
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Drop database
+ *
+ * @param string $db_name (ignored)
+ * @return bool
+ */
+ public function drop_database($db_name = '')
+ {
+ // In SQLite, a database is dropped when we delete a file
+ if (@file_exists($this->db->database))
+ {
+ // We need to close the pseudo-connection first
+ $this->db->close();
+ if ( ! @unlink($this->db->database))
+ {
+ return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
+ }
+ elseif ( ! empty($this->db->data_cache['db_names']))
+ {
+ $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+ if ($key !== FALSE)
+ {
+ unset($this->db->data_cache['db_names'][$key]);
+ }
+ }
+
+ return TRUE;
+ }
+
+ return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if ($alter_type === 'DROP' OR $alter_type === 'CHANGE')
+ {
+ // drop_column():
+ // BEGIN TRANSACTION;
+ // CREATE TEMPORARY TABLE t1_backup(a,b);
+ // INSERT INTO t1_backup SELECT a,b FROM t1;
+ // DROP TABLE t1;
+ // CREATE TABLE t1(a,b);
+ // INSERT INTO t1 SELECT a,b FROM t1_backup;
+ // DROP TABLE t1_backup;
+ // COMMIT;
+
+ return FALSE;
+ }
+
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type']
+ .$field['auto_increment']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'ENUM':
+ case 'SET':
+ $attributes['TYPE'] = 'TEXT';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['type'] = 'INTEGER PRIMARY KEY';
+ $field['default'] = '';
+ $field['null'] = '';
+ $field['unique'] = '';
+ $field['auto_increment'] = ' AUTOINCREMENT';
+
+ $this->primary_keys = array();
+ }
+ }
+
+}
+
+/* End of file pdo_sqlite_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
new file mode 100644
index 000000000..ec0252613
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
@@ -0,0 +1,363 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO SQLSRV Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
+
+ /**
+ * Sub-driver
+ *
+ * @var string
+ */
+ public $subdriver = 'sqlsrv';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('NEWID()', 'RAND(%d)');
+
+ /**
+ * Quoted identifier flag
+ *
+ * Whether to use SQL-92 standard quoted identifier
+ * (double quotes) or brackets for identifier escaping.
+ *
+ * @var bool
+ */
+ protected $_quoted_identifier;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * Builds the DSN if not already set.
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ parent::__construct($params);
+
+ if (empty($this->dsn))
+ {
+ $this->dsn = 'sqlsrv:Server='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname);
+
+ empty($this->port) OR $this->dsn .= ','.$this->port;
+ empty($this->database) OR $this->dsn .= ';Database='.$this->database;
+
+ // Some custom options
+
+ if (isset($this->QuotedId))
+ {
+ $this->dsn .= ';QuotedId='.$this->QuotedId;
+ $this->_quoted_identifier = (bool) $this->QuotedId;
+ }
+
+ if (isset($this->ConnectionPooling))
+ {
+ $this->dsn .= ';ConnectionPooling='.$this->ConnectionPooling;
+ }
+
+ if ($this->encrypt === TRUE)
+ {
+ $this->dsn .= ';Encrypt=1';
+ }
+
+ if (isset($this->TraceOn))
+ {
+ $this->dsn .= ';TraceOn='.$this->TraceOn;
+ }
+
+ if (isset($this->TrustServerCertificate))
+ {
+ $this->dsn .= ';TrustServerCertificate='.$this->TrustServerCertificate;
+ }
+
+ empty($this->APP) OR $this->dsn .= ';APP='.$this->APP;
+ empty($this->Failover_Partner) OR $this->dsn .= ';Failover_Partner='.$this->Failover_Partner;
+ empty($this->LoginTimeout) OR $this->dsn .= ';LoginTimeout='.$this->LoginTimeout;
+ empty($this->MultipleActiveResultSets) OR $this->dsn .= ';MultipleActiveResultSets='.$this->MultipleActiveResultSets;
+ empty($this->TraceFile) OR $this->dsn .= ';TraceFile='.$this->TraceFile;
+ empty($this->WSID) OR $this->dsn .= ';WSID='.$this->WSID;
+ }
+ elseif (preg_match('/QuotedId=(0|1)/', $this->dsn, $match))
+ {
+ $this->_quoted_identifier = (bool) $match[1];
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database connection
+ *
+ * @param bool $persistent
+ * @return object
+ */
+ public function db_connect($persistent = FALSE)
+ {
+ if ( ! empty($this->char_set) && preg_match('/utf[^8]*8/i', $this->char_set))
+ {
+ $this->options[PDO::SQLSRV_ENCODING_UTF8] = 1;
+ }
+
+ $this->conn_id = parent::db_connect($persistent);
+
+ if ( ! is_object($this->conn_id) OR is_bool($this->_quoted_identifier))
+ {
+ return $this->conn_id;
+ }
+
+ // Determine how identifiers are escaped
+ $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+ $query = $query->row_array();
+ $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
+ $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+ return $this->conn_id;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show table query
+ *
+ * Generates a platform-specific query string so that the table names can be fetched
+ *
+ * @param bool $prefix_limit
+ * @return string
+ */
+ protected function _list_tables($prefix_limit = FALSE)
+ {
+ return 'SELECT '.$this->escape_identifiers('name')
+ .' FROM '.$this->escape_identifiers('sysobjects')
+ .' WHERE '.$this->escape_identifiers('type')." = 'U'";
+
+ if ($prefix_limit === TRUE && $this->dbprefix !== '')
+ {
+ $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
+ .sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ }
+
+ return $sql.' ORDER BY '.$this->escape_identifiers('name');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show column query
+ *
+ * Generates a platform-specific query string so that the column names can be fetched
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _list_columns($table = '')
+ {
+ return 'SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns an object with field data
+ *
+ * @param string $table
+ * @return array
+ */
+ public function field_data($table = '')
+ {
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+ $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Update statement
+ *
+ * Generates a platform-specific update string from the supplied data
+ *
+ * @param string $table
+ * @param array $values
+ * @return string
+ */
+ protected function _update($table, $values)
+ {
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string $table
+ * @return string
+ */
+ protected function _delete($table)
+ {
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
+
+ return parent::_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * LIMIT
+ *
+ * Generates a platform-specific LIMIT clause
+ *
+ * @param string $sql SQL Query
+ * @return string
+ */
+ protected function _limit($sql)
+ {
+ // As of SQL Server 2012 (11.0.*) OFFSET is supported
+ if (version_compare($this->version(), '11', '>='))
+ {
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
+ }
+
+ $limit = $this->qb_offset + $this->qb_limit;
+
+ // An ORDER BY clause is required for ROW_NUMBER() to work
+ if ($this->qb_offset && ! empty($this->qb_orderby))
+ {
+ $orderby = $this->_compile_order_by();
+
+ // We have to strip the ORDER BY clause
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
+
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
+ }
+
+ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert batch statement
+ *
+ * Generates a platform-specific insert string from the supplied data.
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string|bool
+ */
+ protected function _insert_batch($table, $keys, $values)
+ {
+ // Multiple-value inserts are only supported as of SQL Server 2008
+ if (version_compare($this->version(), '10', '>='))
+ {
+ return parent::_insert_batch($table, $keys, $values);
+ }
+
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+}
+
+/* End of file pdo_sqlsrv_driver.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php
new file mode 100644
index 000000000..e4b669f6e
--- /dev/null
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * 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:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * PDO SQLSRV Forge Class
+ *
+ * @category Database
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_pdo_sqlsrv_forge extends CI_DB_pdo_forge {
+
+ /**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE";
+
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE";
+
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT' => 'SMALLINT',
+ 'SMALLINT' => 'INT',
+ 'INT' => 'BIGINT',
+ 'REAL' => 'FLOAT'
+ );
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN ';
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ $sqls[] = $sql.$this->_process_column($field[$i]);
+ }
+
+ return $sqls;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
+ {
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INTEGER':
+ $attributes['TYPE'] = 'INT';
+ return;
+ default: return;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' IDENTITY(1,1)';
+ }
+ }
+
+}
+
+/* End of file pdo_sqlsrv_forge.php */
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 20b78673e..44cd0ce9b 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Postgre Database Adapter Class
@@ -40,21 +41,37 @@
*/
class CI_DB_postgre_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'postgre';
- protected $_escape_char = '"';
+ /**
+ * Database schema
+ *
+ * @var string
+ */
+ public $schema = 'public';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ // --------------------------------------------------------------------
- protected $_random_keyword = ' RANDOM()'; // database specific random keyword
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM()');
+
+ // --------------------------------------------------------------------
/**
- * Constructor
+ * Class constructor
*
* Creates a DSN string to be used for db_connect() and db_pconnect()
*
+ * @param array $params
* @return void
*/
public function __construct($params)
@@ -114,13 +131,32 @@ class CI_DB_postgre_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Non-persistent database connection
+ * Database connection
*
+ * @param bool $persistent
* @return resource
*/
- public function db_connect()
+ public function db_connect($persistent = FALSE)
{
- return @pg_connect($this->dsn);
+ if ($persistent === TRUE
+ && ($this->conn_id = @pg_pconnect($this->dsn))
+ && pg_connection_status($this->conn_id) === PGSQL_CONNECTION_BAD
+ && pg_ping($this->conn_id) === FALSE
+ )
+ {
+ return FALSE;
+ }
+ else
+ {
+ $this->conn_id = @pg_connect($this->dsn);
+ }
+
+ if ($this->conn_id && ! empty($this->schema))
+ {
+ $this->simple_query('SET search_path TO '.$this->schema.',public');
+ }
+
+ return $this->conn_id;
}
// --------------------------------------------------------------------
@@ -132,7 +168,7 @@ class CI_DB_postgre_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @pg_pconnect($this->dsn);
+ return $this->db_connect(TRUE);
}
// --------------------------------------------------------------------
@@ -158,7 +194,7 @@ class CI_DB_postgre_driver extends CI_DB {
/**
* Set client character set
*
- * @param string
+ * @param string $charset
* @return bool
*/
protected function _db_set_charset($charset)
@@ -179,8 +215,12 @@ class CI_DB_postgre_driver extends CI_DB {
{
return $this->data_cache['version'];
}
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
- if (($pg_version = pg_version($this->conn_id)) === FALSE)
+ if ( ! $this->conn_id OR ($pg_version = pg_version($this->conn_id)) === FALSE)
{
return FALSE;
}
@@ -200,7 +240,7 @@ class CI_DB_postgre_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -213,7 +253,7 @@ class CI_DB_postgre_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -273,8 +313,8 @@ class CI_DB_postgre_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -308,9 +348,8 @@ class CI_DB_postgre_driver extends CI_DB {
* "Smart" Escape String
*
* Escapes data based on type
- * Sets boolean and null types
*
- * @param string
+ * @param string $str
* @return mixed
*/
public function escape($str)
@@ -388,12 +427,12 @@ class CI_DB_postgre_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
- $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \'public\'';
+ $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'";
if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
@@ -408,31 +447,56 @@ class CI_DB_postgre_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Show column query
+ * List column query
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
- return 'SELECT "column_name" FROM "information_schema"."columns" WHERE "table_name" = '.$this->escape($table);
+ return 'SELECT "column_name"
+ FROM "information_schema"."columns"
+ WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
}
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT * FROM '.$table.' LIMIT 1';
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT "column_name", "data_type", "character_maximum_length", "numeric_precision", "column_default"
+ FROM "information_schema"."columns"
+ WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->column_name;
+ $retval[$i]->type = $query[$i]->data_type;
+ $retval[$i]->max_length = ($query[$i]->character_maximum_length > 0) ? $query[$i]->character_maximum_length : $query[$i]->numeric_precision;
+ $retval[$i]->default = $query[$i]->column_default;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -453,17 +517,36 @@ class CI_DB_postgre_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * ORDER BY
*
- * @param array
- * @return string
+ * @param string $orderby
+ * @param string $direction ASC or DESC
+ * @param bool $escape
+ * @return object
*/
- protected function _from_tables($tables)
+ public function order_by($orderby, $direction = '', $escape = NULL)
{
- return is_array($tables) ? implode(', ', $tables) : $tables;
+ $direction = strtoupper(trim($direction));
+ if ($direction === 'RANDOM')
+ {
+ if ( ! is_float($orderby) && ctype_digit((string) $orderby))
+ {
+ $orderby = ($orderby > 1)
+ ? (float) '0.'.$orderby
+ : (float) $orderby;
+ }
+
+ if (is_float($orderby))
+ {
+ $this->simple_query('SET SEED '.$orderby);
+ }
+
+ $orderby = $this->_random_keyword[0];
+ $direction = '';
+ $escape = FALSE;
+ }
+
+ return parent::order_by($orderby, $direction, $escape);
}
// --------------------------------------------------------------------
@@ -473,29 +556,15 @@ class CI_DB_postgre_driver extends CI_DB {
*
* Generates a platform-specific update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
+ * @param string $table
+ * @param array $values
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -505,12 +574,12 @@ class CI_DB_postgre_driver extends CI_DB {
*
* Generates a platform-specific batch update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
+ * @param string $table Table name
+ * @param array $values Update data
+ * @param string $index WHERE key
* @return string
*/
- protected function _update_batch($table, $values, $index, $where = NULL)
+ protected function _update_batch($table, $values, $index)
{
$ids = array();
foreach ($values as $key => $val)
@@ -521,7 +590,7 @@ class CI_DB_postgre_driver extends CI_DB {
{
if ($field !== $index)
{
- $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field];
+ $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field];
}
}
}
@@ -529,14 +598,14 @@ class CI_DB_postgre_driver extends CI_DB {
$cases = '';
foreach ($final as $k => $v)
{
- $cases .= $k.' = (CASE '.$k."\n"
+ $cases .= $k.' = (CASE '.$index."\n"
.implode("\n", $v)."\n"
.'ELSE '.$k.' END), ';
}
- return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
- .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
- .$index.' IN('.implode(',', $ids).')';
+ $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
+
+ return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
}
// --------------------------------------------------------------------
@@ -546,108 +615,28 @@ class CI_DB_postgre_driver extends CI_DB {
*
* Generates a platform-specific delete string from the supplied data
*
- * @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause (ignored)
+ * @param string $table
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+ $this->qb_limit = FALSE;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT
*
* Generates a platform-specific LIMIT clause
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
- return $sql.' LIMIT '.$limit.($offset ? ' OFFSET '.$offset : '');
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Where
- *
- * Called by where() or or_where()
- *
- * @param mixed
- * @param mixed
- * @param string
- * @param mixed
- * @return object
- */
- protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
- {
- if ( ! is_array($key))
- {
- $key = array($key => $value);
- }
-
- // If the escape value was not set will will base it on the global setting
- is_bool($escape) OR $escape = $this->_protect_identifiers;
-
- foreach ($key as $k => $v)
- {
- $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0)
- ? $this->_group_get_type('')
- : $this->_group_get_type($type);
-
- if ($escape === TRUE)
- {
- $k = (($op = $this->_get_operator($k)) !== FALSE)
- ? $this->escape_identifiers(trim(substr($k, 0, strpos($k, $op)))).' '.strstr($k, $op)
- : $this->escape_identifiers(trim($k));
- }
-
- if (is_null($v) && ! $this->_has_operator($k))
- {
- // value appears not to have been set, assign the test to IS NULL
- $k .= ' IS NULL';
- }
-
- if ( ! is_null($v))
- {
- if ($escape === TRUE)
- {
- $v = ' '.$this->escape($v);
- }
- elseif (is_bool($v))
- {
- $v = ($v ? ' TRUE' : ' FALSE');
- }
-
- if ( ! $this->_has_operator($k))
- {
- $k .= ' = ';
- }
- }
-
- $this->qb_where[] = $prefix.$k.$v;
- if ($this->qb_caching === TRUE)
- {
- $this->qb_cache_where[] = $prefix.$k.$v;
- $this->qb_cache_exists[] = 'where';
- }
-
- }
-
- return $this;
+ return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index c434e9510..5e378385c 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Postgre Forge Class
@@ -34,184 +35,152 @@
*/
class CI_DB_postgre_forge extends CI_DB_forge {
- protected $_drop_table = 'DROP TABLE IF EXISTS %s CASCADE';
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'INT2' => 'INTEGER',
+ 'SMALLINT' => 'INTEGER',
+ 'INT' => 'BIGINT',
+ 'INT4' => 'BIGINT',
+ 'INTEGER' => 'BIGINT',
+ 'INT8' => 'NUMERIC',
+ 'BIGINT' => 'NUMERIC',
+ 'REAL' => 'DOUBLE PRECISION',
+ 'FLOAT' => 'DOUBLE PRECISION'
+ );
/**
- * Process Fields
+ * NULL value representation in CREATE/ALTER TABLE statements
*
- * @param mixed the fields
- * @return string
+ * @var string
*/
- protected function _process_fields($fields, $primary_keys = array())
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
{
- $sql = '';
- $current_field_count = 0;
+ parent::__construct($db);
- foreach ($fields as $field => $attributes)
+ if (version_compare($this->db->version(), '9.0', '>'))
{
- // 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
+ $this->create_table_if = 'CREATE TABLE IF NOT EXISTS';
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
+ {
+ return parent::_alter_table($alter_type, $table, $field);
+ }
+
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
+ {
+ if ($field[$i]['_literal'] !== FALSE)
+ {
+ return FALSE;
+ }
+
+ if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type']))
{
- $sql .= "\n\t".$attributes;
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TYPE '.$field[$i]['type'].$field[$i]['length'];
}
- else
+
+ if ( ! empty($field[$i]['default']))
+ {
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' SET DEFAULT '.$field[$i]['default'];
+ }
+
+ if (isset($field[$i]['null']))
{
- $sql .= "\n\t".$this->db->escape_identifiers($field);
-
- $attributes = array_change_key_case($attributes, CASE_UPPER);
- $is_unsigned = ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE);
-
- // Convert datatypes to be PostgreSQL-compatible
- switch (strtoupper($attributes['TYPE']))
- {
- case 'TINYINT':
- $attributes['TYPE'] = 'SMALLINT';
- break;
- case 'SMALLINT':
- $attributes['TYPE'] = ($is_unsigned) ? 'INTEGER' : 'SMALLINT';
- break;
- case 'MEDIUMINT':
- $attributes['TYPE'] = 'INTEGER';
- break;
- case 'INT':
- $attributes['TYPE'] = ($is_unsigned) ? 'BIGINT' : 'INTEGER';
- break;
- case 'BIGINT':
- $attributes['TYPE'] = ($is_unsigned) ? 'NUMERIC' : 'BIGINT';
- break;
- case 'DOUBLE':
- $attributes['TYPE'] = 'DOUBLE PRECISION';
- break;
- case 'DATETIME':
- $attributes['TYPE'] = 'TIMESTAMP';
- break;
- case 'LONGTEXT':
- $attributes['TYPE'] = 'TEXT';
- break;
- case 'BLOB':
- $attributes['TYPE'] = 'BYTEA';
- break;
- default:
- break;
- }
-
- // If this is an auto-incrementing primary key, use the serial data type instead
- $sql .= (in_array($field, $primary_keys) && ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- ? ' SERIAL' : ' '.$attributes['TYPE'];
-
- // Modified to prevent constraints with integer data types
- if ( ! empty($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') === FALSE)
- {
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
-
- // Added new attribute to create unique fields. Also works with MySQL
- if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
- {
- $sql .= ' UNIQUE';
- }
+ $sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL');
}
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
+ if ( ! empty($field[$i]['new_name']))
{
- $sql .= ',';
+ $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
+ .' TO '.$this->db->escape_identifiers($field[$i]['new_name']);
}
}
- return $sql;
- }
+ return $sqls;
+ }
// --------------------------------------------------------------------
/**
- * Create Table
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @param array &$attributes
+ * @return void
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _attr_type(&$attributes)
{
- $sql = 'CREATE TABLE ';
-
- // PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
- if ($if_not_exists === TRUE && $this->db->table_exists($table))
+ // Reset field lenghts for data types that don't support it
+ if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE)
{
- return TRUE;
+ $attributes['CONSTRAINT'] = NULL;
}
- $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields, $primary_keys);
-
- if (count($primary_keys) > 0)
+ switch (strtoupper($attributes['TYPE']))
{
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+ case 'TINYINT':
+ $attributes['TYPE'] = 'SMALLINT';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ default: return;
}
-
- $sql .= "\n);";
-
- if (is_array($keys) && count($keys) > 0)
- {
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- foreach ($key as $field)
- {
- $sql .= "\nCREATE INDEX ".$this->db->escape_identifiers($table.'_'.str_replace(array('"', "'"), '', $field).'_index')
- .' ON '.$this->db->escape_identifiers($table).' ('.$this->db->escape_identifiers($field).');';
- }
- }
- }
-
- return $sql;
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute AUTO_INCREMENT
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
- *
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $fields, $after_field = '')
- {
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
- {
- return $sql.$this->db->escape_identifiers($fields);
- }
-
- return $sql.$this->_process_fields($fields)
- .($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
- }
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+ {
+ $field['type'] = ($field['type'] === 'NUMERIC')
+ ? 'BIGSERIAL'
+ : 'SERIAL';
+ }
+ }
}
diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index eb9d647e7..fdaeaef70 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Postgres Result Class
@@ -99,8 +100,6 @@ class CI_DB_postgre_result extends CI_DB_result {
$retval[$i]->name = pg_field_name($this->result_id, $i);
$retval[$i]->type = pg_field_type($this->result_id, $i);
$retval[$i]->max_length = pg_field_size($this->result_id, $i);
- $retval[$i]->primary_key = 0;
- $retval[$i]->default = '';
}
return $retval;
@@ -129,11 +128,12 @@ class CI_DB_postgre_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return pg_result_seek($this->result_id, $n);
}
@@ -159,7 +159,7 @@ class CI_DB_postgre_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php
index c95e6df0c..d3b2b9cdc 100644
--- a/system/database/drivers/postgre/postgre_utility.php
+++ b/system/database/drivers/postgre/postgre_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Postgre Utility Class
@@ -34,19 +35,32 @@
*/
class CI_DB_postgre_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'SELECT datname FROM pg_database';
+
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = 'REINDEX TABLE %s';
+ // --------------------------------------------------------------------
+
/**
- * Postgre Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 19824dbbf..8c706c242 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite Database Adapter Class
@@ -40,16 +41,23 @@
*/
class CI_DB_sqlite_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'sqlite';
- // The character used to escape with - not needed for SQLite
- protected $_escape_char = '"';
+ // --------------------------------------------------------------------
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM()');
- protected $_random_keyword = ' Random()'; // database specific random keyword
+ // --------------------------------------------------------------------
/**
* Non-persistent database connection
@@ -116,7 +124,7 @@ class CI_DB_sqlite_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -131,6 +139,7 @@ class CI_DB_sqlite_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -193,8 +202,8 @@ class CI_DB_sqlite_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -253,7 +262,7 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -275,7 +284,7 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return bool
*/
protected function _list_columns($table = '')
@@ -287,16 +296,41 @@ class CI_DB_sqlite_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1';
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE)
+ {
+ return FALSE;
+ }
+
+ $query = $query->result_array();
+ if (empty($query))
+ {
+ return FALSE;
+ }
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]['name'];
+ $retval[$i]->type = $query[$i]['type'];
+ $retval[$i]->max_length = NULL;
+ $retval[$i]->default = $query[$i]['dflt_value'];
+ $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -323,9 +357,9 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* Generates a platform-specific replace string from the supplied data
*
- * @param string the table name
- * @param array the insert keys
- * @param array the insert values
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
* @return string
*/
protected function _replace($table, $keys, $values)
@@ -340,10 +374,10 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this function maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index e02e327f3..6ad583560 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite Forge Class
@@ -35,9 +36,32 @@
class CI_DB_sqlite_forge extends CI_DB_forge {
/**
+ * CREATE TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_create_table_if = FALSE;
+
+ /**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
* Create database
*
- * @param string the database name
+ * @param string $db_name (ignored)
* @return bool
*/
public function create_database($db_name = '')
@@ -52,7 +76,7 @@ class CI_DB_sqlite_forge extends CI_DB_forge {
/**
* Drop database
*
- * @param string the database name (ignored)
+ * @param string $db_name (ignored)
* @return bool
*/
public function drop_database($db_name = '')
@@ -76,126 +100,95 @@ class CI_DB_sqlite_forge extends CI_DB_forge {
// --------------------------------------------------------------------
/**
- * Create Table
+ * ALTER TABLE
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @todo implement drop_column(), modify_column()
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _alter_table($alter_type, $table, $field)
{
- $sql = 'CREATE TABLE ';
-
- // IF NOT EXISTS added to SQLite in 3.3.0
- if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE)
+ if ($alter_type === 'DROP' OR $alter_type === 'CHANGE')
{
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' (';
- $current_field_count = 0;
-
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
-
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
+ // drop_column():
+ // BEGIN TRANSACTION;
+ // CREATE TEMPORARY TABLE t1_backup(a,b);
+ // INSERT INTO t1_backup SELECT a,b FROM t1;
+ // DROP TABLE t1;
+ // CREATE TABLE t1(a,b);
+ // INSERT INTO t1 SELECT a,b FROM t1_backup;
+ // DROP TABLE t1_backup;
+ // COMMIT;
+ return FALSE;
+ }
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ return parent::_alter_table($alter_type, $table, $field);
+ }
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ // --------------------------------------------------------------------
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type']
+ .$field['auto_increment']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
+ }
- if (count($primary_keys) > 0)
- {
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
- }
+ // --------------------------------------------------------------------
- if (is_array($keys) && count($keys) > 0)
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
{
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
- }
+ case 'ENUM':
+ case 'SET':
+ $attributes['TYPE'] = 'TEXT';
+ return;
+ default: return;
}
-
- return $sql."\n)";
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute AUTO_INCREMENT
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
- *
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_auto_increment(&$attributes, &$field)
{
- /* SQLite only supports adding new columns and it does
- * NOT support the AFTER statement. Each new column will
- * be added as the last one in the table.
- */
- if ($alter_type !== 'ADD COLUMN')
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
{
- // Not supported
- return FALSE;
- }
+ $field['type'] = 'INTEGER PRIMARY KEY';
+ $field['default'] = '';
+ $field['null'] = '';
+ $field['unique'] = '';
+ $field['auto_increment'] = ' AUTOINCREMENT';
- return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
- .' '.$column_definition
- .($default_value != '' ? " DEFAULT '".$default_value."'" : '')
- // If NOT NULL is specified, the field must have a DEFAULT value other than NULL
- .(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
+ $this->primary_keys = array();
+ }
}
}
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
index eef9787a1..889757dea 100644
--- a/system/database/drivers/sqlite/sqlite_result.php
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite Result Class
@@ -97,10 +98,8 @@ class CI_DB_sqlite_result extends CI_DB_result {
{
$retval[$i] = new stdClass();
$retval[$i]->name = sqlite_field_name($this->result_id, $i);
- $retval[$i]->type = 'varchar';
- $retval[$i]->max_length = 0;
- $retval[$i]->primary_key = 0;
- $retval[$i]->default = '';
+ $retval[$i]->type = NULL;
+ $retval[$i]->max_length = NULL;
}
return $retval;
@@ -113,11 +112,12 @@ class CI_DB_sqlite_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n
* @return bool
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
return sqlite_seek($this->result_id, $n);
}
@@ -143,7 +143,7 @@ class CI_DB_sqlite_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php
index 1bcb42d9f..222d02712 100644
--- a/system/database/drivers/sqlite/sqlite_utility.php
+++ b/system/database/drivers/sqlite/sqlite_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite Utility Class
@@ -34,18 +35,16 @@
*/
class CI_DB_sqlite_utility extends CI_DB_utility {
- protected $_list_databases = FALSE;
-
/**
- * SQLite Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index cc35d319f..e37268aca 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite3 Database Adapter Class
@@ -41,16 +42,23 @@
*/
class CI_DB_sqlite3_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'sqlite3';
- // The character used for escaping
- protected $_escape_char = '"';
+ // --------------------------------------------------------------------
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = ' ESCAPE \'%s\' ';
- protected $_like_escape_chr = '!';
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('RANDOM()', 'RANDOM()');
- protected $_random_keyword = ' RANDOM()';
+ // --------------------------------------------------------------------
/**
* Non-persistent database connection
@@ -107,13 +115,12 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @todo Implement use of SQLite3::querySingle(), if needed
+ * @param string $sql
* @return mixed SQLite3Result object or bool
*/
protected function _execute($sql)
{
- // TODO: Implement use of SQLite3::querySingle(), if needed
-
return $this->is_write_type($sql)
? $this->conn_id->exec($sql)
: $this->conn_id->query($sql);
@@ -124,6 +131,7 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -183,8 +191,8 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -243,7 +251,7 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* Generates a platform-specific query string so that the table names can be fetched
*
- * @param bool
+ * @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
@@ -261,7 +269,7 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
@@ -273,40 +281,56 @@ class CI_DB_sqlite3_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * Field data query
- *
- * Generates a platform-specific query so that the column data can be retrieved
+ * Returns an object with field data
*
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT * FROM '.$table.' LIMIT 0,1';
- }
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
- // --------------------------------------------------------------------
+ if (($query = $this->query('PRAGMA TABLE_INFO('.$this->protect_identifiers($table, TRUE, NULL, FALSE).')')) === FALSE)
+ {
+ return FALSE;
+ }
- /**
- * The error message string
- *
- * @return string
- */
- protected function _error_message()
- {
- return $this->conn_id->lastErrorMsg();
+ $query = $query->result_array();
+ if (empty($query))
+ {
+ return FALSE;
+ }
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]['name'];
+ $retval[$i]->type = $query[$i]['type'];
+ $retval[$i]->max_length = NULL;
+ $retval[$i]->default = $query[$i]['dflt_value'];
+ $retval[$i]->primary_key = isset($query[$i]['pk']) ? (int) $query[$i]['pk'] : 0;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
/**
- * The error message number
+ * Error
*
- * @return int
+ * Returns an array containing code and message of the last
+ * database error that has occured.
+ *
+ * @return array
*/
- protected function _error_number()
+ public function error()
{
- return $this->conn_id->lastErrorCode();
+ return array('code' => $this->conn_id->lastErrorCode(), 'message' => $this->conn_id->lastErrorMsg());
}
// --------------------------------------------------------------------
@@ -316,9 +340,9 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* Generates a platform-specific replace string from the supplied data
*
- * @param string the table name
- * @param array the insert keys
- * @param array the insert values
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
* @return string
*/
protected function _replace($table, $keys, $values)
@@ -333,10 +357,10 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command, then,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php
index 6a76ba929..e9b91e972 100644
--- a/system/database/drivers/sqlite3/sqlite3_forge.php
+++ b/system/database/drivers/sqlite3/sqlite3_forge.php
@@ -1,8 +1,8 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* 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
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite3 Forge Class
@@ -35,9 +36,43 @@
class CI_DB_sqlite3_forge extends CI_DB_forge {
/**
+ * UNSIGNED support
+ *
+ * @var bool|array
+ */
+ protected $_unsigned = FALSE;
+
+ /**
+ * NULL value representation in CREATE/ALTER TABLE statements
+ *
+ * @var string
+ */
+ protected $_null = 'NULL';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param object &$db Database object
+ * @return void
+ */
+ public function __construct(&$db)
+ {
+ parent::__construct($db);
+
+ if (version_compare($this->db->version(), '3.3', '<'))
+ {
+ $this->create_table_if = FALSE;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Create database
*
- * @param string the database name
+ * @param string $db_name
* @return bool
*/
public function create_database($db_name = '')
@@ -52,7 +87,7 @@ class CI_DB_sqlite3_forge extends CI_DB_forge {
/**
* Drop database
*
- * @param string the database name (ignored)
+ * @param string $db_name (ignored)
* @return bool
*/
public function drop_database($db_name = '')
@@ -84,125 +119,95 @@ class CI_DB_sqlite3_forge extends CI_DB_forge {
// --------------------------------------------------------------------
/**
- * Create Table
+ * ALTER TABLE
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @todo implement drop_column(), modify_column()
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ protected function _alter_table($alter_type, $table, $field)
{
- $sql = 'CREATE TABLE ';
-
- // IF NOT EXISTS added to SQLite in 3.3.0
- if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE)
- {
- $sql .= 'IF NOT EXISTS ';
- }
-
- $sql .= $this->db->escape_identifiers($table).' (';
- $current_field_count = 0;
-
- foreach ($fields as $field => $attributes)
+ if ($alter_type === 'DROP' OR $alter_type === 'CHANGE')
{
- // 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
+ // drop_column():
+ // BEGIN TRANSACTION;
+ // CREATE TEMPORARY TABLE t1_backup(a,b);
+ // INSERT INTO t1_backup SELECT a,b FROM t1;
+ // DROP TABLE t1;
+ // CREATE TABLE t1(a,b);
+ // INSERT INTO t1 SELECT a,b FROM t1_backup;
+ // DROP TABLE t1_backup;
+ // COMMIT;
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
+ return FALSE;
+ }
- $sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ return parent::_alter_table($alter_type, $table, $field);
+ }
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ // --------------------------------------------------------------------
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ /**
+ * Process column
+ *
+ * @param array $field
+ * @return string
+ */
+ protected function _process_column($field)
+ {
+ return $this->db->escape_identifiers($field['name'])
+ .' '.$field['type']
+ .$field['auto_increment']
+ .$field['null']
+ .$field['unique']
+ .$field['default'];
+ }
- if (count($primary_keys) > 0)
- {
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
- }
+ // --------------------------------------------------------------------
- if (is_array($keys) && count($keys) > 0)
+ /**
+ * Field attribute TYPE
+ *
+ * Performs a data type mapping between different databases.
+ *
+ * @param array &$attributes
+ * @return void
+ */
+ protected function _attr_type(&$attributes)
+ {
+ switch (strtoupper($attributes['TYPE']))
{
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->db->escape_identifiers($key));
-
- $sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
- }
+ case 'ENUM':
+ case 'SET':
+ $attributes['TYPE'] = 'TEXT';
+ return;
+ default: return;
}
-
- return $sql."\n)";
}
// --------------------------------------------------------------------
/**
- * Alter table query
- *
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Field attribute AUTO_INCREMENT
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_auto_increment(&$attributes, &$field)
{
- /* SQLite only supports adding new columns and it does
- * NOT support the AFTER statement. Each new column will
- * be added as the last one in the table.
- */
- if ($alter_type !== 'ADD COLUMN')
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
{
- // Not supported
- return FALSE;
- }
+ $field['type'] = 'INTEGER PRIMARY KEY';
+ $field['default'] = '';
+ $field['null'] = '';
+ $field['unique'] = '';
+ $field['auto_increment'] = ' AUTOINCREMENT';
- return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
- .' '.$column_definition
- .($default_value !== '' ? ' DEFAULT '.$default_value : '')
- // If NOT NULL is specified, the field must have a DEFAULT value other than NULL
- .(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
+ $this->primary_keys = array();
+ }
}
}
diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php
index 8e9b9c15f..69c42002c 100644
--- a/system/database/drivers/sqlite3/sqlite3_result.php
+++ b/system/database/drivers/sqlite3/sqlite3_result.php
@@ -1,8 +1,8 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* 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
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite3 Result Class
@@ -37,9 +38,6 @@
*/
class CI_DB_sqlite3_result extends CI_DB_result {
- // num_fields() might be called multiple times, so we'll use this one to cache it's result
- protected $_num_fields;
-
/**
* Number of fields in the result set
*
@@ -47,9 +45,7 @@ class CI_DB_sqlite3_result extends CI_DB_result {
*/
public function num_fields()
{
- return ( ! is_int($this->_num_fields))
- ? $this->_num_fields = $this->result_id->numColumns()
- : $this->_num_fields;
+ return $this->result_id->numColumns();
}
// --------------------------------------------------------------------
@@ -83,15 +79,24 @@ class CI_DB_sqlite3_result extends CI_DB_result {
*/
public function field_data()
{
+ static $data_types = array(
+ SQLITE3_INTEGER => 'integer',
+ SQLITE3_FLOAT => 'float',
+ SQLITE3_TEXT => 'text',
+ SQLITE3_BLOB => 'blob',
+ SQLITE3_NULL => 'null'
+ );
+
$retval = array();
for ($i = 0, $c = $this->num_fields(); $i < $this->num_fields(); $i++)
{
$retval[$i] = new stdClass();
$retval[$i]->name = $this->result_id->columnName($i);
- $retval[$i]->type = 'varchar';
- $retval[$i]->max_length = 0;
- $retval[$i]->primary_key = 0;
- $retval[$i]->default = '';
+
+ $type = $this->result_id->columnType($i);
+ $retval[$i]->type = isset($data_types[$type]) ? $data_types[$type] : $type;
+
+ $retval[$i]->max_length = NULL;
}
return $retval;
@@ -134,7 +139,7 @@ class CI_DB_sqlite3_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
@@ -165,14 +170,15 @@ class CI_DB_sqlite3_result extends CI_DB_result {
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
- * result set starts at zero
+ * result set starts at zero.
*
+ * @param int $n (ignored)
* @return array
*/
- protected function _data_seek($n = 0)
+ public function data_seek($n = 0)
{
// Only resetting to the start of the result set is supported
- return $this->result_id->reset();
+ return ($n > 0) ? FALSE : $this->result_id->reset();
}
}
diff --git a/system/database/drivers/sqlite3/sqlite3_utility.php b/system/database/drivers/sqlite3/sqlite3_utility.php
index 965c838e5..c7736cc6d 100644
--- a/system/database/drivers/sqlite3/sqlite3_utility.php
+++ b/system/database/drivers/sqlite3/sqlite3_utility.php
@@ -1,8 +1,8 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* 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
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLite3 Utility Class
@@ -34,18 +35,16 @@
*/
class CI_DB_sqlite3_utility extends CI_DB_utility {
- protected $_list_databases = FALSE;
-
/**
- * SQLite Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// Not supported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 8bd18bd76..ee9823ed1 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.0.3
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLSRV Database Adapter Class
@@ -40,36 +41,52 @@
*/
class CI_DB_sqlsrv_driver extends CI_DB {
+ /**
+ * Database driver
+ *
+ * @var string
+ */
public $dbdriver = 'sqlsrv';
- // The character used for escaping
- protected $_escape_char = '"';
-
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
+ // --------------------------------------------------------------------
- protected $_random_keyword = ' NEWID()';
+ /**
+ * ORDER BY random keyword
+ *
+ * @var array
+ */
+ protected $_random_keyword = array('NEWID()', 'RAND(%d)');
- // SQLSRV-specific properties
+ /**
+ * Quoted identifier flag
+ *
+ * Whether to use SQL-92 standard quoted identifier
+ * (double quotes) or brackets for identifier escaping.
+ *
+ * @var bool
+ */
protected $_quoted_identifier = TRUE;
+ // --------------------------------------------------------------------
+
/**
- * Non-persistent database connection
+ * Database connection
*
+ * @param bool $pooling
* @return resource
*/
public function db_connect($pooling = FALSE)
{
- // Check for a UTF-8 charset being passed as CI's default 'utf8'.
- $character_set = (0 === strcasecmp('utf8', $this->char_set)) ? 'UTF-8' : $this->char_set;
+ $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE)
+ ? 'UTF-8' : SQLSRV_ENC_CHAR;
$connection = array(
'UID' => empty($this->username) ? '' : $this->username,
'PWD' => empty($this->password) ? '' : $this->password,
'Database' => $this->database,
- 'ConnectionPooling' => $pooling ? 1 : 0,
- 'CharacterSet' => $character_set,
+ 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0,
+ 'CharacterSet' => $charset,
+ 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0,
'ReturnDatesAsStrings' => 1
);
@@ -108,7 +125,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Select the database
*
- * @param string database name
+ * @param string $database
* @return bool
*/
public function db_select($database = '')
@@ -118,7 +135,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
$database = $this->database;
}
- if ($this->_execute('USE '.$database))
+ if ($this->_execute('USE '.$this->escape_identifiers($database)))
{
$this->database = $database;
return TRUE;
@@ -132,7 +149,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Execute the query
*
- * @param string an SQL query
+ * @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
@@ -147,6 +164,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Begin Transaction
*
+ * @param bool $test_mode
* @return bool
*/
public function trans_begin($test_mode = FALSE)
@@ -206,8 +224,8 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Escape String
*
- * @param string
- * @param bool whether or not the string will be used in a LIKE condition
+ * @param string $str
+ * @param bool $like Whether or not the string will be used in a LIKE condition
* @return string
*/
public function escape_str($str, $like = FALSE)
@@ -225,7 +243,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*/
public function affected_rows()
{
- return sqlrv_rows_affected($this->result_id);
+ return sqlsrv_rows_affected($this->result_id);
}
// --------------------------------------------------------------------
@@ -257,8 +275,12 @@ class CI_DB_sqlsrv_driver extends CI_DB {
{
return $this->data_cache['version'];
}
+ elseif ( ! $this->conn_id)
+ {
+ $this->initialize();
+ }
- if (($info = sqlsrv_server_info($this->conn_id)) === FALSE)
+ if ( ! $this->conn_id OR ($info = sqlsrv_server_info($this->conn_id)) === FALSE)
{
return FALSE;
}
@@ -274,7 +296,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
* Generates a platform-specific query string so that the table names can be fetched
*
* @param bool
- * @return string
+ * @return string $prefix_limit
*/
protected function _list_tables($prefix_limit = FALSE)
{
@@ -298,27 +320,52 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*
* Generates a platform-specific query string so that the column names can be fetched
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
- return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
+ return 'SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
}
// --------------------------------------------------------------------
/**
- * Field data query
+ * Returns an object with field data
*
- * Generates a platform-specific query so that the column data can be retrieved
- *
- * @param string the table name
- * @return string
+ * @param string $table
+ * @return array
*/
- protected function _field_data($table)
+ public function field_data($table = '')
{
- return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
+ if ($table === '')
+ {
+ return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+ }
+
+ $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
+ FROM INFORMATION_SCHEMA.Columns
+ WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
+
+ if (($query = $this->query($sql)) === FALSE)
+ {
+ return FALSE;
+ }
+ $query = $query->result_object();
+
+ $retval = array();
+ for ($i = 0, $c = count($query); $i < $c; $i++)
+ {
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $query[$i]->COLUMN_NAME;
+ $retval[$i]->type = $query[$i]->DATA_TYPE;
+ $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
+ $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
+ }
+
+ return $retval;
}
// --------------------------------------------------------------------
@@ -362,49 +409,19 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
- * @param string the table name
- * @param array the update data
- * @param array the where clause
- * @param array the orderby clause (ignored)
- * @param array the limit clause (ignored)
- * @param array the like clause
+ * @param string $table
+ * @param array $values
* @return string
*/
- protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+ protected function _update($table, $values)
{
- foreach ($values as $key => $val)
- {
- $valstr[] = $key.' = '.$val;
- }
-
- $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
-
- if ( ! empty($like))
- {
- $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
- }
-
- return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
+ $this->qb_limit = FALSE;
+ $this->qb_orderby = array();
+ return parent::_update($table, $values);
}
// --------------------------------------------------------------------
@@ -414,10 +431,10 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*
* Generates a platform-specific truncate string from the supplied data
*
- * If the database does not support the truncate() command,
+ * If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
- * @param string the table name
+ * @param string $table
* @return string
*/
protected function _truncate($table)
@@ -432,60 +449,70 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*
* Generates a platform-specific delete string from the supplied data
*
- * @param string the table name
- * @param array the where clause
- * @param array the like clause
- * @param string the limit clause
+ * @param string $table
* @return string
*/
- protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ protected function _delete($table)
{
- $conditions = array();
-
- empty($where) OR $conditions[] = implode(' ', $where);
- empty($like) OR $conditions[] = implode(' ', $like);
-
- $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+ if ($this->qb_limit)
+ {
+ return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
+ }
- return ($limit)
- ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
- : 'DELETE FROM '.$table.$conditions;
+ return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
- * Limit string
+ * LIMIT
*
* Generates a platform-specific LIMIT clause
*
- * @param string the sql query string
- * @param int the number of rows to limit the query to
- * @param int the offset value
+ * @param string $sql SQL Query
* @return string
*/
- protected function _limit($sql, $limit, $offset)
+ protected function _limit($sql)
{
// As of SQL Server 2012 (11.0.*) OFFSET is supported
if (version_compare($this->version(), '11', '>='))
{
- return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+ return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
}
- $limit = $offset + $limit;
+ $limit = $this->qb_offset + $this->qb_limit;
// An ORDER BY clause is required for ROW_NUMBER() to work
- if ($offset && ! empty($this->qb_orderby))
+ if ($this->qb_offset && ! empty($this->qb_orderby))
{
- $orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+ $orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
- $sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
-
- return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
- .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
- ."\n) ".$this->escape_identifiers('CI_subquery')
- ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+ $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
+
+ // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
+ if (count($this->qb_select) === 0)
+ {
+ $select = '*'; // Inevitable
+ }
+ else
+ {
+ // Use only field names and their aliases, everything else is out of our scope.
+ $select = array();
+ $field_regexp = ($this->_quoted_identifier)
+ ? '("[^\"]+")' : '(\[[^\]]+\])';
+ for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
+ {
+ $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
+ ? $m[1] : $this->qb_select[$i];
+ }
+ $select = implode(', ', $select);
+ }
+
+ return 'SELECT '.$select." FROM (\n\n"
+ .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+ ."\n\n) ".$this->escape_identifiers('CI_subquery')
+ ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
@@ -494,6 +521,29 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * Insert batch statement
+ *
+ * Generates a platform-specific insert string from the supplied data.
+ *
+ * @param string $table Table name
+ * @param array $keys INSERT keys
+ * @param array $values INSERT values
+ * @return string|bool
+ */
+ protected function _insert_batch($table, $keys, $values)
+ {
+ // Multiple-value inserts are only supported as of SQL Server 2008
+ if (version_compare($this->version(), '10', '>='))
+ {
+ return parent::_insert_batch($table, $keys, $values);
+ }
+
+ return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index ccdb36929..da8f68c56 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.0.3
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLSRV Forge Class
@@ -34,124 +35,99 @@
*/
class CI_DB_sqlsrv_forge extends CI_DB_forge {
- protected $_drop_table = 'DROP TABLE %s';
-
/**
- * Create Table
+ * CREATE TABLE IF statement
*
- * @param string the table name
- * @param array the fields
- * @param mixed primary key(s)
- * @param mixed key(s)
- * @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return string
+ * @var string
*/
- protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
- {
- $sql = ($if_not_exists === TRUE)
- ? "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'".$table."') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\n"
- : '';
-
- $sql .= 'CREATE TABLE '.$this->db->escape_identifiers($table).' (';
-
- $current_field_count = 0;
- 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
- // entered the field information, so we'll simply add it to the list
- if (is_numeric($field))
- {
- $sql .= "\n\t".$attributes;
- }
- else
- {
- $attributes = array_change_key_case($attributes, CASE_UPPER);
-
- $sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
-
- if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
- {
- $sql .= '('.$attributes['CONSTRAINT'].')';
- }
-
- if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
- {
- $sql .= ' UNSIGNED';
- }
+ protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE";
- if (isset($attributes['DEFAULT']))
- {
- $sql .= " DEFAULT '".$attributes['DEFAULT']."'";
- }
-
- $sql .= ( ! empty($attributes['NULL']) && $attribues['NULL'] === TRUE)
- ? ' NULL' : ' NOT NULL';
+ /**
+ * DROP TABLE IF statement
+ *
+ * @var string
+ */
+ protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE";
- if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
- {
- $sql .= ' AUTO_INCREMENT';
- }
- }
+ /**
+ * UNSIGNED support
+ *
+ * @var array
+ */
+ protected $_unsigned = array(
+ 'TINYINT' => 'SMALLINT',
+ 'SMALLINT' => 'INT',
+ 'INT' => 'BIGINT',
+ 'REAL' => 'FLOAT'
+ );
- // don't add a comma on the end of the last field
- if (++$current_field_count < count($fields))
- {
- $sql .= ',';
- }
- }
+ // --------------------------------------------------------------------
- if (count($primary_keys) > 0)
+ /**
+ * ALTER TABLE
+ *
+ * @param string $alter_type ALTER type
+ * @param string $table Table name
+ * @param mixed $field Column definition
+ * @return string|string[]
+ */
+ protected function _alter_table($alter_type, $table, $field)
+ {
+ if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
{
- $sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+ return parent::_alter_table($alter_type, $table, $field);
}
- if (is_array($keys) && count($keys) > 0)
+ $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN ';
+ $sqls = array();
+ for ($i = 0, $c = count($field); $i < $c; $i++)
{
- foreach ($keys as $key)
- {
- $key = is_array($key)
- ? $this->db->escape_identifiers($key)
- : array($this->escape_identifiers($key));
-
- $sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
- }
+ $sqls[] = $sql.$this->_process_column($field[$i]);
}
- return $sql."\n)";
+ return $sqls;
}
// --------------------------------------------------------------------
/**
- * Alter table query
+ * Field attribute TYPE
*
- * Generates a platform-specific query so that a table can be altered
- * Called by add_column(), drop_column(), and column_alter(),
+ * Performs a data type mapping between different databases.
*
- * @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 bool should 'NOT NULL' be added
- * @param string the field after which we should add the new field
- * @return string
+ * @param array &$attributes
+ * @return void
*/
- protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+ protected function _attr_type(&$attributes)
{
- $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
-
- // DROP has everything it needs now.
- if ($alter_type === 'DROP')
+ switch (strtoupper($attributes['TYPE']))
{
- return $sql;
+ case 'MEDIUMINT':
+ $attributes['TYPE'] = 'INTEGER';
+ $attributes['UNSIGNED'] = FALSE;
+ return;
+ case 'INTEGER':
+ $attributes['TYPE'] = 'INT';
+ return;
+ default: return;
}
+ }
- return $sql.' '.$column_definition
- .($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
- .($null === NULL ? ' NULL' : ' NOT NULL')
- .($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ // --------------------------------------------------------------------
+
+ /**
+ * Field attribute AUTO_INCREMENT
+ *
+ * @param array &$attributes
+ * @param array &$field
+ * @return void
+ */
+ protected function _attr_auto_increment(&$attributes, &$field)
+ {
+ if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
+ {
+ $field['auto_increment'] = ' IDENTITY(1,1)';
+ }
}
}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index fb7a68647..b084b84cd 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLSRV Result Class
@@ -93,16 +94,12 @@ class CI_DB_sqlsrv_result extends CI_DB_result {
public function field_data()
{
$retval = array();
- foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field)
+ foreach (sqlsrv_field_metadata($this->result_id) as $i => $field)
{
- $F = new stdClass();
- $F->name = $field['Name'];
- $F->type = $field['Type'];
- $F->max_length = $field['Size'];
- $F->primary_key = 0;
- $F->default = '';
-
- $retval[] = $F;
+ $retval[$i] = new stdClass();
+ $retval[$i]->name = $field['Name'];
+ $retval[$i]->type = $field['Type'];
+ $retval[$i]->max_length = $field['Size'];
}
return $retval;
@@ -145,7 +142,7 @@ class CI_DB_sqlsrv_result extends CI_DB_result {
*
* Returns the result set as an object
*
- * @param string
+ * @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php
index d518cc15a..2bc7f9e03 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_utility.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 2.0.3
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* SQLSRV Utility Class
@@ -34,19 +35,32 @@
*/
class CI_DB_sqlsrv_utility extends CI_DB_utility {
+ /**
+ * List databases statement
+ *
+ * @var string
+ */
protected $_list_databases = 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases
+
+ /**
+ * OPTIMIZE TABLE statement
+ *
+ * @var string
+ */
protected $_optimize_table = 'ALTER INDEX all ON %s REORGANIZE';
+ // --------------------------------------------------------------------
+
/**
- * SQLSRV Export
+ * Export
*
- * @param array Preferences
+ * @param array $params Preferences
* @return bool
*/
protected function _backup($params = array())
{
// Currently unsupported
- return $this->db->display_error('db_unsuported_feature');
+ return $this->db->display_error('db_unsupported_feature');
}
}