Merge upstream branch
diff --git a/system/core/Input.php b/system/core/Input.php
index ee15f40..5a4659a 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -699,6 +699,23 @@
 		return (php_sapi_name() === 'cli' OR defined('STDIN'));
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Request Method
+	 *
+	 * Return the Request Method
+	 *
+	 * @param	bool	uppercase or lowercase
+	 * @return 	bool
+	 */
+	public function method($upper = FALSE)
+	{
+		return ($upper)
+			? strtoupper($this->server('REQUEST_METHOD'))
+			: strtolower($this->server('REQUEST_METHOD'));
+	}
+
 }
 
 /* End of file Input.php */
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 12daaa9..20cf7ef 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -833,7 +833,7 @@
 		// If the PHP installation does not support short tags we'll
 		// do a little string replacement, changing the short tags
 		// to standard PHP echo statements.
-		if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
+		if ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE && config_item('rewrite_short_tags') == TRUE)
 		{
 			echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
 		}
diff --git a/system/core/Security.php b/system/core/Security.php
index 1007f61..2bffa41 100755
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Security Class
  *
@@ -106,23 +104,27 @@
 
 	public function __construct()
 	{
-		// CSRF config
-		foreach(array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
+		// Is CSRF protection enabled?
+		if (config_item('csrf_protection') === TRUE)
 		{
-			if (FALSE !== ($val = config_item($key)))
+			// CSRF config
+			foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
 			{
-				$this->{'_'.$key} = $val;
+				if (FALSE !== ($val = config_item($key)))
+				{
+					$this->{'_'.$key} = $val;
+				}
 			}
-		}
 
-		// Append application specific cookie prefix
-		if (config_item('cookie_prefix'))
-		{
-			$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
-		}
+			// Append application specific cookie prefix
+			if (config_item('cookie_prefix'))
+			{
+				$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
+			}
 
-		// Set the CSRF hash
-		$this->_csrf_set_hash();
+			// Set the CSRF hash
+			$this->_csrf_set_hash();
+		}
 
 		log_message('debug', 'Security Class Initialized');
 	}
@@ -136,8 +138,8 @@
 	 */
 	public function csrf_verify()
 	{
-		// If no POST data exists we will set the CSRF cookie
-		if (count($_POST) === 0)
+		// If it's not a POST request we will set the CSRF cookie
+		if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
 		{
 			return $this->csrf_set_cookie();
 		}
@@ -189,7 +191,7 @@
 		$expire = time() + $this->_csrf_expire;
 		$secure_cookie = (bool) config_item('cookie_secure');
 
-		if ($secure_cookie && ( ! isset($_SERVER['HTTPS']) OR $_SERVER['HTTPS'] == 'off' OR ! $_SERVER['HTTPS']))
+		if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off'))
 		{
 			return FALSE;
 		}
@@ -358,7 +360,7 @@
 
 		foreach ($words as $word)
 		{
-			$word = implode("\s*", str_split($word)) . "\s*";
+			$word = implode('\s*', str_split($word)).'\s*';
 
 			// We only want to do this when it is followed by a non-word character
 			// That way valid stuff like "dealer to" does not become "dealerto"
@@ -425,7 +427,6 @@
 					'\\1\\2&#40;\\3&#41;',
 					$str);
 
-
 		// Final clean up
 		// This adds a bit of extra precaution in case
 		// something got through the above filters
@@ -601,7 +602,7 @@
 			}
 
 			// find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
-			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is',  $str, $matches, PREG_SET_ORDER);
+			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is', $str, $matches, PREG_SET_ORDER);
 
 			foreach ($matches as $attr)
 			{
@@ -633,7 +634,7 @@
 	{
 		return '&lt;'.$matches[1].$matches[2].$matches[3] // encode opening brace
 			// encode captured opening or closing brace to prevent recursive vectors:
-			. str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
+			.str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/DB_active_rec.php b/system/database/DB_active_rec.php
index eaae23f..de8cfc1 100644
--- a/system/database/DB_active_rec.php
+++ b/system/database/DB_active_rec.php
@@ -212,7 +212,7 @@
 			$alias = $this->_create_alias_from_table(trim($select));
 		}
 
-		$sql = $this->_protect_identifiers($type.'('.trim($select).')').' AS '.$this->_protect_identifiers(trim($alias));
+		$sql = $this->protect_identifiers($type.'('.trim($select).')').' AS '.$this->protect_identifiers(trim($alias));
 		$this->ar_select[] = $sql;
 
 		if ($this->ar_caching === TRUE)
@@ -279,7 +279,7 @@
 				{
 					$v = trim($v);
 					$this->_track_aliases($v);
-					$v = $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
+					$v = $this->ar_from[] = $this->protect_identifiers($v, TRUE, NULL, FALSE);
 
 					if ($this->ar_caching === TRUE)
 					{
@@ -295,7 +295,7 @@
 				// Extract any aliases that might exist. We use this information
 				// in the _protect_identifiers to know whether to add a table prefix
 				$this->_track_aliases($val);
-				$this->ar_from[] = $val = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
+				$this->ar_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE);
 
 				if ($this->ar_caching === TRUE)
 				{
@@ -341,13 +341,13 @@
 		$this->_track_aliases($table);
 
 		// Strip apart the condition and protect the identifiers
-		if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
+		if (preg_match('/([\[\w\.]+)([\W\s]+)(.+)/', $cond, $match))
 		{
-			$cond = $this->_protect_identifiers($match[1]).$match[2].$this->_protect_identifiers($match[3]);
+			$cond = $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]);
 		}
 
 		// Assemble the JOIN statement
-		$this->ar_join[] = $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
+		$this->ar_join[] = $join = $type.'JOIN '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
 
 		if ($this->ar_caching === TRUE)
 		{
@@ -433,7 +433,7 @@
 			{
 				if ($escape === TRUE)
 				{
-					$k = $this->_protect_identifiers($k, FALSE, $escape);
+					$k = $this->protect_identifiers($k, FALSE, $escape);
 					$v = ' '.$this->escape($v);
 				}
 
@@ -444,7 +444,7 @@
 			}
 			else
 			{
-				$k = $this->_protect_identifiers($k, FALSE, $escape);
+				$k = $this->protect_identifiers($k, FALSE, $escape);
 			}
 
 			$this->ar_where[] = $prefix.$k.$v;
@@ -562,7 +562,7 @@
 		}
 
 		$prefix = (count($this->ar_where) === 0) ? '' : $type;
-		$this->ar_where[] = $where_in = $prefix.$this->_protect_identifiers($key).$not.' IN ('.implode(', ', $this->ar_wherein).') ';
+		$this->ar_where[] = $where_in = $prefix.$this->protect_identifiers($key).$not.' IN ('.implode(', ', $this->ar_wherein).') ';
 
 		if ($this->ar_caching === TRUE)
 		{
@@ -666,7 +666,7 @@
 
 		foreach ($field as $k => $v)
 		{
-			$k = $this->_protect_identifiers($k);
+			$k = $this->protect_identifiers($k);
 			$prefix = (count($this->ar_like) === 0) ? '' : $type;
 			$v = $this->escape_like_str($v);
 
@@ -827,7 +827,7 @@
 
 			if ($val != '')
 			{
-				$this->ar_groupby[] = $val = $this->_protect_identifiers($val);
+				$this->ar_groupby[] = $val = $this->protect_identifiers($val);
 
 				if ($this->ar_caching === TRUE)
 				{
@@ -896,7 +896,7 @@
 
 			if ($escape === TRUE)
 			{
-				$k = $this->_protect_identifiers($k);
+				$k = $this->protect_identifiers($k);
 			}
 
 			if ( ! $this->_has_operator($k))
@@ -951,7 +951,7 @@
 				$part = trim($part);
 				if ( ! in_array($part, $this->ar_aliased_tables))
 				{
-					$part = $this->_protect_identifiers(trim($part));
+					$part = $this->protect_identifiers(trim($part));
 				}
 
 				$temp[] = $part;
@@ -963,7 +963,7 @@
 		{
 			if ($escape === TRUE)
 			{
-				$orderby = $this->_protect_identifiers($orderby);
+				$orderby = $this->protect_identifiers($orderby);
 			}
 		}
 
@@ -1036,11 +1036,11 @@
 		{
 			if ($escape === FALSE)
 			{
-				$this->ar_set[$this->_protect_identifiers($k)] = $v;
+				$this->ar_set[$this->protect_identifiers($k)] = $v;
 			}
 			else
 			{
-				$this->ar_set[$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
+				$this->ar_set[$this->protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
 			}
 		}
 
@@ -1125,7 +1125,7 @@
 			$this->from($table);
 		}
 
-		$result = $this->query($this->_compile_select($this->_count_string.$this->_protect_identifiers('numrows')));
+		$result = $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
 		$this->_reset_select();
 
 		if ($result->num_rows() === 0)
@@ -1211,7 +1211,7 @@
 		// Batch this baby
 		for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100)
 		{
-			$this->query($this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100)));
+			$this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100)));
 		}
 
 		$this->_reset_write();
