summaryrefslogtreecommitdiffstats
path: root/system/database
diff options
context:
space:
mode:
authorAndrey Andreev <narf@bofh.bg>2012-04-03 19:54:49 +0200
committerAndrey Andreev <narf@bofh.bg>2012-04-03 19:54:49 +0200
commitfd105ab7f05e64c0d9188e43c6fd6a2bb2c6cf7f (patch)
treed16dc16ae5e81f6171a18b3278d48038406937bd /system/database
parent5b46f42d654e7474a47ecfd9f7dafece98ee668e (diff)
parentab1d568b7b7bce779cd00c90cd99c6f43747575b (diff)
Merge branch 'develop' of github.com:EllisLab/CodeIgniter into develop-db-postgre
Diffstat (limited to 'system/database')
-rwxr-xr-xsystem/database/DB.php17
-rw-r--r--system/database/DB_cache.php2
-rw-r--r--system/database/DB_driver.php2
-rw-r--r--system/database/drivers/mysql/mysql_forge.php2
-rw-r--r--system/database/drivers/mysqli/mysqli_forge.php2
-rw-r--r--system/database/drivers/oci8/oci8_driver.php139
-rw-r--r--system/database/drivers/oci8/oci8_forge.php38
-rw-r--r--system/database/drivers/oci8/oci8_result.php526
-rw-r--r--system/database/drivers/oci8/oci8_utility.php11
-rw-r--r--system/database/drivers/postgre/postgre_driver.php6
-rw-r--r--system/database/drivers/sqlite3/index.html10
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php521
-rw-r--r--system/database/drivers/sqlite3/sqlite3_forge.php223
-rw-r--r--system/database/drivers/sqlite3/sqlite3_result.php619
-rw-r--r--system/database/drivers/sqlite3/sqlite3_utility.php103
15 files changed, 2060 insertions, 161 deletions
diff --git a/system/database/DB.php b/system/database/DB.php
index 96e495515..0d81e40d3 100755
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -92,16 +92,12 @@ function &DB($params = '', $active_record_override = NULL)
if (isset($dsn['query']))
{
parse_str($dsn['query'], $extra);
+
foreach ($extra as $key => $val)
{
- // booleans please
- if (strtoupper($val) === 'TRUE')
- {
- $val = TRUE;
- }
- elseif (strtoupper($val) === 'FALSE')
+ if (is_string($val) && in_array(strtoupper($val), array('TRUE', 'FALSE', 'NULL')))
{
- $val = FALSE;
+ $val = var_export($val);
}
$params[$key] = $val;
@@ -138,7 +134,12 @@ function &DB($params = '', $active_record_override = NULL)
class CI_DB extends CI_DB_driver { }
}
- require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php');
+ // Load the DB driver
+ $driver_file = BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php';
+
+ if ( ! file_exists($driver_file)) show_error('Invalid DB driver');
+
+ require_once($driver_file);
// Instantiate the DB adapter
$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index 58e6968c0..ff942856b 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -177,7 +177,7 @@ class CI_DB_Cache {
*/
public function delete_all()
{
- delete_files($this->db->cachedir, TRUE);
+ delete_files($this->db->cachedir, TRUE, 0, TRUE);
}
}
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 45f17e8ec..dea705054 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -407,8 +407,6 @@ abstract class CI_DB_driver {
$driver = $this->load_rdriver();
$RES = new $driver($this);
- $RES->num_rows = $RES->num_rows();
-
// Is query caching enabled? If so, we'll serialize the
// result object and save it to a cache file.
if ($this->cache_on == TRUE && $this->_cache_init())
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index 11172b41b..9e19de1bb 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -42,7 +42,7 @@ class CI_DB_mysql_forge extends CI_DB_forge {
*/
public function _create_database($name)
{
- return 'CREATE DATABASE '.$name;
+ return 'CREATE DATABASE '.$name.' CHARACTER SET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index 8cf0ae1fd..a1caf5cfb 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -42,7 +42,7 @@ class CI_DB_mysqli_forge extends CI_DB_forge {
*/
public function _create_database($name)
{
- return 'CREATE DATABASE '.$name;
+ return 'CREATE DATABASE '.$name.' CHARACTER SET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 45b0198eb..0a96f3f6d 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -46,7 +46,6 @@
* permit access to oracle databases
*
* @author Kelly McArdle
- *
*/
class CI_DB_oci8_driver extends CI_DB {
@@ -68,7 +67,7 @@ class CI_DB_oci8_driver extends CI_DB {
protected $_random_keyword = ' ASC'; // not currently supported
// Set "auto commit" by default
- protected $_commit = OCI_COMMIT_ON_SUCCESS;
+ public $commit_mode = OCI_COMMIT_ON_SUCCESS;
// need to track statement id and cursor id
public $stmt_id;
@@ -207,12 +206,13 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _execute($sql)
{
- // oracle must parse the query before it is run. All of the actions with
- // the query are based on the statement id returned by ociparse
+ /* Oracle must parse the query before it is run. All of the actions with
+ * the query are based on the statement id returned by oci_parse().
+ */
$this->stmt_id = FALSE;
$this->_set_stmt_id($sql);
oci_set_prefetch($this->stmt_id, 1000);
- return @oci_execute($this->stmt_id, $this->_commit);
+ return @oci_execute($this->stmt_id, $this->commit_mode);
}
/**
@@ -238,8 +238,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
public function get_cursor()
{
- $this->curs_id = oci_new_cursor($this->conn_id);
- return $this->curs_id;
+ return $this->curs_id = oci_new_cursor($this->conn_id);
}
// --------------------------------------------------------------------
@@ -247,19 +246,19 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Stored Procedure. Executes a stored procedure
*
- * @param string package stored procedure is in
- * @param string stored procedure to execute
+ * @param string package name in which the stored procedure is in
+ * @param string stored procedure name to execute
* @param array parameters
- * @return object
+ * @return mixed
*
* params array keys
*
* KEY OPTIONAL NOTES
- * name no the name of the parameter should be in :<param_name> format
- * value no the value of the parameter. If this is an OUT or IN OUT parameter,
- * this should be a reference to a variable
- * type yes the type of the parameter
- * length yes the max size of the parameter
+ * name no the name of the parameter should be in :<param_name> format
+ * value no the value of the parameter. If this is an OUT or IN OUT parameter,
+ * this should be a reference to a variable
+ * type yes the type of the parameter
+ * length yes the max size of the parameter
*/
public function stored_procedure($package, $procedure, $params)
{
@@ -274,24 +273,24 @@ class CI_DB_oci8_driver extends CI_DB {
}
// build the query string
- $sql = "begin $package.$procedure(";
+ $sql = 'BEGIN '.$package.'.'.$procedure.'(';
$have_cursor = FALSE;
foreach ($params as $param)
{
- $sql .= $param['name'] . ",";
+ $sql .= $param['name'].',';
- if (array_key_exists('type', $param) && ($param['type'] === OCI_B_CURSOR))
+ if (isset($param['type']) && $param['type'] === OCI_B_CURSOR)
{
$have_cursor = TRUE;
}
}
- $sql = trim($sql, ",") . "); end;";
+ $sql = trim($sql, ',') . '); END;';
$this->stmt_id = FALSE;
$this->_set_stmt_id($sql);
$this->_bind_params($params);
- $this->query($sql, FALSE, $have_cursor);
+ return $this->query($sql, FALSE, $have_cursor);
}
// --------------------------------------------------------------------
@@ -347,7 +346,7 @@ class CI_DB_oci8_driver extends CI_DB {
// even if the queries produce a successful result.
$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
- $this->_commit = OCI_DEFAULT;
+ $this->commit_mode = (is_php('5.3.2')) ? OCI_NO_AUTO_COMMIT : OCI_DEFAULT;
return TRUE;
}
@@ -371,9 +370,8 @@ class CI_DB_oci8_driver extends CI_DB {
return TRUE;
}
- $ret = oci_commit($this->conn_id);
- $this->_commit = OCI_COMMIT_ON_SUCCESS;
- return $ret;
+ $this->commit_mode = OCI_COMMIT_ON_SUCCESS;
+ return oci_commit($this->conn_id);
}
// --------------------------------------------------------------------
@@ -385,20 +383,14 @@ class CI_DB_oci8_driver extends CI_DB {
*/
public function trans_rollback()
{
- if ( ! $this->trans_enabled)
- {
- return TRUE;
- }
-
// When transactions are nested we only begin/commit/rollback the outermost ones
- if ($this->_trans_depth > 0)
+ if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
{
return TRUE;
}
- $ret = oci_rollback($this->conn_id);
- $this->_commit = OCI_COMMIT_ON_SUCCESS;
- return $ret;
+ $this->commit_mode = OCI_COMMIT_ON_SUCCESS;
+ return oci_rollback($this->conn_id);
}
// --------------------------------------------------------------------
@@ -469,7 +461,7 @@ class CI_DB_oci8_driver extends CI_DB {
* the specified database
*
* @param string
- * @return string
+ * @return int
*/
public function count_all($table = '')
{
@@ -501,11 +493,11 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _list_tables($prefix_limit = FALSE)
{
- $sql = "SELECT TABLE_NAME FROM ALL_TABLES";
+ $sql = 'SELECT TABLE_NAME FROM ALL_TABLES';
- if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+ if ($prefix_limit !== FALSE && $this->dbprefix != '')
{
- $sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+ return $sql." WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
return $sql;
@@ -523,7 +515,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _list_columns($table = '')
{
- return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
+ return 'SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = \''.$table.'\'';
}
// --------------------------------------------------------------------
@@ -538,7 +530,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _field_data($table)
{
- return "SELECT * FROM ".$table." where rownum = 1";
+ return 'SELECT * FROM '.$table.' WHERE rownum = 1';
}
// --------------------------------------------------------------------
@@ -593,24 +585,20 @@ class CI_DB_oci8_driver extends CI_DB {
{
if (strpos($item, '.'.$id) !== FALSE)
{
- $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
+ $item = str_replace('.', $this->_escape_char.'.', $item);
// remove duplicates if the user already included the escape
- return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+ return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
}
}
if (strpos($item, '.') !== FALSE)
{
- $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
- }
- else
- {
- $str = $this->_escape_char.$item.$this->_escape_char;
+ $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
}
// remove duplicates if the user already included the escape
- return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+ return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
}
// --------------------------------------------------------------------
@@ -626,12 +614,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _from_tables($tables)
{
- if ( ! is_array($tables))
- {
- $tables = array($tables);
- }
-
- return implode(', ', $tables);
+ return is_array($tables) ? implode(', ', $tables) : $tables;
}
// --------------------------------------------------------------------
@@ -648,7 +631,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _insert($table, $keys, $values)
{
- return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+ return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
}
// --------------------------------------------------------------------
@@ -670,12 +653,10 @@ class CI_DB_oci8_driver extends CI_DB {
for ($i = 0, $c = count($values); $i < $c; $i++)
{
- $sql .= ' INTO ' . $table . ' (' . $keys . ') VALUES ' . $values[$i] . "\n";
+ $sql .= ' INTO '.$table.' ('.$keys.') VALUES '.$values[$i].'\n';
}
- $sql .= 'SELECT * FROM dual';
-
- return $sql;
+ return $sql.'SELECT * FROM dual';
}
// --------------------------------------------------------------------
@@ -696,20 +677,13 @@ class CI_DB_oci8_driver extends CI_DB {
{
foreach ($values as $key => $val)
{
- $valstr[] = $key." = ".$val;
+ $valstr[] = $key.' = '.$val;
}
- $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
- $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
- $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
- $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
- $sql .= $orderby.$limit;
-
- return $sql;
+ return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
+ .(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
+ .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
+ .( ! $limit ? '' : ' LIMIT '.$limit);
}
// --------------------------------------------------------------------
@@ -726,7 +700,7 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _truncate($table)
{
- return "TRUNCATE TABLE ".$table;
+ return 'TRUNCATE TABLE '.$table;
}
// --------------------------------------------------------------------
@@ -744,22 +718,18 @@ class CI_DB_oci8_driver extends CI_DB {
protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
{
$conditions = '';
-
if (count($where) > 0 OR count($like) > 0)
{
- $conditions = "\nWHERE ";
- $conditions .= implode("\n", $this->ar_where);
+ $conditions = "\nWHERE ".implode("\n", $this->ar_where);
if (count($where) > 0 && count($like) > 0)
{
- $conditions .= " AND ";
+ $conditions .= ' AND ';
}
$conditions .= implode("\n", $like);
}
- $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
- return "DELETE FROM ".$table.$conditions.$limit;
+ return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
}
// --------------------------------------------------------------------
@@ -776,18 +746,9 @@ class CI_DB_oci8_driver extends CI_DB {
*/
protected function _limit($sql, $limit, $offset)
{
- $limit = $offset + $limit;
- $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
-
- if ($offset != 0)
- {
- $newsql .= " WHERE rnum >= $offset";
- }
-
- // remember that we used limits
$this->limit_used = TRUE;
-
- return $newsql;
+ return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit).')'
+ .($offset != 0 ? ' WHERE rnum >= '.$offset : '');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 8285a29d2..4b2eccae5 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -42,6 +42,7 @@ class CI_DB_oci8_forge extends CI_DB_forge {
*/
public function _create_database($name)
{
+ // Not supported - schemas in Oracle are actual usernames
return FALSE;
}
@@ -55,6 +56,7 @@ class CI_DB_oci8_forge extends CI_DB_forge {
*/
public function _drop_database($name)
{
+ // Not supported - schemas in Oracle are actual usernames
return FALSE;
}
@@ -68,7 +70,7 @@ class CI_DB_oci8_forge extends CI_DB_forge {
* @param mixed primary key(s)
* @param mixed key(s)
* @param bool should 'IF NOT EXISTS' be added to the SQL
- * @return bool
+ * @return string
*/
public function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
{
@@ -128,7 +130,7 @@ class CI_DB_oci8_forge extends CI_DB_forge {
$key = array($this->db->protect_identifiers($key));
}
- $sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).")";
+ $sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')';
}
}
@@ -140,11 +142,11 @@ class CI_DB_oci8_forge extends CI_DB_forge {
/**
* Drop Table
*
- * @return bool
+ * @return string
*/
public function _drop_table($table)
{
- return FALSE;
+ return 'DROP TABLE '.$this->db->protect_identifiers($table);
}
// --------------------------------------------------------------------
@@ -169,33 +171,15 @@ class CI_DB_oci8_forge extends CI_DB_forge {
$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
// DROP has everything it needs now.
- if ($alter_type == 'DROP')
+ if ($alter_type === 'DROP')
{
return $sql;
}
- $sql .= " $column_definition";
-
- if ($default_value != '')
- {
- $sql .= " DEFAULT \"$default_value\"";
- }
-
- if ($null === NULL)
- {
- $sql .= ' NULL';
- }
- else
- {
- $sql .= ' NOT NULL';
- }
-
- if ($after_field != '')
- {
- return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
- }
-
- return $sql;
+ return $sql.' '.$column_definition
+ .($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+ .($null === NULL ? ' NULL' : ' NOT NULL')
+ .($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
}
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index c3f775730..aad24cfd9 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -39,6 +39,12 @@ class CI_DB_oci8_result extends CI_DB_result {
public $stmt_id;
public $curs_id;
public $limit_used;
+ public $commit_mode;
+
+ /* Overwriting the parent here, so we have a way to know if it's
+ * already called or not:
+ */
+ public $num_rows;
public function __construct(&$driver_object)
{
@@ -46,28 +52,32 @@ class CI_DB_oci8_result extends CI_DB_result {
$this->stmt_id = $driver_object->stmt_id;
$this->curs_id = $driver_object->curs_id;
$this->limit_used = $driver_object->limit_used;
+ $this->commit_mode =& $driver_object->commit_mode;
$driver_object->stmt_id = FALSE;
}
/**
* Number of rows in the result set.
*
- * Oracle doesn't have a graceful way to retun the number of rows
+ * Oracle doesn't have a graceful way to return the number of rows
* so we have to use what amounts to a hack.
*
* @return int
*/
public function num_rows()
{
- if ($this->num_rows === 0 && count($this->result_array()) > 0)
+ if ( ! is_int($this->num_rows))
{
- $this->num_rows = count($this->result_array());
- @oci_execute($this->stmt_id, OCI_DEFAULT);
-
- if ($this->curs_id)
+ if (count($this->result_array) > 0)
+ {
+ return $this->num_rows = count($this->result_array);
+ }
+ elseif (count($this->result_object) > 0)
{
- @oci_execute($this->curs_id, OCI_DEFAULT);
+ return $this->num_rows = count($this->result_object);
}
+
+ return $this->num_rows = count($this->result_array());
}
return $this->num_rows;
@@ -85,12 +95,7 @@ class CI_DB_oci8_result extends CI_DB_result {
$count = @oci_num_fields($this->stmt_id);
// if we used a limit we subtract it
- if ($this->limit_used)
- {
- $count = $count - 1;
- }
-
- return $count;
+ return ($this->limit_used) ? $count - 1 : $count;
}
// --------------------------------------------------------------------
@@ -126,10 +131,10 @@ class CI_DB_oci8_result extends CI_DB_result {
$retval = array();
for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++)
{
- $F = new stdClass();
- $F->name = oci_field_name($this->stmt_id, $c);
- $F->type = oci_field_type($this->stmt_id, $c);
- $F->max_length = oci_field_size($this->stmt_id, $c);
+ $F = new stdClass();
+ $F->name = oci_field_name($this->stmt_id, $c);
+ $F->type = oci_field_type($this->stmt_id, $c);
+ $F->max_length = oci_field_size($this->stmt_id, $c);
$retval[] = $F;
}
@@ -151,6 +156,17 @@ class CI_DB_oci8_result extends CI_DB_result {
oci_free_statement($this->result_id);
$this->result_id = FALSE;
}
+
+ if (is_resource($this->stmt_id))
+ {
+ oci_free_statement($this->stmt_id);
+ }
+
+ if (is_resource($this->curs_id))
+ {
+ oci_cancel($this->curs_id);
+ $this->curs_id = NULL;
+ }
}
// --------------------------------------------------------------------
@@ -180,13 +196,13 @@ class CI_DB_oci8_result extends CI_DB_result {
protected function _fetch_object()
{
$id = ($this->curs_id) ? $this->curs_id : $this->stmt_id;
- return @oci_fetch_object($id);
+ return oci_fetch_object($id);
}
// --------------------------------------------------------------------
/**
- * Query result. "array" version.
+ * Query result. Array version.
*
* @return array
*/
@@ -196,14 +212,433 @@ class CI_DB_oci8_result extends CI_DB_result {
{
return $this->result_array;
}
+ elseif (count($this->result_object) > 0)
+ {
+ for ($i = 0, $c = count($this->result_object); $i < $c; $i++)
+ {
+ $this->result_array[$i] = (array) $this->result_object[$i];
+ }
+
+ return $this->result_array;
+ }
+ elseif (is_array($this->row_data))
+ {
+ if (count($this->row_data) === 0)
+ {
+ return $this->result_array;
+ }
+ else
+ {
+ $row_index = count($this->row_data);
+ }
+ }
+ else
+ {
+ $row_index = 0;
+ $this->row_data = array();
+ }
$row = NULL;
while ($row = $this->_fetch_assoc())
{
- $this->result_array[] = $row;
+ $this->row_data[$row_index++] = $row;
+ }
+
+ // Un-comment the following line, in case it becomes needed
+ // $this->_data_seek();
+ return $this->result_array = $this->row_data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Query result. "object" version.
+ *
+ * @return array
+ */
+ public function result_object()
+ {
+ if (count($this->result_object) > 0)
+ {
+ return $this->result_object;
+ }
+ elseif (count($this->result_array) > 0)
+ {
+ for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
+ {
+ $this->result_object[] = (object) $this->result_array[$i];
+ }
+
+ return $this->result_object;
+ }
+ elseif (is_array($this->row_data))
+ {
+ if (count($this->row_data) === 0)
+ {
+ return $this->result_object;
+ }
+ else
+ {
+ $row_index = count($this->row_data);
+ for ($i = 0; $i < $row_index; $i++)
+ {
+ $this->result_object[$i] = (object) $this->row_data[$i];
+ }
+ }
+ }
+ else
+ {
+ $row_index = 0;
+ $this->row_data = array();
+ }
+
+ $row = NULL;
+ while ($row = $this->_fetch_object())
+ {
+ $this->row_data[$row_index] = (array) $row;
+ $this->result_object[$row_index++] = $row;
+ }
+
+ // Un-comment the following line, in case it becomes needed
+ // $this->_data_seek();
+ return $this->result_object;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Query result. Custom object version.
+ *
+ * @param string class name used to instantiate rows to
+ * @return array
+ */
+ public function custom_result_object($class_name)
+ {
+ if (isset($this->custom_result_object[$class_name]))
+ {
+ return $this->custom_result_object[$class_name];
+ }
+
+ if ( ! class_exists($class_name) OR $this->result_id === FALSE OR $this->num_rows() === 0)
+ {
+ return array();
+ }
+
+ /* Even if we didn't have result_array or result_object
+ * set prior to custom_result_object() being called,
+ * num_rows() has already done so.
+ * Pass by reference, as we don't know how
+ * large it might be and we don't want 1000 row
+ * sets being copied.
+ */
+ if (count($this->result_array) > 0)
+ {
+ $data = &$this->result_array;
+ }
+ elseif (count($this->result_object) > 0)
+ {
+ $data = &$this->result_object;
+ }
+
+ $this->custom_result_object[$class_name] = array();
+ for ($i = 0, $c = count($data); $i < $c; $i++)
+ {
+ $this->custom_result_object[$class_name][$i] = new $class_name();
+ foreach ($data[$i] as $key => $value)
+ {
+ $this->custom_result_object[$class_name][$i]->$key = $value;
+ }
+ }
+
+ return $this->custom_result_object[$class_name];
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result.
+ *
+ * Acts as a wrapper for row_object(), row_array()
+ * and custom_row_object(). Also used by first_row(), next_row()
+ * and previous_row().
+ *
+ * @param int row index
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function row($n = 0, $type = 'object')
+ {
+ if ($type === 'object')
+ {
+ return $this->row_object($n);
+ }
+ elseif ($type === 'array')
+ {
+ return $this->row_array($n);
+ }
+
+ return $this->custom_row_object($n, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Array version.
+ *
+ * @param int row index
+ * @return array
+ */
+ public function row_array($n = 0)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+
+ /* If row_data is initialized, it means that we've already tried
+ * (at least) to fetch some data, so ... check if we already have
+ * this row.
+ */
+ if (is_array($this->row_data))
+ {
+ /* If we already have row_data[$n] - return it.
+ *
+ * If we enter the elseif, there's a number of reasons to
+ * return an empty array:
+ *
+ * - count($this->row_data) === 0 means there are no results
+ * - num_rows being set, result_array and/or result_object
+ * having count() > 0 means that we've already fetched all
+ * data and $n is greater than our highest row index available
+ * - $n < $this->current_row means that if such row existed,
+ * we would've already returned it, therefore $n is an
+ * invalid index
+ */
+ if (isset($this->row_data[$n])) // We already have this row
+ {
+ $this->current_row = $n;
+ return $this->row_data[$n];
+ }
+ elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
+ OR count($this->result_array) > 0 OR count($this->result_object) > 0
+ OR $n < $this->current_row)
+ {
+ // No such row exists
+ return array();
+ }
+
+ // Get the next row index that would actually need to be fetched
+ $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
+ }
+ else
+ {
+ $current_row = $this->current_row = 0;
+ $this->row_data = array();
+ }
+
+ /* Fetch more data, if available
+ *
+ * NOTE: Operator precedence is important here, if you change
+ * 'AND' with '&&' - it WILL BREAK the results, as
+ * $row will be assigned the scalar value of both
+ * expressions!
+ */
+ while ($row = $this->_fetch_assoc() AND $current_row <= $n)
+ {
+ $this->row_data[$current_row++] = $row;
}
- return $this->result_array;
+ // This would mean that there's no (more) data to fetch
+ if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
+ {
+ // Cache what we already have
+ if (is_array($this->row_data))
+ {
+ $this->num_rows = count($this->row_data);
+ /* Usually, row_data could have less elements than result_array,
+ * but at this point - they should be exactly the same.
+ */
+ $this->result_array = $this->row_data;
+ }
+ else
+ {
+ $this->num_rows = 0;
+ }
+
+ return array();
+ }
+
+ $this->current_row = $n;
+ return $this->row_data[$n];
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Object version.
+ *
+ * @param int row index
+ * @return mixed object if row found; empty array if not
+ */
+ public function row_object($n = 0)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+ /* Logic here is exactly the same as in row_array,
+ * except we have to cast row_data[$n] to an object.
+ *
+ * If we already have result_object though - we can
+ * directly return from it.
+ */
+ if (isset($this->result_object[$n]))
+ {
+ $this->current_row = $n;
+ // Set this, if not already done.
+ if ( ! is_int($this->num_rows))
+ {
+ $this->num_rows = count($this->result_object);
+ }
+
+ return $this->result_object[$n];
+ }
+
+ $row = $this->row_array($n);
+ // Cast only if the row exists
+ if (count($row) > 0)
+ {
+ $this->current_row = $n;
+ return (object) $row;
+ }
+
+ return array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Custom object version.
+ *
+ * @param int row index
+ * @param string custom class name
+ * @return mixed custom object if row found; empty array otherwise
+ */
+ public function custom_row_object($n = 0, $class_name)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+
+ if (array_key_exists($class_name, $this->custom_result_object))
+ {
+ /* We already have a the whole result set with this class_name,
+ * return the specified row if it exists, and an empty array if
+ * it doesn't.
+ */
+ if (isset($this->custom_result_object[$class_name][$n]))
+ {
+ $this->current_row = $n;
+ return $this->custom_result_object[$class_name][$n];
+ }
+ else
+ {
+ return array();
+ }
+ }
+ elseif ( ! class_exists($class_name)) // No such class exists
+ {
+ return array();
+ }
+
+ $row = $this->row_array($n);
+ // An array would mean that the row doesn't exist
+ if (is_array($row))
+ {
+ return $row;
+ }
+
+ // Convert to the desired class and return
+ $row_object = new $class_name();
+ foreach ($row as $key => $value)
+ {
+ $row_object->$key = $value;
+ }
+
+ $this->current_row = $n;
+ return $row_object;
+ }
+
+ // --------------------------------------------------------------------
+
+ /* First row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function first_row($type = 'object')
+ {
+ return $this->row(0, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Last row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function last_row($type = 'object')
+ {
+ $result = &$this->result($type);
+ if ( ! isset($this->num_rows))
+ {
+ $this->num_rows = count($result);
+ }
+ $this->current_row = $this->num_rows - 1;
+ return $result[$this->current_row];
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Next row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function next_row($type = 'object')
+ {
+ if (is_array($this->row_data))
+ {
+ $count = count($this->row_data);
+ if ($this->current_row > $count OR ($this->current_row === 0 && $count === 0))
+ {
+ $n = $count;
+ }
+ else
+ {
+ $n = $this->current_row + 1;
+ }
+ }
+ else
+ {
+ $n = 0;
+ }
+
+ return $this->row($n, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Previous row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function previous_row($type = 'object')
+ {
+ $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
+ return $this->row($n, $type);
}
// --------------------------------------------------------------------
@@ -213,13 +648,54 @@ class CI_DB_oci8_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.
*
- * @return array
+ * 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($n = 0)
+ protected function _data_seek()
{
- return FALSE; // Not needed
+ /* 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;
}
}
diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php
index e303fb6cb..efb4bca02 100644
--- a/system/database/drivers/oci8/oci8_utility.php
+++ b/system/database/drivers/oci8/oci8_utility.php
@@ -37,11 +37,14 @@ class CI_DB_oci8_utility extends CI_DB_utility {
/**
* List databases
*
- * @return bool
+ * Generates a platform-specific query so that we get a list of schemas
+ * Those are actually usernames in Oracle.
+ *
+ * @return string
*/
public function _list_databases()
{
- return FALSE;
+ return 'SELECT username FROM dba_users';
}
// --------------------------------------------------------------------
@@ -56,7 +59,7 @@ class CI_DB_oci8_utility extends CI_DB_utility {
*/
public function _optimize_table($table)
{
- return FALSE; // Is this supported in Oracle?
+ return FALSE; // Not supported in Oracle
}
// --------------------------------------------------------------------
@@ -71,7 +74,7 @@ class CI_DB_oci8_utility extends CI_DB_utility {
*/
public function _repair_table($table)
{
- return FALSE; // Is this supported in Oracle?
+ return FALSE; // Not supported in Oracle
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 95d635aae..d92110e3b 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -80,16 +80,16 @@ class CI_DB_postgre_driver extends CI_DB {
$this->port = '';
}
- $this->hostname === '' OR $this->dsn = 'host='.$this->hostname;
+ $this->hostname === '' OR $this->dsn = 'host='.$this->hostname.' ';
if ( ! empty($this->port) && ctype_digit($this->port))
{
- $this->dsn .= 'host='.$this->port.' ';
+ $this->dsn .= 'port='.$this->port.' ';
}
if ($this->username !== '')
{
- $this->dsn .= 'username='.$this->username.' ';
+ $this->dsn .= 'user='.$this->username.' ';
/* An empty password is valid!
*
diff --git a/system/database/drivers/sqlite3/index.html b/system/database/drivers/sqlite3/index.html
new file mode 100644
index 000000000..c942a79ce
--- /dev/null
+++ b/system/database/drivers/sqlite3/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/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
new file mode 100644
index 000000000..de3705296
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -0,0 +1,521 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * 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 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package CodeIgniter
+ * @subpackage Drivers
+ * @category Database
+ * @author Andrey Andreev
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_driver extends CI_DB {
+
+ 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 = '!';
+
+ /**
+ * 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.
+ */
+ protected $_count_string = 'SELECT COUNT(*) AS ';
+ protected $_random_keyword = ' RANDOM()';
+
+ /**
+ * Non-persistent database connection
+ *
+ * @return object type SQLite3
+ */
+ public function db_connect()
+ {
+ try
+ {
+ return ( ! $this->password)
+ ? new SQLite3($this->database)
+ : new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password);
+ }
+ catch (Exception $e)
+ {
+ return FALSE;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Persistent database connection
+ *
+ * @return object type SQLite3
+ */
+ public function db_pconnect()
+ {
+ log_message('debug', 'SQLite3 doesn\'t support persistent connections');
+ return $this->db_pconnect();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Database version number
+ *
+ * @return string
+ */
+ public function version()
+ {
+ if (isset($this->data_cache['version']))
+ {
+ return $this->data_cache['version'];
+ }
+
+ $version = $this->conn_id->version();
+ return $this->data_cache['version'] = $version['versionString'];
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Execute the query
+ *
+ * @param string an SQL query
+ * @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);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Begin Transaction
+ *
+ * @return bool
+ */
+ public function trans_begin($test_mode = FALSE)
+ {
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ {
+ return TRUE;
+ }
+
+ // Reset the transaction failure flag.
+ // If the $test_mode flag is set to TRUE transactions will be rolled back
+ // even if the queries produce a successful result.
+ $this->_trans_failure = ($test_mode === TRUE);
+
+ return $this->conn_id->exec('BEGIN TRANSACTION');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Commit Transaction
+ *
+ * @return bool
+ */
+ public function trans_commit()
+ {
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ {
+ return TRUE;
+ }
+
+ return $this->conn_id->exec('END TRANSACTION');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Rollback Transaction
+ *
+ * @return bool
+ */
+ public function trans_rollback()
+ {
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ {
+ return TRUE;
+ }
+
+ return $this->conn_id->exec('ROLLBACK');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Escape String
+ *
+ * @param string
+ * @param bool whether or not the string will be used in a LIKE condition
+ * @return string
+ */
+ public function escape_str($str, $like = FALSE)
+ {
+ if (is_array($str))
+ {
+ foreach ($str as $key => $val)
+ {
+ $str[$key] = $this->escape_str($val, $like);
+ }
+
+ return $str;
+ }
+
+ $str = $this->conn_id->escapeString(remove_invisible_characters($str));
+
+ // escape LIKE condition wildcards
+ if ($like === TRUE)
+ {
+ return str_replace(array($this->_like_escape_chr, '%', '_'),
+ array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+ $str);
+ }
+
+ return $str;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Affected Rows
+ *
+ * @return int
+ */
+ public function affected_rows()
+ {
+ return $this->conn_id->changes();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert ID
+ *
+ * @return int
+ */
+ public function insert_id()
+ {
+ return $this->conn_id->lastInsertRowID();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * "Count All" query
+ *
+ * Generates a platform-specific query string that counts all records in
+ * the specified database
+ *
+ * @param string
+ * @return int
+ */
+ public function count_all($table = '')
+ {
+ if ($table == '')
+ {
+ return 0;
+ }
+
+ $result = $this->conn_id->querySingle($this->_count_string.$this->protect_identifiers('numrows')
+ .' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+
+ return empty($result) ? 0 : (int) $result;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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)
+ {
+ return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
+ .(($prefix_limit !== FALSE && $this->dbprefix != '')
+ ? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr)
+ : '');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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 = '')
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field data query
+ *
+ * Generates a platform-specific query so that the column data can be retrieved
+ *
+ * @param string the table name
+ * @return string
+ */
+ protected function _field_data($table)
+ {
+ return 'SELECT * FROM '.$table.' LIMIT 0,1';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * The error message string
+ *
+ * @return string
+ */
+ protected function _error_message()
+ {
+ return $this->conn_id->lastErrorMsg();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * The error message number
+ *
+ * @return int
+ */
+ protected function _error_number()
+ {
+ return $this->conn_id->lastErrorCode();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Escape the SQL Identifiers
+ *
+ * This function escapes column and table names
+ *
+ * @param string
+ * @return string
+ */
+ public function _escape_identifiers($item)
+ {
+ if ($this->_escape_char == '')
+ {
+ return $item;
+ }
+
+ foreach ($this->_reserved_identifiers as $id)
+ {
+ if (strpos($item, '.'.$id) !== FALSE)
+ {
+ $item = str_replace('.', $this->_escape_char.'.', $item);
+
+ // remove duplicates if the user already included the escape
+ return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
+ }
+ }
+
+ if (strpos($item, '.') !== FALSE)
+ {
+ $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
+ }
+
+ // remove duplicates if the user already included the escape
+ return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * From Tables
+ *
+ * This function implicitly groups FROM tables so there is no confusion
+ * about operator precedence in harmony with SQL standards
+ *
+ * @param string
+ * @return string
+ */
+ protected function _from_tables($tables)
+ {
+ if ( ! is_array($tables))
+ {
+ $tables = array($tables);
+ }
+
+ return '('.implode(', ', $tables).')';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Insert 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
+ * @return string
+ */
+ protected function _insert($table, $keys, $values)
+ {
+ return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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
+ * @return string
+ */
+ protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
+ {
+ foreach ($values as $key => $val)
+ {
+ $valstr[] = $key.' = '.$val;
+ }
+
+ return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
+ .(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
+ .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
+ .( ! $limit ? '' : ' LIMIT '.$limit);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Truncate statement
+ *
+ * Generates a platform-specific truncate string from the supplied data
+ * If the database does not support the truncate() command, then
+ * this method maps to "DELETE FROM table"
+ *
+ * @param string the table name
+ * @return string
+ */
+ protected function _truncate($table)
+ {
+ return $this->_delete($table);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete statement
+ *
+ * Generates a platform-specific delete string from the supplied data
+ *
+ * @param string the table name
+ * @param array the where clause
+ * @param string the limit clause
+ * @return string
+ */
+ protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+ {
+ $conditions = '';
+ if (count($where) > 0 OR count($like) > 0)
+ {
+ $conditions .= "\nWHERE ".implode("\n", $this->ar_where);
+
+ if (count($where) > 0 && count($like) > 0)
+ {
+ $conditions .= ' AND ';
+ }
+ $conditions .= implode("\n", $like);
+ }
+
+ return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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)
+ {
+ return $sql.' LIMIT '.($offset ? $offset.',' : '').$limit;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Close DB Connection
+ *
+ * @return void
+ */
+ protected function _close()
+ {
+ $this->conn_id->close();
+ }
+
+}
+
+/* End of file sqlite3_driver.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_driver.php */ \ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php
new file mode 100644
index 000000000..254db21d8
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_forge.php
@@ -0,0 +1,223 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * 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 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Forge Class
+ *
+ * @category Database
+ * @author Andrey Andreev
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_forge extends CI_DB_forge {
+
+ /**
+ * Create database
+ *
+ * @param string the database name
+ * @return bool
+ */
+ public function _create_database()
+ {
+ // 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 the database name
+ * @return bool
+ */
+ public function _drop_database($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;
+ }
+
+ return TRUE;
+ }
+
+ return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Create 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
+ */
+ public function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+ {
+ $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)
+ {
+ // 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->protect_identifiers($field)
+ .' '.$attributes['TYPE']
+ .( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '')
+ .(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
+ .(isset($attributes['DEFAULT']) ? ' DEFAULT \''.$attributes['DEFAULT'].'\'' : '')
+ .(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
+ .(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' 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)
+ {
+ $primary_keys = $this->db->protect_identifiers($primary_keys);
+ $sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+ }
+
+ if (is_array($keys) && count($keys) > 0)
+ {
+ foreach ($keys as $key)
+ {
+ if (is_array($key))
+ {
+ $key = $this->db->protect_identifiers($key);
+ }
+ else
+ {
+ $key = array($this->db->protect_identifiers($key));
+ }
+
+ $sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
+ }
+ }
+
+ return $sql."\n)";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Drop Table
+ *
+ * @param string the table name
+ * @return string
+ */
+ public function _drop_table($table)
+ {
+ return 'DROP TABLE '.$table.' IF EXISTS';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Alter table query
+ *
+ * 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
+ */
+ public function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_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')
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ return 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_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');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Rename a table
+ *
+ * Generates a platform-specific query so that a table can be renamed
+ *
+ * @param string the old table name
+ * @param string the new table name
+ * @return string
+ */
+ public function _rename_table($table_name, $new_table_name)
+ {
+ return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
+ }
+}
+
+/* End of file sqlite3_forge.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_forge.php */ \ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php
new file mode 100644
index 000000000..ddf59dbd0
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_result.php
@@ -0,0 +1,619 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * 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 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category Database
+ * @author Andrey Andreev
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_result extends CI_DB_result {
+
+ // Overwriting the parent here, so we have a way to know if it's already set
+ public $num_rows;
+
+ // num_fields() might be called multiple times, so we'll use this one to cache it's result
+ protected $_num_fields;
+
+ /**
+ * Number of rows in the result set
+ *
+ * @return int
+ */
+ public function num_rows()
+ {
+ /* The SQLite3 driver doesn't have a graceful way to do this,
+ * so we'll have to do it on our own.
+ */
+ return is_int($this->num_rows)
+ ? $this->num_rows
+ : $this->num_rows = count($this->result_array());
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Number of fields in the result set
+ *
+ * @return int
+ */
+ public function num_fields()
+ {
+ return ( ! is_int($this->_num_fields))
+ ? $this->_num_fields = $this->result_id->numColumns()
+ : $this->_num_fields;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fetch Field Names
+ *
+ * Generates an array of column names
+ *
+ * @return array
+ */
+ public function list_fields()
+ {
+ $field_names = array();
+ for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
+ {
+ $field_names[] = $this->result_id->columnName($i);
+ }
+
+ return $field_names;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Field data
+ *
+ * Generates an array of objects containing field meta-data
+ *
+ * @return array
+ */
+ public function field_data()
+ {
+ $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 = '';
+ }
+
+ return $retval;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Free the result
+ *
+ * @return void
+ */
+ public function free_result()
+ {
+ if (is_object($this->result_id))
+ {
+ $this->result_id->finalize();
+ $this->result_id = NULL;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - associative array
+ *
+ * Returns the result set as an array
+ *
+ * @return array
+ */
+ protected function _fetch_assoc()
+ {
+ return $this->result_id->fetchArray(SQLITE3_ASSOC);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Result - object
+ *
+ * Returns the result set as an object
+ *
+ * @return object
+ */
+ protected function _fetch_object()
+ {
+ // No native support for fetching as an object
+ $row = $this->_fetch_assoc();
+ return ($row !== FALSE) ? (object) $row : FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Query result. "array" version.
+ *
+ * return array
+ */
+ public function result_array()
+ {
+ if (count($this->result_array) > 0)
+ {
+ return $this->result_array;
+ }
+ elseif (is_array($this->row_data))
+ {
+ if (count($this->row_data) === 0)
+ {
+ return $this->result_array;
+ }
+ else
+ {
+ $row_index = count($this->row_data);
+ }
+ }
+ else
+ {
+ $row_index = 0;
+ $this->row_data = array();
+ }
+
+ $row = NULL;
+ while ($row = $this->_fetch_assoc())
+ {
+ $this->row_data[$row_index++] = $row;
+ }
+
+ // Un-comment the following line, in case it becomes needed
+ // $this->_data_seek();
+ return $this->result_array = $this->row_data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Query result. "object" version.
+ *
+ * @return array
+ */
+ public function result_object()
+ {
+ if (count($this->result_object) > 0)
+ {
+ return $this->result_object;
+ }
+ elseif (count($this->result_array) > 0)
+ {
+ for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
+ {
+ $this->result_object[] = (object) $this->result_array[$i];
+ }
+
+ return $this->result_object;
+ }
+ elseif (is_array($this->row_data))
+ {
+ if (count($this->row_data) === 0)
+ {
+ return $this->result_object;
+ }
+ else
+ {
+ $row_index = count($this->row_data);
+ for ($i = 0; $i < $row_index; $i++)
+ {
+ $this->result_object[$i] = (object) $this->row_data[$i];
+ }
+ }
+ }
+ else
+ {
+ $row_index = 0;
+ $this->row_data = array();
+ }
+
+ $row = NULL;
+ while ($row = $this->_fetch_assoc())
+ {
+ $this->row_data[$row_index] = $row;
+ $this->result_object[$row_index++] = (object) $row;
+ }
+
+ $this->result_array = $this->row_data;
+
+ /* As described for the num_rows() method - there's no easy
+ * way to get the number of rows selected. Our work-around
+ * solution (as in here as well) first checks if result_array
+ * exists and returns its count. It doesn't however check for
+ * custom_object_result, so - do it here.
+ */
+ if ( ! is_int($this->num_rows))
+ {
+ $this->num_rows = count($this->result_object);
+ }
+
+ // Un-comment the following line, in case it becomes needed
+ // $this->_data_seek();
+ return $this->result_object;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Query result. Custom object version.
+ *
+ * @param string class name used to instantiate rows to
+ * @return array
+ */
+ public function custom_result_object($class_name)
+ {
+ if (array_key_exists($class_name, $this->custom_result_object))
+ {
+ return $this->custom_result_object[$class_name];
+ }
+
+ if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
+ {
+ return array();
+ }
+
+ /* Even if result_array hasn't been set prior to custom_result_object being called,
+ * num_rows() has done it.
+ */
+ $data = &$this->result_array;
+
+ $result_object = array();
+ for ($i = 0, $c = count($data); $i < $c; $i++)
+ {
+ $result_object[$i] = new $class_name();
+ foreach ($data[$i] as $key => $value)
+ {
+ $result_object[$i]->$key = $value;
+ }
+ }
+
+ /* As described for the num_rows() method - there's no easy
+ * way to get the number of rows selected. Our work-around
+ * solution (as in here as well) first checks if result_array
+ * exists and returns its count. It doesn't however check for
+ * custom_object_result, so - do it here.
+ */
+ if ( ! is_int($this->num_rows))
+ {
+ $this->num_rows = count($result_object);
+ }
+
+ // Cache and return the array
+ return $this->custom_result_object[$class_name] = $result_object;
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result.
+ *
+ * Acts as a wrapper for row_object(), row_array()
+ * and custom_row_object(). Also used by first_row(), next_row()
+ * and previous_row().
+ *
+ * @param int row index
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function row($n = 0, $type = 'object')
+ {
+ if ($type === 'object')
+ {
+ return $this->row_object($n);
+ }
+ elseif ($type === 'array')
+ {
+ return $this->row_array($n);
+ }
+
+ return $this->custom_row_object($n, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Array version.
+ *
+ * @param int row index
+ * @return array
+ */
+ public function row_array($n = 0)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+
+ /* If row_data is initialized, it means that we've already tried
+ * (at least) to fetch some data, so ... check if we already have
+ * this row.
+ */
+ if (is_array($this->row_data))
+ {
+ /* If we already have row_data[$n] - return it.
+ *
+ * If we enter the elseif, there's a number of reasons to
+ * return an empty array:
+ *
+ * - count($this->row_data) === 0 means there are no results
+ * - num_rows being set or result_array having count() > 0 means
+ * that we've already fetched all data and $n is greater than
+ * our highest row index available
+ * - $n < $this->current_row means that if such row existed,
+ * we would've already returned it, therefore $n is an
+ * invalid index
+ */
+ if (isset($this->row_data[$n])) // We already have this row
+ {
+ $this->current_row = $n;
+ return $this->row_data[$n];
+ }
+ elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
+ OR count($this->result_array) > 0 OR $n < $this->current_row)
+ {
+ // No such row exists
+ return array();
+ }
+
+ // Get the next row index that would actually need to be fetched
+ $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
+ }
+ else
+ {
+ $current_row = $this->current_row = 0;
+ $this->row_data = array();
+ }
+
+ /* Fetch more data, if available
+ *
+ * NOTE: Operator precedence is important here, if you change
+ * 'AND' with '&&' - it WILL BREAK the results, as
+ * $row will be assigned the scalar value of both
+ * expressions!
+ */
+ while ($row = $this->_fetch_assoc() AND $current_row <= $n)
+ {
+ $this->row_data[$current_row++] = $row;
+ }
+
+ // This would mean that there's no (more) data to fetch
+ if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
+ {
+ // Cache what we already have
+ if (is_array($this->row_data))
+ {
+ $this->num_rows = count($this->row_data);
+ /* Usually, row_data could have less elements than result_array,
+ * but at this point - they should be exactly the same.
+ */
+ $this->result_array = $this->row_data;
+ }
+ else
+ {
+ $this->num_rows = 0;
+ }
+
+ return array();
+ }
+
+ $this->current_row = $n;
+ return $this->row_data[$n];
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Object version.
+ *
+ * @param int row index
+ * @return mixed object if row found; empty array if not
+ */
+ public function row_object($n = 0)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+
+ /* Logic here is exactly the same as in row_array,
+ * except we have to cast row_data[$n] to an object.
+ *
+ * If we already have result_object though - we can
+ * directly return from it.
+ */
+ if (isset($this->result_object[$n]))
+ {
+ $this->current_row = $n;
+ return $this->result_object[$n];
+ }
+
+ $row = $this->row_array($n);
+ // Cast only if the row exists
+ if (count($row) > 0)
+ {
+ $this->current_row = $n;
+ return (object) $row;
+ }
+
+ return array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Single row result. Custom object version.
+ *
+ * @param int row index
+ * @param string custom class name
+ * @return mixed custom object if row found; empty array otherwise
+ */
+ public function custom_row_object($n = 0, $class_name)
+ {
+ // Make sure $n is not a string
+ if ( ! is_int($n))
+ {
+ $n = (int) $n;
+ }
+
+ if (array_key_exists($class_name, $this->custom_result_object))
+ {
+ /* We already have a the whole result set with this class_name,
+ * return the specified row if it exists, and an empty array if
+ * it doesn't.
+ */
+ if (isset($this->custom_result_object[$class_name][$n]))
+ {
+ $this->current_row = $n;
+ return $this->custom_result_object[$class_name][$n];
+ }
+ else
+ {
+ return array();
+ }
+ }
+ elseif ( ! class_exists($class_name)) // No such class exists
+ {
+ return array();
+ }
+
+ $row = $this->row_array($n);
+ // An array would mean that the row doesn't exist
+ if (is_array($row))
+ {
+ return $row;
+ }
+
+ // Convert to the desired class and return
+ $row_object = new $class_name();
+ foreach ($row as $key => $value)
+ {
+ $row_object->$key = $value;
+ }
+
+ $this->current_row = $n;
+ return $row_object;
+ }
+
+ // --------------------------------------------------------------------
+
+ /* First row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function first_row($type = 'object')
+ {
+ return $this->row(0, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Last row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function last_row($type = 'object')
+ {
+ $result = &$this->result($type);
+ if ( ! isset($this->num_rows))
+ {
+ $this->num_rows = count($result);
+ }
+ $this->current_row = $this->num_rows - 1;
+ return $result[$this->current_row];
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Next row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function next_row($type = 'object')
+ {
+ if (is_array($this->row_data))
+ {
+ $count = count($this->row_data);
+ $n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
+ }
+ else
+ {
+ $n = 0;
+ }
+
+ return $this->row($n, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /* Previous row result.
+ *
+ * @param string ('object', 'array' or a custom class name)
+ * @return mixed whatever was passed to the second parameter
+ */
+ public function previous_row($type = 'object')
+ {
+ $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
+ return $this->row($n, $type);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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
+ *
+ * @return array
+ */
+ protected function _data_seek($n = 0)
+ {
+ // Only resetting to the start of the result set is supported
+ return $this->result_id->reset();
+ }
+
+}
+
+/* End of file sqlite3_result.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_result.php */ \ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_utility.php b/system/database/drivers/sqlite3/sqlite3_utility.php
new file mode 100644
index 000000000..a4dc875e1
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_utility.php
@@ -0,0 +1,103 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * 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 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Utility Class
+ *
+ * @category Database
+ * @author Andrey Andreev
+ * @link http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_utility extends CI_DB_utility {
+
+ /**
+ * List databases
+ *
+ * @return bool
+ */
+ public function _list_databases()
+ {
+ // Not supported
+ return FALSE;
+
+ // Do we use this?
+ if ($this->db_debug)
+ {
+ return $this->db->display_error('db_unsuported_feature');
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Optimize table query
+ *
+ * Is optimization even supported in SQLite?
+ *
+ * @param string the table name
+ * @return bool
+ */
+ public function _optimize_table($table)
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Repair table query
+ *
+ * Are table repairs even supported in SQLite?
+ *
+ * @param string the table name
+ * @return object
+ */
+ public function _repair_table($table)
+ {
+ // Not supported
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * SQLite Export
+ *
+ * @param array Preferences
+ * @return mixed
+ */
+ public function _backup($params = array())
+ {
+ // Not supported
+ return $this->db->display_error('db_unsuported_feature');
+ }
+
+}
+
+/* End of file sqlite3_utility.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_utility.php */ \ No newline at end of file