@@ -1269,7 +1269,7 @@
 
 		foreach ($keys as $k)
 		{
-			$this->ar_keys[] = $this->_protect_identifiers($k);
+			$this->ar_keys[] = $this->protect_identifiers($k);
 		}
 
 		return $this;
@@ -1295,9 +1295,7 @@
 		}
 
 		$sql = $this->_insert(
-			$this->_protect_identifiers(
-				$this->ar_from[0], TRUE, NULL, FALSE
-			),
+			$this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE),
 			array_keys($this->ar_set),
 			array_values($this->ar_set)
 		);
@@ -1335,9 +1333,7 @@
 		}
 
 		$sql = $this->_insert(
-			$this->_protect_identifiers(
-				$this->ar_from[0], TRUE, NULL, FALSE
-			),
+			$this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE),
 			array_keys($this->ar_set),
 			array_values($this->ar_set)
 		);
@@ -1414,7 +1410,7 @@
 			$table = $this->ar_from[0];
 		}
 
-		$sql = $this->_replace($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set));
+		$sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set));
 		$this->_reset_write();
 		return $this->query($sql);
 	}
@@ -1441,7 +1437,7 @@
 			return FALSE;
 		}
 
-		$sql = $this->_update($this->_protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit);
+		$sql = $this->_update($this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit);
 
 		if ($reset === TRUE)
 		{
@@ -1488,7 +1484,7 @@
 			$this->limit($limit);
 		}
 
-		$sql = $this->_update($this->_protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit, $this->ar_like);
+		$sql = $this->_update($this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit, $this->ar_like);
 		$this->_reset_write();
 		return $this->query($sql);
 	}
@@ -1573,7 +1569,7 @@
 		// Batch this baby
 		for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100)
 		{
-			$this->query($this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->_protect_identifiers($index), $this->ar_where));
+			$this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->protect_identifiers($index), $this->ar_where));
 		}
 
 		$this->_reset_write();
@@ -1614,7 +1610,7 @@
 					$not[] = $k.'-'.$v;
 				}
 
-				$clean[$this->_protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
+				$clean[$this->protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
 			}
 
 			if ($index_set == FALSE)
@@ -1651,7 +1647,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_delete($table);
@@ -1684,7 +1680,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_truncate($table);
@@ -1751,7 +1747,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		if ($where != '')
@@ -1894,7 +1890,7 @@
 				foreach ($this->ar_select as $key => $val)
 				{
 					$no_escape = isset($this->ar_no_escape[$key]) ? $this->ar_no_escape[$key] : NULL;
-					$this->ar_select[$key] = $this->_protect_identifiers($val, FALSE, $no_escape);
+					$this->ar_select[$key] = $this->protect_identifiers($val, FALSE, $no_escape);
 				}
 
 				$sql .= implode(', ', $this->ar_select);
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 15195b2..025441f 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
  * An open source application development framework for PHP 5.1.6 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Database Driver Class
  *
@@ -42,54 +40,44 @@
  */
 class CI_DB_driver {
 
-	var $username;
-	var $password;
-	var $hostname;
-	var $database;
-	var $dbdriver		= 'mysql';
-	var $dbprefix		= '';
-	var $char_set		= 'utf8';
-	var $dbcollat		= 'utf8_general_ci';
-	var $autoinit		= TRUE; // Whether to automatically initialize the DB
-	var $swap_pre		= '';
-	var $port			= '';
-	var $pconnect		= FALSE;
-	var $conn_id		= FALSE;
-	var $result_id		= FALSE;
-	var $db_debug		= FALSE;
-	var $benchmark		= 0;
-	var $query_count	= 0;
-	var $bind_marker	= '?';
-	var $save_queries	= TRUE;
-	var $queries		= array();
-	var $query_times	= array();
-	var $data_cache		= array();
-	var $trans_enabled	= TRUE;
-	var $trans_strict	= TRUE;
-	var $_trans_depth	= 0;
-	var $_trans_status	= TRUE; // Used with transactions to determine if a rollback should occur
-	var $cache_on		= FALSE;
-	var $cachedir		= '';
-	var $cache_autodel	= FALSE;
-	var $CACHE; // The cache class object
+	public $dsn;
+	public $username;
+	public $password;
+	public $hostname;
+	public $database;
+	public $dbdriver		= 'mysql';
+	public $dbprefix		= '';
+	public $char_set		= 'utf8';
+	public $dbcollat		= 'utf8_general_ci';
+	public $autoinit		= TRUE; // Whether to automatically initialize the DB
+	public $swap_pre		= '';
+	public $port			= '';
+	public $pconnect		= FALSE;
+	public $conn_id			= FALSE;
+	public $result_id		= FALSE;
+	public $db_debug		= FALSE;
+	public $benchmark		= 0;
+	public $query_count		= 0;
+	public $bind_marker		= '?';
+	public $save_queries		= TRUE;
+	public $queries			= array();
+	public $query_times		= array();
+	public $data_cache		= array();
 
-	// Private variables
-	var $_protect_identifiers	= TRUE;
-	var $_reserved_identifiers	= array('*'); // Identifiers that should NOT be escaped
+	public $trans_enabled		= TRUE;
+	public $trans_strict		= TRUE;
+	protected $_trans_depth		= 0;
+	protected $_trans_status	= TRUE; // Used with transactions to determine if a rollback should occur
 
-	// These are use with Oracle
-	var $stmt_id;
-	var $curs_id;
-	var $limit_used;
-	
+	public $cache_on		= FALSE;
+	public $cachedir		= '';
+	public $cache_autodel		= FALSE;
+	public $CACHE; // The cache class object
 
-	/**
-	 * Constructor.  Accepts one parameter containing the database
-	 * connection settings.
-	 *
-	 * @param array
-	 */
-	function __construct($params)
+	protected $_protect_identifiers		= TRUE;
+	protected $_reserved_identifiers	= array('*'); // Identifiers that should NOT be escaped
+
+	public function __construct($params)
 	{
 		if (is_array($params))
 		{
@@ -211,10 +199,9 @@
 	/**
 	 * The name of the platform in use (mysql, mssql, etc...)
 	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function platform()
+	public function platform()
 	{
 		return $this->dbdriver;
 	}
@@ -264,17 +251,16 @@
 	 * Execute the query
 	 *
 	 * Accepts an SQL string as input and returns a result object upon
-	 * successful execution of a "read" type query.  Returns boolean TRUE
+	 * successful execution of a "read" type query. Returns boolean TRUE
 	 * upon successful execution of a "write" type query. Returns boolean
 	 * FALSE upon failure, and if the $db_debug variable is set to TRUE
 	 * will raise an error.
 	 *
-	 * @access	public
 	 * @param	string	An SQL query string
 	 * @param	array	An array of binding data
 	 * @return	mixed
 	 */
-	function query($sql, $binds = FALSE, $return_object = TRUE)
+	public function query($sql, $binds = FALSE, $return_object = TRUE)
 	{
 		if ($sql == '')
 		{
@@ -293,7 +279,13 @@
 			$sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
 		}
 
-		// Is query caching enabled?  If the query is a "read type"
+		// Compile binds if needed
+		if ($binds !== FALSE)
+		{
+			$sql = $this->compile_binds($sql, $binds);
+		}
+
+		// Is query caching enabled? If the query is a "read type"
 		// we will load the caching class and return the previously
 		// cached query if it exists
 		if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
@@ -308,12 +300,6 @@
 			}
 		}
 
-		// Compile binds if needed
-		if ($binds !== FALSE)
-		{
-			$sql = $this->compile_binds($sql, $binds);
-		}
-
 		// Save the  query for debugging
 		if ($this->save_queries == TRUE)
 		{
@@ -396,21 +382,9 @@
 		}
 
 		// Load and instantiate the result driver
+		$driver		= $this->load_rdriver();
+		$RES		= new $driver($this);
 
-		$driver			= $this->load_rdriver();
-		$RES			= new $driver();
-		$RES->conn_id	= $this->conn_id;
-		$RES->result_id	= $this->result_id;
-
-		if ($this->dbdriver == 'oci8')
-		{
-			$RES->stmt_id		= $this->stmt_id;
-			$RES->curs_id		= NULL;
-			$RES->limit_used	= $this->limit_used;
-			$this->stmt_id		= FALSE;
-		}
-
-		// oci8 vars must be set before calling this
 		$RES->num_rows	= $RES->num_rows();
 
 		// Is query caching enabled?  If so, we'll serialize the
@@ -443,10 +417,9 @@
 	/**
 	 * Load the result drivers
 	 *
-	 * @access	public
 	 * @return	string	the name of the result class
 	 */
-	function load_rdriver()
+	public function load_rdriver()
 	{
 		$driver = 'CI_DB_'.$this->dbdriver.'_result';
 
@@ -463,15 +436,14 @@
 
 	/**
 	 * Simple Query
-	 * This is a simplified version of the query() function.  Internally
+	 * This is a simplified version of the query() function. Internally
 	 * we only use it when running transaction commands since they do
 	 * not require all the features of the main query() function.
 	 *
-	 * @access	public
 	 * @param	string	the sql query
 	 * @return	mixed
 	 */
-	function simple_query($sql)
+	public function simple_query($sql)
 	{
 		if ( ! $this->conn_id)
 		{
@@ -487,10 +459,9 @@
 	 * Disable Transactions
 	 * This permits transactions to be disabled at run-time.
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_off()
+	public function trans_off()
 	{
 		$this->trans_enabled = FALSE;
 	}
@@ -504,10 +475,9 @@
 	 * If strict mode is disabled, each group is treated autonomously, meaning
 	 * a failure of one group will not affect any others
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_strict($mode = TRUE)
+	public function trans_strict($mode = TRUE)
 	{
 		$this->trans_strict = is_bool($mode) ? $mode : TRUE;
 	}
@@ -517,10 +487,9 @@
 	/**
 	 * Start Transaction
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_start($test_mode = FALSE)
+	public function trans_start($test_mode = FALSE)
 	{
 		if ( ! $this->trans_enabled)
 		{
@@ -543,10 +512,9 @@
 	/**
 	 * Complete Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_complete()
+	public function trans_complete()
 	{
 		if ( ! $this->trans_enabled)
 		{
@@ -590,10 +558,9 @@
 	/**
 	 * Lets you retrieve the transaction flag to determine if it has failed
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_status()
+	public function trans_status()
 	{
 		return $this->_trans_status;
 	}
@@ -603,12 +570,11 @@
 	/**
 	 * Compile Bindings
 	 *
-	 * @access	public
 	 * @param	string	the sql statement
 	 * @param	array	an array of bind data
 	 * @return	string
 	 */
-	function compile_binds($sql, $binds)
+	public function compile_binds($sql, $binds)
 	{
 		if (strpos($sql, $this->bind_marker) === FALSE)
 		{
@@ -659,11 +625,10 @@
 	/**
 	 * Calculate the aggregate query elapsed time
 	 *
-	 * @access	public
-	 * @param	integer	The number of decimal places
-	 * @return	integer
+	 * @param	int	The number of decimal places
+	 * @return	int
 	 */
-	function elapsed_time($decimals = 6)
+	public function elapsed_time($decimals = 6)
 	{
 		return number_format($this->benchmark, $decimals);
 	}
@@ -673,10 +638,9 @@
 	/**
 	 * Returns the total number of queries
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function total_queries()
+	public function total_queries()
 	{
 		return $this->query_count;
 	}
@@ -686,10 +650,9 @@
 	/**
 	 * Returns the last query that was executed
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	string
 	 */
-	function last_query()
+	public function last_query()
 	{
 		return end($this->queries);
 	}
@@ -702,11 +665,10 @@
 	 * Escapes data based on type
 	 * Sets boolean and null types
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	mixed
 	 */
-	function escape($str)
+	public function escape($str)
 	{
 		if (is_string($str))
 		{
@@ -732,11 +694,10 @@
 	 * Calls the individual driver for platform
 	 * specific escaping for LIKE conditions
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	mixed
 	 */
-	function escape_like_str($str)
+	public function escape_like_str($str)
 	{
 		return $this->escape_str($str, TRUE);
 	}
@@ -746,14 +707,13 @@
 	/**
 	 * Primary
 	 *
-	 * Retrieves the primary key.  It assumes that the row in the first
+	 * Retrieves the primary key. It assumes that the row in the first
 	 * position is the primary key
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function primary($table = '')
+	public function primary($table = '')
 	{
 		$fields = $this->list_fields($table);
 
@@ -770,10 +730,9 @@
 	/**
 	 * Returns an array of table names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_tables($constrain_by_prefix = FALSE)
+	public function list_tables($constrain_by_prefix = FALSE)
 	{
 		// Is there a cached result?
 		if (isset($this->data_cache['table_names']))
@@ -811,7 +770,7 @@
 		}
 
 		$this->data_cache['table_names'] = $retval;
-		
+
 		return $this->data_cache['table_names'];
 	}
 
@@ -819,12 +778,12 @@
 
 	/**
 	 * Determine if a particular table exists
-	 * @access	public
-	 * @return	boolean
+	 *
+	 * @return	bool
 	 */
-	function table_exists($table_name)
+	public function table_exists($table_name)
 	{
-		return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
+		return in_array($this->protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables());
 	}
 
 	// --------------------------------------------------------------------
@@ -832,11 +791,10 @@
 	/**
 	 * Fetch MySQL Field Names
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	array
 	 */
-	function list_fields($table = '')
+	public function list_fields($table = '')
 	{
 		// Is there a cached result?
 		if (isset($this->data_cache['field_names'][$table]))
@@ -885,12 +843,12 @@
 
 	/**
 	 * Determine if a particular field exists
-	 * @access	public
+	 *
 	 * @param	string
 	 * @param	string
-	 * @return	boolean
+	 * @return	bool
 	 */
-	function field_exists($field_name, $table_name)
+	public function field_exists($field_name, $table_name)
 	{
 		return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
 	}
@@ -900,11 +858,10 @@
 	/**
 	 * Returns an object with field data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	object
 	 */
-	function field_data($table = '')
+	public function field_data($table = '')
 	{
 		if ($table == '')
 		{
@@ -915,7 +872,7 @@
 			return FALSE;
 		}
 
-		$query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
+		$query = $this->query($this->_field_data($this->protect_identifiers($table, TRUE, NULL, FALSE)));
 
 		return $query->field_data();
 	}
@@ -925,12 +882,11 @@
 	/**
 	 * Generate an insert string
 	 *
-	 * @access	public
 	 * @param	string	the table upon which the query will be performed
 	 * @param	array	an associative array data of key/values
 	 * @return	string
 	 */
-	function insert_string($table, $data)
+	public function insert_string($table, $data)
 	{
 		$fields = array();
 		$values = array();
@@ -941,7 +897,7 @@
 			$values[] = $this->escape($val);
 		}
 
-		return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
+		return $this->_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
 	}
 
 	// --------------------------------------------------------------------
@@ -949,23 +905,22 @@
 	/**
 	 * Generate an update string
 	 *
-	 * @access	public
 	 * @param	string	the table upon which the query will be performed
 	 * @param	array	an associative array data of key/values
 	 * @param	mixed	the "where" statement
 	 * @return	string
 	 */
-	function update_string($table, $data, $where)
+	public function update_string($table, $data, $where)
 	{
 		if ($where == '')
 		{
-			return false;
+			return FALSE;
 		}
 
 		$fields = array();
 		foreach ($data as $key => $val)
 		{
-			$fields[$this->_protect_identifiers($key)] = $this->escape($val);
+			$fields[$this->protect_identifiers($key)] = $this->escape($val);
 		}
 
 		if ( ! is_array($where))
@@ -978,7 +933,7 @@
 			foreach ($where as $key => $val)
 			{
 				$prefix = (count($dest) == 0) ? '' : ' AND ';
-				$key = $this->_protect_identifiers($key);
+				$key = $this->protect_identifiers($key);
 
 				if ($val !== '')
 				{
@@ -994,7 +949,7 @@
 			}
 		}
 
-		return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
+		return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
 	}
 
 	// --------------------------------------------------------------------
@@ -1002,11 +957,10 @@
 	/**
 	 * Tests whether the string has an SQL operator
 	 *
-	 * @access	private
 	 * @param	string
 	 * @return	bool
 	 */
-	function _has_operator($str)
+	protected function _has_operator($str)
 	{
 		$str = trim($str);
 		if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
@@ -1022,12 +976,11 @@
 	/**
 	 * Enables a native PHP function to be run, using a platform agnostic wrapper.
 	 *
-	 * @access	public
 	 * @param	string	the function name
 	 * @param	mixed	any parameters needed by the function
 	 * @return	mixed
 	 */
-	function call_function($function)
+	public function call_function($function)
 	{
 		$driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
 
@@ -1064,11 +1017,10 @@
 	/**
 	 * Set Cache Directory Path
 	 *
-	 * @access	public
 	 * @param	string	the path to the cache directory
 	 * @return	void
 	 */
-	function cache_set_path($path = '')
+	public function cache_set_path($path = '')
 	{
 		$this->cachedir = $path;
 	}
@@ -1078,10 +1030,9 @@
 	/**
 	 * Enable Query Caching
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool	cache_on value
 	 */
-	function cache_on()
+	public function cache_on()
 	{
 		$this->cache_on = TRUE;
 		return TRUE;
@@ -1092,10 +1043,9 @@
 	/**
 	 * Disable Query Caching
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool	cache_on value
 	 */
-	function cache_off()
+	public function cache_off()
 	{
 		$this->cache_on = FALSE;
 		return FALSE;
@@ -1107,10 +1057,9 @@
 	/**
 	 * Delete the cache files associated with a particular URI
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool
 	 */
-	function cache_delete($segment_one = '', $segment_two = '')
+	public function cache_delete($segment_one = '', $segment_two = '')
 	{
 		if ( ! $this->_cache_init())
 		{
@@ -1124,10 +1073,9 @@
 	/**
 	 * Delete All cache files
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool
 	 */
-	function cache_delete_all()
+	public function cache_delete_all()
 	{
 		if ( ! $this->_cache_init())
 		{
@@ -1142,10 +1090,9 @@
 	/**
 	 * Initialize the Cache Class
 	 *
-	 * @access	private
-	 * @return	void
+	 * @return	bool
 	 */
-	function _cache_init()
+	protected function _cache_init()
 	{
 		if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
 		{
@@ -1169,10 +1116,9 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function close()
+	public function close()
 	{
 		if (is_resource($this->conn_id) OR is_object($this->conn_id))
 		{
@@ -1186,13 +1132,12 @@
 	/**
 	 * Display an error message
 	 *
-	 * @access	public
 	 * @param	string	the error message
 	 * @param	string	any "swap" values
-	 * @param	boolean	whether to localize the message
+	 * @param	bool	whether to localize the message
 	 * @return	string	sends the application/error_db.php template
 	 */
-	function display_error($error = '', $swap = '', $native = FALSE)
+	public function display_error($error = '', $swap = '', $native = FALSE)
 	{
 		$LANG =& load_class('Lang', 'core');
 		$LANG->load('db');
@@ -1236,27 +1181,11 @@
 	/**
 	 * Protect Identifiers
 	 *
-	 * This function adds backticks if appropriate based on db type
-	 *
-	 * @access	private
-	 * @param	mixed	the item to escape
-	 * @return	mixed	the item with backticks
-	 */
-	function protect_identifiers($item, $prefix_single = FALSE)
-	{
-		return $this->_protect_identifiers($item, $prefix_single);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Protect Identifiers
-	 *
 	 * This function is used extensively by the Active Record class, and by
 	 * a couple functions in this class.
 	 * It takes a column or table name (optionally with an alias) and inserts
 	 * the table prefix onto it.  Some logic is necessary in order to deal with
-	 * column names that include the path.  Consider a query like this:
+	 * column names that include the path. Consider a query like this:
 	 *
 	 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
 	 *
@@ -1269,14 +1198,13 @@
 	 * insert the table prefix (if it exists) in the proper position, and escape only
 	 * the correct identifiers.
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	bool
 	 * @param	mixed
 	 * @param	bool
 	 * @return	string
 	 */
-	function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
+	public function protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
 	{
 		if ( ! is_bool($protect_identifiers))
 		{
@@ -1286,10 +1214,9 @@
 		if (is_array($item))
 		{
 			$escaped_array = array();
-
 			foreach ($item as $k => $v)
 			{
-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
+				$escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v);
 			}
 
 			return $escaped_array;
@@ -1309,7 +1236,7 @@
 
 		// This is basically a bug fix for queries that use MAX, MIN, etc.
 		// If a parenthesis is found we know that we do not need to
-		// escape the data or add a prefix.  There's probably a more graceful
+		// escape the data or add a prefix. There's probably a more graceful
 		// way to deal with this, but I'm not thinking of it -- Rick
 		if (strpos($item, '(') !== FALSE)
 		{
@@ -1324,7 +1251,7 @@
 			$parts	= explode('.', $item);
 
 			// Does the first segment of the exploded item match
-			// one of the aliases previously identified?  If so,
+			// one of the aliases previously identified? If so,
 			// we have nothing more to do other than escape the item
 			if (in_array($parts[0], $this->ar_aliased_tables))
 			{
@@ -1343,7 +1270,7 @@
 				return $item.$alias;
 			}
 
-			// Is there a table prefix defined in the config file?  If not, no need to do anything
+			// Is there a table prefix defined in the config file? If not, no need to do anything
 			if ($this->dbprefix != '')
 			{
 				// We now add the table prefix based on some logic.
@@ -1397,7 +1324,7 @@
 			return $item.$alias;
 		}
 
-		// Is there a table prefix?  If not, no need to insert it
+		// Is there a table prefix? If not, no need to insert it
 		if ($this->dbprefix != '')
 		{
 			// Verify table prefix and replace if necessary
@@ -1420,7 +1347,7 @@
 
 		return $item.$alias;
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -1428,12 +1355,10 @@
 	 *
 	 * This function is used extensively by every db driver.
 	 *
-	 * @access	private
 	 * @return	void
 	 */
 	protected function _reset_select()
 	{
-	
 	}
 
 }
diff --git a/system/database/DB_result.php b/system/database/DB_result.php
index 7304432..61aa561 100644
--- a/system/database/DB_result.php
+++ b/system/database/DB_result.php
@@ -47,6 +47,12 @@
 	public $num_rows			= 0;
 	public $row_data			= NULL;
 
+	public function __construct(&$driver_object)
+	{
+		$this->conn_id = $driver_object->conn_id;
+		$this->result_id = $driver_object->result_id;
+	}
+
 	/**
 	 * Query result.  Acts as a wrapper function for the following functions.
 	 *
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index afdaef3..3c0850a 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -378,9 +378,8 @@
 		{
 			return 0;
 		}
-		
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
 
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
@@ -427,7 +426,7 @@
 	 */
 	function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index 85e7400..76002cb 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -93,11 +93,11 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t\"" . $this->db->_protect_identifiers($field) . "\"";
+				$sql .= "\n\t\"".$this->db->protect_identifiers($field).'"';
 
 				if (array_key_exists('NAME', $attributes))
 				{
-					$sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' ';
+					$sql .= ' '.$this->db->protect_identifiers($attributes['NAME']).' ';
 				}
 
 				if (array_key_exists('TYPE', $attributes))
@@ -197,10 +197,9 @@
 		// If there is a PK defined
 		if (count($primary_keys) > 0)
 		{
-			$key_name = "pk_" . $table . "_" .
-				$this->db->_protect_identifiers(implode('_', $primary_keys));
-			
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$key_name = 'pk_'.$table.'_'.$this->db->protect_identifiers(implode('_', $primary_keys));
+
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tCONSTRAINT " . $key_name . " PRIMARY KEY(" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -210,15 +209,15 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->_protect_identifiers(implode('_', $key));
-					$key = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->protect_identifiers(implode('_', $key));
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->protect_identifiers($key);
 					$key = array($key_name);
 				}
-				
+
 				$sql .= ",\n\tKEY \"{$key_name}\" (" . implode(', ', $key) . ")";
 			}
 		}
@@ -258,19 +257,19 @@
 	 */
 	function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ";
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
 		{
-			return $sql.$this->db->_protect_identifiers($fields);
+			return $sql.$this->db->protect_identifiers($fields);
 		}
 
 		$sql .= $this->_process_fields($fields);
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -290,11 +289,10 @@
 	 */
 	function _rename_table($table_name, $new_table_name)
 	{
-		$sql = 'RENAME TABLE '.$this->db->_protect_identifiers($table_name)." AS ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'RENAME TABLE '.$this->db->protect_identifiers($table_name).' AS '.$this->db->protect_identifiers($new_table_name);
 	}
 
 }
 
 /* End of file cubrid_forge.php */
-/* Location: ./system/database/drivers/cubrid/cubrid_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/cubrid/cubrid_forge.php */
diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/interbase/interbase_driver.php
index f4bd9e2..bacb668 100644
--- a/system/database/drivers/interbase/interbase_driver.php
+++ b/system/database/drivers/interbase/interbase_driver.php
@@ -320,8 +320,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . ' FROM ' . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 147c634..39b84f9 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -365,8 +365,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index dd8aa34..ec97805 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -113,7 +113,7 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
 
 				$sql .=  ' '.$attributes['TYPE'];
 
@@ -156,7 +156,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -166,11 +166,11 @@
 			{
 				if (is_array($key))
 				{
-					$key = $this->db->_protect_identifiers($key);
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key = array($this->db->_protect_identifiers($key));
+					$key = array($this->db->protect_identifiers($key));
 				}
 
 				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
@@ -202,7 +202,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -228,7 +228,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -250,11 +250,10 @@
 	function _rename_table($table_name, $new_table_name)
 	{
 		// I think this syntax will work, but can find little documentation on renaming tables in MSSQL
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
 
 }
 
 /* End of file mssql_forge.php */
-/* Location: ./system/database/drivers/mssql/mssql_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/mssql/mssql_forge.php */
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 84f7791..cd17637 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -404,16 +404,35 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * 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
+	 * @return	object
 	 */
-	public function _field_data($table)
+	public function field_data($table = '')
 	{
-		return 'DESCRIBE '.$table;
+		if ($table == '')
+		{
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+		}
+
+		$query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, 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];
+			$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');
+		}
+
+		return $retval;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index 0f251b0..a907b20 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -151,7 +151,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->_protect_identifiers(implode('_', $primary_keys));
+			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
 			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
 		}
 
@@ -161,12 +161,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->_protect_identifiers(implode('_', $key));
-					$key = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->protect_identifiers(implode('_', $key));
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->protect_identifiers($key);
 					$key = array($key_name);
 				}
 
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index 1935394..d06119a 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -353,7 +353,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string.$this->_protect_identifiers('numrows').' FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE));
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
@@ -399,22 +399,41 @@
 	 */
 	protected function _list_columns($table = '')
 	{
-		return 'SHOW COLUMNS FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * 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
+	 * @return	object
 	 */
-	protected function _field_data($table)
+	public function field_data($table = '')
 	{
-		return 'DESCRIBE '.$table;
+		if ($table == '')
+		{
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
+		}
+
+		$query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, 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];
+			$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');
+		}
+
+		return $retval;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index 7de0361..744525f 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -183,7 +183,7 @@
 	 */
 	public function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 35cafff..8db6c12 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -458,8 +458,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query == FALSE)
 		{
 			return 0;
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 0aa1199..48f98d0 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -172,7 +172,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -198,7 +198,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -219,11 +219,9 @@
 	 */
 	function _rename_table($table_name, $new_table_name)
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
 
-
 }
 
 /* End of file oci8_forge.php */
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index 0f69fa9..383b9f1 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -38,9 +38,18 @@
  */
 class CI_DB_oci8_result extends CI_DB_result {
 
-	var $stmt_id;
-	var $curs_id;
-	var $limit_used;
+	public $stmt_id;
+	public $curs_id;
+	public $limit_used;
+
+	public function __construct(&$driver_object)
+	{
+		parent::__construct($driver_object);
+		$this->stmt_id = $driver_object->stmt_id;
+		$this->curs_id = $driver_object->curs_id;
+		$this->limit_used = $driver_object->limit_used;
+		$driver_object->stmt_id = FALSE;
+	}
 
 	/**
 	 * Number of rows in the result set.
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 779b0c6..2575f43 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -287,12 +287,11 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	bool
 	 */
-	function insert_id()
+	public function insert_id()
 	{
-		return @odbc_insert_id($this->conn_id);
+		return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -314,7 +313,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
+		$query = $this->query($this->_count_string . $this->protect_identifiers('numrows') . " FROM " . $this->protect_identifiers($table, TRUE, NULL, FALSE));
 
 		if ($query->num_rows() == 0)
 		{
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index e0ec687..51addf0 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -112,7 +112,7 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
 
 				$sql .=  ' '.$attributes['TYPE'];
 
@@ -155,7 +155,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -165,11 +165,11 @@
 			{
 				if (is_array($key))
 				{
-					$key = $this->db->_protect_identifiers($key);
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key = array($this->db->_protect_identifiers($key));
+					$key = array($this->db->protect_identifiers($key));
 				}
 
 				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
@@ -219,7 +219,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -245,7 +245,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -267,12 +267,10 @@
 	 */
 	function _rename_table($table_name, $new_table_name)
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
 
-
 }
 
 /* End of file odbc_forge.php */
-/* Location: ./system/database/drivers/odbc/odbc_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/odbc/odbc_forge.php */
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index 572e110..de2c58c 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -245,8 +245,77 @@
 		return $rs_assoc;
 	}
 
-}
+	// --------------------------------------------------------------------
 
+	/**
+	 * Query result. Array version.
+	 *
+	 * @return	array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) > 0)
+		{
+			return $this->result_array;
+		}
+		elseif (($c = count($this->result_object)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_array[$i] = (array) $this->result_object[$i];
+			}
+		}
+		elseif ($this->result_id === FALSE)
+		{
+			return array();
+		}
+		else
+		{
+			while ($row = $this->_fetch_assoc())
+			{
+				$this->result_array[] = $row;
+			}
+		}
+
+		return $this->result_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. Object version.
+	 *
+	 * @return	array
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) > 0)
+		{
+			return $this->result_object;
+		}
+		elseif (($c = count($this->result_array)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_object[$i] = (object) $this->result_array[$i];
+			}
+		}
+		elseif ($this->result_id === FALSE)
+		{
+			return array();
+		}
+		else
+		{
+			while ($row = $this->_fetch_object())
+			{
+				$this->result_object[] = $row;
+			}
+		}
+
+		return $this->result_object;
+	}
+
+}
 
 /* End of file odbc_result.php */
 /* Location: ./system/database/drivers/odbc/odbc_result.php */
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 8fdfd58..c8732ac 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -59,8 +59,7 @@
 	var $_count_string = "SELECT COUNT(*) AS ";
 	var $_random_keyword;
 
-	// need to track the pdo DSN, driver and options
-	var $dsn;
+	// need to track the pdo driver and options
 	var $pdodriver;
 	var $options = array();
 
@@ -530,8 +529,7 @@
 			return 0;
 		}
 
-		$sql   = $this->_count_string.$this->_protect_identifiers('numrows').' FROM ';
-		$sql  .= $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		$sql = $this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
 		$query = $this->query($sql);
 
 		if ($query->num_rows() == 0)
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index 478b2db..b4ddca5 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -113,7 +113,7 @@
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 				$numeric    = array('SERIAL', 'INTEGER');
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
 
 				$sql .=  ' '.$attributes['TYPE'];
 
@@ -160,7 +160,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -170,11 +170,11 @@
 			{
 				if (is_array($key))
 				{
-					$key = $this->db->_protect_identifiers($key);
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key = array($this->db->_protect_identifiers($key));
+					$key = array($this->db->protect_identifiers($key));
 				}
 
 				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
@@ -224,7 +224,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE `'.$this->db->_protect_identifiers($table)."` $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE `'.$this->db->protect_identifiers($table).'` '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -250,7 +250,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -272,11 +272,10 @@
 	 */
 	function _rename_table($table_name, $new_table_name)
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
 
 }
 
 /* End of file pdo_forge.php */
-/* Location: ./system/database/drivers/pdo/pdo_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/pdo/pdo_forge.php */
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index d8b4369..133861f 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -412,7 +412,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string.$this->_protect_identifiers('numrows').' FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE));
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
@@ -638,22 +638,20 @@
 	 * @param	string	the limit clause
 	 * @return	string
 	 */
-	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	protected function _delete($table, $where = array(), $like = array())
 	{
-		$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);
+			$conditions = "\nWHERE ".implode("\n", $this->ar_where)
+					.((count($where) > 0 && count($like) > 0) ? ' AND ' : '')
+					.implode("\n", $like);
+		}
+		else
+		{
+			$conditions = '';
 		}
 
-		return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
+		return 'DELETE FROM '.$table.$conditions;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 3eaec94..91598ab 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -343,8 +343,7 @@
 			return 0;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
 		if ($query->num_rows() == 0)
 		{
 			return 0;
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index fd0f3eb..4f379d9 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -110,7 +110,7 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
 
 				$sql .=  ' '.$attributes['TYPE'];
 
@@ -153,7 +153,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -163,11 +163,11 @@
 			{
 				if (is_array($key))
 				{
-					$key = $this->db->_protect_identifiers($key);
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key = array($this->db->_protect_identifiers($key));
+					$key = array($this->db->protect_identifiers($key));
 				}
 
 				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
@@ -218,7 +218,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -247,7 +247,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -268,9 +268,9 @@
 	 */
 	function _rename_table($table_name, $new_table_name)
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
+
 }
 
 /* End of file sqlite_forge.php */
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index 2a77669..1521922 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -113,7 +113,7 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
 
 				$sql .=  ' '.$attributes['TYPE'];
 
@@ -156,7 +156,7 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
 		}
 
@@ -166,11 +166,11 @@
 			{
 				if (is_array($key))
 				{
-					$key = $this->db->_protect_identifiers($key);
+					$key = $this->db->protect_identifiers($key);
 				}
 				else
 				{
-					$key = array($this->db->_protect_identifiers($key));
+					$key = array($this->db->protect_identifiers($key));
 				}
 
 				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
@@ -202,7 +202,7 @@
 	 */
 	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type == 'DROP')
@@ -228,7 +228,7 @@
 
 		if ($after_field != '')
 		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
+			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
 		}
 
 		return $sql;
@@ -250,11 +250,10 @@
 	function _rename_table($table_name, $new_table_name)
 	{
 		// I think this syntax will work, but can find little documentation on renaming tables in MSSQL
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
 	}
 
 }
 
-/* End of file mssql_forge.php */
-/* Location: ./system/database/drivers/mssql/mssql_forge.php */
\ No newline at end of file
+/* End of file sqlsrv_forge.php */
+/* Location: ./system/database/drivers/sqlsrv/sqlsrv_forge.php */
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 668b034..4a48df2 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -5,9 +5,9 @@
  * 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:
@@ -94,16 +94,15 @@
 		// Remove old images
 		// -----------------------------------
 
-		list($usec, $sec) = explode(" ", microtime());
-		$now = ((float)$usec + (float)$sec);
+		$now = microtime(TRUE);
 
 		$current_dir = @opendir($img_path);
 
 		while ($filename = @readdir($current_dir))
 		{
-			if ($filename != "." and $filename != ".." and $filename != "index.html")
+			if ($filename != '.' && $filename != '..' && $filename != 'index.html')
 			{
-				$name = str_replace(".jpg", "", $filename);
+				$name = str_replace('.jpg', '', $filename);
 
 				if (($name + $expiration) < $now)
 				{
@@ -198,7 +197,7 @@
 		//  Write the text
 		// -----------------------------------
 
-		$use_font = ($font_path != '' AND file_exists($font_path) AND function_exists('imagettftext')) ? TRUE : FALSE;
+		$use_font = ($font_path != '' && file_exists($font_path) && function_exists('imagettftext')) ? TRUE : FALSE;
 
 		if ($use_font == FALSE)
 		{
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index bed2cb2..6efef23 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -22,7 +22,6 @@
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
  * @since		Version 1.0
- * @filesource
  */
 
 // ------------------------------------------------------------------------
@@ -72,8 +71,8 @@
 
 		$form = '<form action="'.$action.'"'._attributes_to_string($attributes, TRUE).">\n";
 
-		// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites
-		if ($CI->config->item('csrf_protection') === TRUE AND ! (strpos($action, $CI->config->site_url()) === FALSE OR strpos($form, 'method="get"')))
+		// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites	
+		if ($CI->config->item('csrf_protection') === TRUE AND ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"')))	
 		{
 			$hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
 		}
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 2cbcd9d..3f0fef5 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -470,39 +470,35 @@
  * Create URL Title
  *
  * Takes a "title" string as input and creates a
- * human-friendly URL string with either a dash
- * or an underscore as the word separator.
+ * human-friendly URL string with a "separator" string 
+ * as the word separator.
  *
  * @access	public
  * @param	string	the string
- * @param	string	the separator: dash, or underscore
+ * @param	string	the separator
  * @return	string
  */
 if ( ! function_exists('url_title'))
 {
-	function url_title($str, $separator = 'dash', $lowercase = FALSE)
+	function url_title($str, $separator = '-', $lowercase = FALSE)
 	{
 		if ($separator === 'dash')
 		{
-			$search		= '_';
-			$replace	= '-';
+		    $separator = '-';
 		}
-		else
+		else if ($separator == 'underscore')
 		{
-			$search		= '-';
-			$replace	= '_';
+		    $separator = '_';
 		}
+		
+		$q_separator = preg_quote($separator);
 
 		$trans = array(
-						'&\#\d+?;'				=> '',
-						'&\S+?;'				=> '',
-						'\s+'					=> $replace,
-						'[^a-z0-9\-\._]'		=> '',
-						$replace.'+'			=> $replace,
-						$replace.'$'			=> $replace,
-						'^'.$replace			=> $replace,
-						'\.+$'					=> ''
-					);
+			'&.+?;'                 => '',
+			'[^a-z0-9 _-]'          => '',
+			'\s+'                   => $separator,
+			'('.$q_separator.')+'   => $separator
+		);
 
 		$str = strip_tags($str);
 		foreach ($trans as $key => $val)
@@ -515,7 +511,7 @@
 			$str = strtolower($str);
 		}
 
-		return trim(trim(stripslashes($str)), $replace);
+		return trim(trim($str, $separator));
 	}
 }
 
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 6afa37a..ea58961 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -25,30 +25,32 @@
  * @filesource
  */
 
-$lang['required']			= "The %s field is required.";
-$lang['isset']				= "The %s field must have a value.";
-$lang['valid_email']		= "The %s field must contain a valid email address.";
-$lang['valid_emails']		= "The %s field must contain all valid email addresses.";
-$lang['valid_url']			= "The %s field must contain a valid URL.";
-$lang['valid_ip']			= "The %s field must contain a valid IP.";
-$lang['min_length']			= "The %s field must be at least %s characters in length.";
-$lang['max_length']			= "The %s field cannot exceed %s characters in length.";
-$lang['exact_length']		= "The %s field must be exactly %s characters in length.";
-$lang['alpha']				= "The %s field may only contain alphabetical characters.";
-$lang['alpha_numeric']		= "The %s field may only contain alpha-numeric characters.";
-$lang['alpha_dash']			= "The %s field may only contain alpha-numeric characters, underscores, and dashes.";
-$lang['numeric']			= "The %s field must contain only numbers.";
-$lang['is_numeric']			= "The %s field must contain only numeric characters.";
-$lang['integer']			= "The %s field must contain an integer.";
-$lang['regex_match']		= "The %s field is not in the correct format.";
-$lang['matches']			= "The %s field does not match the %s field.";
-$lang['is_unique'] 			= "The %s field must contain a unique value.";
-$lang['is_natural']			= "The %s field must contain only positive numbers.";
-$lang['is_natural_no_zero']	= "The %s field must contain a number greater than zero.";
-$lang['decimal']			= "The %s field must contain a decimal number.";
-$lang['less_than']			= "The %s field must contain a number less than %s.";
-$lang['greater_than']		= "The %s field must contain a number greater than %s.";
+$lang['required']				= "The %s field is required.";
+$lang['isset']					= "The %s field must have a value.";
+$lang['valid_email']			= "The %s field must contain a valid email address.";
+$lang['valid_emails']			= "The %s field must contain all valid email addresses.";
+$lang['valid_url']				= "The %s field must contain a valid URL.";
+$lang['valid_ip']				= "The %s field must contain a valid IP.";
+$lang['min_length']				= "The %s field must be at least %s characters in length.";
+$lang['max_length']				= "The %s field cannot exceed %s characters in length.";
+$lang['exact_length']			= "The %s field must be exactly %s characters in length.";
+$lang['alpha']					= "The %s field may only contain alphabetical characters.";
+$lang['alpha_numeric']			= "The %s field may only contain alpha-numeric characters.";
+$lang['alpha_dash']				= "The %s field may only contain alpha-numeric characters, underscores, and dashes.";
+$lang['numeric']				= "The %s field must contain only numbers.";
+$lang['is_numeric']				= "The %s field must contain only numeric characters.";
+$lang['integer']				= "The %s field must contain an integer.";
+$lang['regex_match']			= "The %s field is not in the correct format.";
+$lang['matches']				= "The %s field does not match the %s field.";
+$lang['is_unique'] 				= "The %s field must contain a unique value.";
+$lang['is_natural']				= "The %s field must contain only positive numbers.";
+$lang['is_natural_no_zero']		= "The %s field must contain a number greater than zero.";
+$lang['decimal']				= "The %s field must contain a decimal number.";
+$lang['less_than']				= "The %s field must contain a number less than %s.";
+$lang['less_than_equal_to']		= "The %s field must contain a number less than or equal to %s.";
+$lang['greater_than']			= "The %s field must contain a number greater than %s.";
+$lang['greater_than_equal_to']	= "The %s field must contain a number greater than or equal to %s.";
 
 
 /* End of file form_validation_lang.php */
-/* Location: ./system/language/english/form_validation_lang.php */
\ No newline at end of file
+/* Location: ./system/language/english/form_validation_lang.php */
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 5069a44..bd8b7c2 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -47,10 +47,8 @@
 	protected $_error_suffix		= '</p>';
 	protected $error_string			= '';
 	protected $_safe_form_data		= FALSE;
+	protected $validation_data		= array();
 
-	/**
-	 * Constructor
-	 */
 	public function __construct($rules = array())
 	{
 		$this->CI =& get_instance();
@@ -67,7 +65,7 @@
 			mb_internal_encoding($this->CI->config->item('charset'));
 		}
 
-		log_message('debug', "Form Validation Class Initialized");
+		log_message('debug', 'Form Validation Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -85,7 +83,8 @@
 	public function set_rules($field, $label = '', $rules = '')
 	{
 		// No reason to set rules if we have no POST data
-		if (count($_POST) === 0)
+		// or a validation array has not been specified
+		if ($this->CI->input->method() !== 'post' && empty($this->validation_data))
 		{
 			return $this;
 		}
@@ -162,10 +161,33 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * By default, form validation uses the $_POST array to validate
+	 *
+	 * If an array is set through this method, then this array will
+	 * be used instead of the $_POST array
+	 *
+	 * Note that if you are validating multiple arrays, then the
+	 * reset_validation() function should be called after validating
+	 * each array due to the limitations of CI's singleton
+	 *
+	 * @param	array	$data
+	 * @return	void
+	 */
+	public function set_data($data = '')
+	{
+		if ( ! empty($data) && is_array($data))
+		{
+			$this->validation_data = $data;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Set Error Message
 	 *
 	 * Lets users set their own error messages on the fly.  Note:  The key
-	 * name has to match the  function name that it corresponds to.
+	 * name has to match the function name that it corresponds to.
 	 *
 	 * @param	string
 	 * @param	string
@@ -300,7 +322,8 @@
 	public function run($group = '')
 	{
 		// Do we even have any data to process?  Mm?
-		if (count($_POST) === 0)
+		$validation_array = ( ! empty($this->validation_data)) ? $this->validation_data : $_POST;
+		if (count($validation_array) === 0)
 		{
 			return FALSE;
 		}
@@ -342,18 +365,18 @@
 		// corresponding $_POST item and test for errors
 		foreach ($this->_field_data as $field => $row)
 		{
-			// Fetch the data from the corresponding $_POST array and cache it in the _field_data array.
+			// Fetch the data from the corresponding $_POST or validation array and cache it in the _field_data array.
 			// Depending on whether the field name is an array or a string will determine where we get it from.
 
 			if ($row['is_array'] === TRUE)
 			{
-				$this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']);
+				$this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array, $row['keys']);
 			}
 			else
 			{
-				if (isset($_POST[$field]) AND $_POST[$field] != "")
+				if (isset($validation_array[$field]) AND $validation_array[$field] != "")
 				{
-					$this->_field_data[$field]['postdata'] = $_POST[$field];
+					$this->_field_data[$field]['postdata'] = $validation_array[$field];
 				}
 			}
 
@@ -867,12 +890,13 @@
 	 */
 	public function matches($str, $field)
 	{
-		if ( ! isset($_POST[$field]))
+		$validation_array = ( ! empty($this->validation_data)) ? $this->validation_data : $_POST;
+		if ( ! isset($validation_array[$field]))
 		{
 			return FALSE;
 		}
 
-		return ($str === $_POST[$field]);
+		return ($str === $validation_array[$field]);
 	}
 
 	// --------------------------------------------------------------------
@@ -1117,7 +1141,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Greather than
+	 * Greater than
 	 *
 	 * @param	string
 	 * @return	bool
@@ -1134,6 +1158,23 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Equal to or Greater than
+	 *
+	 * @param	string
+	 * @return	bool
+	 */
+	public function greater_than_equal_to($str, $min)
+	{
+		if ( ! is_numeric($str))
+		{
+			return FALSE;
+		}
+		return $str >= $min;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Less than
 	 *
 	 * @param	string
@@ -1151,6 +1192,23 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Equal to or Less than
+	 *
+	 * @param	string
+	 * @return	bool
+	 */
+	public function less_than_equal_to($str, $max)
+	{
+		if ( ! is_numeric($str))
+		{
+			return FALSE;
+		}
+		return $str <= $max;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Is a Natural number  (0,1,2,3, etc.)
 	 *
 	 * @param	string
@@ -1283,6 +1341,25 @@
 		return str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reset validation vars
+	 *
+	 * Prevents subsequent validation routines from being affected by the
+	 * results of any previous validation routine due to the CI singleton.
+	 *
+	 * @return	void
+	 */
+	public function reset_validation()
+	{
+		$this->_field_data = array();
+		$this->_config_rules = array();
+		$this->_error_array = array();
+		$this->_error_messages = array();
+		$this->error_string = '';
+	}
+
 }
 
 /* End of file Form_validation.php */
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index dd50a91..104b888 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -454,7 +454,7 @@
 	 */
 	public function userdata($item)
 	{
-		return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
+		return isset($this->userdata[$item]) ? $this->userdata[$item] : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -729,7 +729,7 @@
 	 */
 	protected function _unserialize($data)
 	{
-		$data = @unserialize(strip_slashes($data));
+		$data = @unserialize(strip_slashes(trim($data)));
 
 		if (is_array($data))
 		{
@@ -737,9 +737,11 @@
 			return $data;
 		}
 
-		return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
+		return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
 	}
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * Unescape slashes
 	 *
@@ -779,7 +781,7 @@
 		{
 			$expire = $this->now - $this->sess_expiration;
 
-			$this->CI->db->where("last_activity < {$expire}");
+			$this->CI->db->where('last_activity < '.$expire);
 			$this->CI->db->delete($this->sess_table_name);
 
 			log_message('debug', 'Session garbage collection performed.');
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index ac29c1b..89575c8 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -1101,7 +1101,7 @@
 				$proc = @popen($cmd, 'r');
 				if (is_resource($proc))
 				{
-					$mime = @fread($test, 512);
+					$mime = @fread($proc, 512);
 					@pclose($proc);
 					if ($mime !== FALSE)
 					{
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index cb33336..587c64c 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -62,6 +62,9 @@
 	 -  pg_version() is now used to get the database version number, when possible.
 	 -  Added db_set_charset() support.
 	 -  Added _optimize_table() support for the :doc:`Database Utility Class <database/utilities>` (rebuilds table indexes).
+   -  Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction.
+   -  Removed limit() and order_by() support for UPDATE and DELETE queries in PostgreSQL driver. Postgres does not support those features.
+   -  Removed protect_identifiers() and renamed _protect_identifiers() to it instead - it was just an alias.
 
 -  Libraries
 
@@ -83,6 +86,8 @@
    -  Removed SHA1 function in the :doc:`Encryption Library <libraries/encryption>`.
    -  Added $config['csrf_regeneration'] to the CSRF protection in the :doc:`Security library <libraries/security>`, which makes token regeneration optional.
    -  Added function error_array() to return all error messages as an array in the Form_validation class.
+   -  Added function set_data() to Form_validation library, which can be used in place of the default $_POST array.
+   -  Added function reset_validation() to form validation library, which resets internal validation variables in case of multiple validation routines.
    -  Changed the Session library to select only one row when using database sessions.
 
 -  Core
@@ -91,6 +96,8 @@
    -  Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions).
    -  Added method get_vars() to CI_Loader to retrieve all variables loaded with $this->load->vars().
    -  is_loaded() function from system/core/Commons.php now returns a reference.
+   -  $config['rewrite_short_tags'] now has no effect when using PHP 5.4 as *<?=* will always be available.
+   -  Added method() to CI_Input to retrieve $_SERVER['REQUEST_METHOD'].
 
 Bug fixes for 3.0
 ------------------
@@ -135,6 +142,13 @@
 -  Fixed a bug (#1101) - MySQL/MySQLi result method field_data() was implemented as if it was handling a DESCRIBE result instead of the actual result set.
 -  Fixed a bug in Oracle's :doc:`Database Forge Class <database/forge>` method _create_table() where it failed with AUTO_INCREMENT as it's not supported.
 -  Fixed a bug (#1080) - When using the SMTP protocol, the :doc:`Email Library <libraries/email>` send() method was returning TRUE even if the connection/authentication against the server failed.
+-  Fixed a bug (#499) - a CSRF cookie was created even with CSRF protection being disabled.
+-  Fixed a bug (#306) - ODBC's insert_id() method was calling non-existent function odbc_insert_id(), which resulted in a fatal error.
+-  Fixed a bug in Oracle's DB_result class where the cursor id passed to it was always NULL.
+-  Fixed a bug (#64) - Regular expression in DB_active_rec.php failed to handle queries containing SQL bracket delimiters in the join condition.
+-  Fixed a bug in the :doc:`Session Library <libraries/sessions>` where a PHP E_NOTICE error was triggered by _unserialize() due to results from databases such as MSSQL and Oracle being space-padded on the right.
+-  Fixed a bug (#501) - set_rules() to check if the request method is not 'POST' before aborting, instead of depending on count($_POST) in the :doc:`Form Validation Library <libraries/form_validation>`.
+-  Fixed a bug (#940) - csrf_verify() used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid.
 
 Version 2.1.1
 =============
@@ -147,6 +161,8 @@
 -  Libraries
    -  Further improved MIME type detection in the :doc:`File Uploading Library <libraries/file_uploading>`.
 
+-  Helpers
+   -  url_title() performance and output improved. You can now use any string as the word delimiter, but 'dash' and 'underscore' are still supported.
 
 Bug fixes for 2.1.1
 -------------------
@@ -155,6 +171,7 @@
 -  Fixed a bug - form_open() compared $action against site_url() instead of base_url().
 -  Fixed a bug - CI_Upload::_file_mime_type() could've failed if mime_content_type() is used for the detection and returns FALSE.
 -  Fixed a bug (#538) - Windows paths were ignored when using the :doc:`Image Manipulation Library <libraries/image_lib>` to create a new file.
+-  Fixed a bug - When database caching was enabled, $this->db->query() checked the cache before binding variables which resulted in cached queries never being found
 
 Version 2.1.0
 =============
diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst
index 4f93c79..8653457 100644
--- a/user_guide_src/source/database/results.rst
+++ b/user_guide_src/source/database/results.rst
@@ -150,6 +150,12 @@
 	
 	echo $query->num_rows();
 
+.. note::
+	Not all database drivers have a native way of getting the total
+	number of rows for a result set. When this is the case, all of
+	the data is prefetched and count() is manually called on the
+	resulting array in order to achieve the same functionality.
+	
 $query->num_fields()
 =====================
 
@@ -182,5 +188,4 @@
 
 	$row = $query2->row();
 	echo $row->name;
-	$query2->free_result();// The $query2 result object will no longer be available
-
+	$query2->free_result(); // The $query2 result object will no longer be available
diff --git a/user_guide_src/source/general/creating_libraries.rst b/user_guide_src/source/general/creating_libraries.rst
index bc545b4..673fbd4 100644
--- a/user_guide_src/source/general/creating_libraries.rst
+++ b/user_guide_src/source/general/creating_libraries.rst
@@ -188,17 +188,23 @@
 
 	}
 
-Note: If you need to use a constructor in your class make sure you
+If you need to use a constructor in your class make sure you
 extend the parent constructor::
 
 	class MY_Email extends CI_Email {
 
-	    public function __construct()
-	    {
-	        parent::__construct();
-	    }
+		public function __construct($config = array())
+		{
+			parent::__construct($config);
+		}
+
 	}
 
+.. note::
+	Not all of the libraries have the same (or any) parameters
+	in their constructor. Take a look at the library that you're
+	extending first to see how it should be implemented.
+
 Loading Your Sub-class
 ----------------------
 
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index 09a192b..39b389f 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -579,7 +579,30 @@
 
 For more info please see the :ref:`using-arrays-as-field-names` section below.
 
-.. _saving-groups:
+Validating an Array (other than $_POST)
+=======================================
+
+Sometimes you may want to validate an array that does not originate from $_POST data.
+
+In this case, you can specify the array to be validated::
+	
+	$data = array(
+			'username' => 'johndoe',
+			'password' => 'mypassword',
+		 	'passconf' => 'mypassword'
+		);
+
+	$this->form_validation->set_data($data);
+
+Creating validation rules, running the validation and retrieving error messages works the same whether you are
+validating $_POST data or an array.
+
+**Important Note:** If you want to validate more than one array during a single execution, then you should	
+call the reset_validation() function before setting up rules and validating the new array.
+
+For more info please see the :ref:`function-reference` section below.
+
+-.. _saving-groups:
 
 ************************************************
 Saving Sets of Validation Rules to a Config File
@@ -823,34 +846,40 @@
 The following is a list of all the native rules that are available to
 use:
 
-======================= ========== ============================================================================================= =======================
-Rule                    Parameter  Description                                                                                   Example
-======================= ========== ============================================================================================= =======================
-**required**            No         Returns FALSE if the form element is empty.                                                                          
-**matches**             Yes        Returns FALSE if the form element does not match the one in the parameter.                    matches[form_item]     
-**is_unique**           Yes        Returns FALSE if the form element is not unique to the                                        is_unique[table.field] 
-                                   table and field name in the parameter. is_unique[table.field]                                                        
-**max_length**          Yes        Returns FALSE if the form element is longer then the parameter value.                         max_length[12]         
-**exact_length**        Yes        Returns FALSE if the form element is not exactly the parameter value.                         exact_length[8]        
-**greater_than**        Yes        Returns FALSE if the form element is less than the parameter value or not numeric.            greater_than[8]        
-**less_than**           Yes        Returns FALSE if the form element is greater than the parameter value or not numeric.         less_than[8]           
-**alpha**               No         Returns FALSE if the form element contains anything other than alphabetical characters.                              
-**alpha_numeric**       No         Returns FALSE if the form element contains anything other than alpha-numeric characters.                             
-**alpha_dash**          No         Returns FALSE if the form element contains anything other than alpha-numeric characters,                             
-                                   underscores or dashes.                                                                                               
-**numeric**             No         Returns FALSE if the form element contains anything other than numeric characters.                                   
-**integer**             No         Returns FALSE if the form element contains anything other than an integer.                                           
-**decimal**             Yes        Returns FALSE if the form element is not exactly the parameter value.                                                
-**is_natural**          No         Returns FALSE if the form element contains anything other than a natural number:
-                                   0, 1, 2, 3, etc.
-**is_natural_no_zero**  No         Returns FALSE if the form element contains anything other than a natural
-                                   number, but not zero: 1, 2, 3, etc.
-**is_unique**           Yes        Returns FALSE if the form element is not unique in a database table.                          is_unique[table.field] 
-**valid_email**         No         Returns FALSE if the form element does not contain a valid email address.
-**valid_emails**        No         Returns FALSE if any value provided in a comma separated list is not a valid email.
-**valid_ip**            No         Returns FALSE if the supplied IP is not valid.
-**valid_base64**        No         Returns FALSE if the supplied string contains anything other than valid Base64 characters.
-======================= ========== ============================================================================================= =======================
+========================= ========== ============================================================================================= =======================
+Rule                      Parameter  Description                                                                                   Example
+========================= ========== ============================================================================================= =======================
+**required**              No         Returns FALSE if the form element is empty.                                                                          
+**matches**               Yes        Returns FALSE if the form element does not match the one in the parameter.                    matches[form_item]     
+**is_unique**             Yes        Returns FALSE if the form element is not unique to the                                        is_unique[table.field] 
+                                     table and field name in the parameter. is_unique[table.field]                                                        
+**max_length**            Yes        Returns FALSE if the form element is longer then the parameter value.                         max_length[12]         
+**exact_length**          Yes        Returns FALSE if the form element is not exactly the parameter value.                         exact_length[8]        
+**greater_than**          Yes        Returns FALSE if the form element is less than or equal to the parameter value or not         greater_than[8]
+                                     numeric.
+**greater_than_equal_to** Yes        Returns FALSE if the form element is less than the parameter value,                           greater_than_equal_to[8]
+                                     or not numeric.
+**less_than**             Yes        Returns FALSE if the form element is greater than or equal to the parameter value or          less_than[8]
+                                     not numeric.
+**less_than_equal_to**    Yes        Returns FALSE if the form element is greater than the parameter value,                        less_than_equal_to[8]
+                                     or not numeric.
+**alpha**                 No         Returns FALSE if the form element contains anything other than alphabetical characters.                              
+**alpha_numeric**         No         Returns FALSE if the form element contains anything other than alpha-numeric characters.                             
+**alpha_dash**            No         Returns FALSE if the form element contains anything other than alpha-numeric characters,                             
+                                     underscores or dashes.                                                                                               
+**numeric**               No         Returns FALSE if the form element contains anything other than numeric characters.                                   
+**integer**               No         Returns FALSE if the form element contains anything other than an integer.                                           
+**decimal**               No         Returns FALSE if the form element contains anything other than a decimal number.                                     
+**is_natural**            No         Returns FALSE if the form element contains anything other than a natural number:
+                                     0, 1, 2, 3, etc.
+**is_natural_no_zero**    No         Returns FALSE if the form element contains anything other than a natural
+                                     number, but not zero: 1, 2, 3, etc.
+**is_unique**             Yes        Returns FALSE if the form element is not unique in a database table.                          is_unique[table.field] 
+**valid_email**           No         Returns FALSE if the form element does not contain a valid email address.
+**valid_emails**          No         Returns FALSE if any value provided in a comma separated list is not a valid email.
+**valid_ip**              No         Returns FALSE if the supplied IP is not valid.
+**valid_base64**          No         Returns FALSE if the supplied string contains anything other than valid Base64 characters.
+========================= ========== ============================================================================================= =======================
 
 .. note:: These rules can also be called as discrete functions. For
 	example::
@@ -930,6 +959,24 @@
 
 		Permits you to set custom error messages. See :ref:`setting-error-messages`
 
+$this->form_validation->set_data();
+========================================
+	
+	.. php:method:: set_data ($data = '')
+
+		:param array $data: The data to validate
+
+		Permits you to set an array for validation, instead of using the default
+		$_POST array.
+
+$this->form_validation->reset_validation();
+========================================
+
+ .. php:method:: reset_validation ()
+
+    Permits you to reset the validation when you validate more than one array.
+	This function should be called before validating each new array.
+
 $this->form_validation->error_array();
 ========================================
 	
@@ -1020,4 +1067,3 @@
 
 	<input type="radio" name="myradio" value="1" <?php echo  set_radio('myradio', '1', TRUE); ?> />
 	<input type="radio" name="myradio" value="2" <?php echo  set_radio('myradio', '2'); ?> />
-
diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst
index bcf1173..1f2ea65 100644
--- a/user_guide_src/source/libraries/input.rst
+++ b/user_guide_src/source/libraries/input.rst
@@ -99,7 +99,7 @@
 
 ::
 
-	$this->input->post(NULL, TRUE); // returns all POST items with XSS filter 
+	$this->input->post(NULL, TRUE); // returns all POST items with XSS filter
 	$this->input->post(); // returns all POST items without XSS filter
 
 $this->input->get()
@@ -119,9 +119,9 @@
 
 ::
 
-	$this->input->get(NULL, TRUE); // returns all GET items with XSS filter 
+	$this->input->get(NULL, TRUE); // returns all GET items with XSS filter
 	$this->input->get(); // returns all GET items without XSS filtering
-	
+
 
 $this->input->get_post()
 =========================
@@ -298,3 +298,13 @@
 
 	$this->input->is_cli_request()
 
+$this->input->method();
+=====================================
+
+Returns the $_SERVER['REQUEST_METHOD'], optional set uppercase or lowercase (default lowercase).
+
+::
+
+	echo $this->input->method(TRUE); // Outputs: POST
+	echo $this->input->method(FALSE); // Outputs: post
+	echo $this->input->method(); // Outputs: post
diff --git a/user_guide_src/source/overview/at_a_glance.rst b/user_guide_src/source/overview/at_a_glance.rst
index 31f0b4d..6dcfdbb 100644
--- a/user_guide_src/source/overview/at_a_glance.rst
+++ b/user_guide_src/source/overview/at_a_glance.rst
@@ -41,7 +41,7 @@
 CodeIgniter uses the Model-View-Controller approach, which allows great
 separation between logic and presentation. This is particularly good for
 projects in which designers are working with your template files, as the
-code these file contain will be minimized. We describe MVC in more
+code these files contain will be minimized. We describe MVC in more
 detail on its own page.
 
 CodeIgniter Generates Clean URLs