Merge pull request #1095 from colonelchlorine/develop

Added support for Wincache when running CI on Windows boxes
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..7f290e6
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: php
+
+phps:
+  - 5.2
+  - 5.3
+  - 5.4
+
+branches:
+  except:
+    - develop
+    - master
diff --git a/application/config/autoload.php b/application/config/autoload.php
index db49ca1..e8c9993 100644
--- a/application/config/autoload.php
+++ b/application/config/autoload.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/config.php b/application/config/config.php
index 17b854b..4ad9d1d 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/constants.php b/application/config/constants.php
index c7203e4..fce1013 100644
--- a/application/config/constants.php
+++ b/application/config/constants.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/database.php b/application/config/database.php
index bd68db1..154638d 100644
--- a/application/config/database.php
+++ b/application/config/database.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/doctypes.php b/application/config/doctypes.php
index 984da59..e5e70da 100644
--- a/application/config/doctypes.php
+++ b/application/config/doctypes.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php
index 1ae0cef..d3713fe 100644
--- a/application/config/foreign_chars.php
+++ b/application/config/foreign_chars.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/hooks.php b/application/config/hooks.php
index 80269df..1b10fc2 100644
--- a/application/config/hooks.php
+++ b/application/config/hooks.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/memcached.php b/application/config/memcached.php
index 2b1a772..7166b70 100644
--- a/application/config/memcached.php
+++ b/application/config/memcached.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/application/config/migration.php b/application/config/migration.php
index 668c357..e1ce1ae 100644
--- a/application/config/migration.php
+++ b/application/config/migration.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 8c34fd2..7ec782b 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -120,9 +120,9 @@
 				'mov'	=>	'video/quicktime',
 				'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
 				'movie'	=>	'video/x-sgi-movie',
-				'doc'	=>	'application/msword',
-				'docx'	=>	'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-				'xlsx'	=>	'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+				'doc'	=>	array('application/msword', 'application/vnd.ms-office'),
+				'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),
+				'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),
 				'word'	=>	array('application/msword', 'application/octet-stream'),
 				'xl'	=>	'application/excel',
 				'eml'	=>	'message/rfc822',
diff --git a/application/config/profiler.php b/application/config/profiler.php
index f956142..5339189 100644
--- a/application/config/profiler.php
+++ b/application/config/profiler.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/routes.php b/application/config/routes.php
index 53fc7e7..686573d 100644
--- a/application/config/routes.php
+++ b/application/config/routes.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/smileys.php b/application/config/smileys.php
index 4132aed..8e3844a 100644
--- a/application/config/smileys.php
+++ b/application/config/smileys.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index e7a6894..0baa252 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/application/controllers/welcome.php b/application/controllers/welcome.php
index 5eb0e96..2451d97 100644
--- a/application/controllers/welcome.php
+++ b/application/controllers/welcome.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/errors/error_404.php b/application/errors/error_404.php
index 4dd8fc4..9af9e39 100644
--- a/application/errors/error_404.php
+++ b/application/errors/error_404.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/errors/error_db.php b/application/errors/error_db.php
index 130ffc1..81ff02a 100644
--- a/application/errors/error_db.php
+++ b/application/errors/error_db.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/errors/error_general.php b/application/errors/error_general.php
index 2a844a8..8efcfd9 100644
--- a/application/errors/error_general.php
+++ b/application/errors/error_general.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/errors/error_php.php b/application/errors/error_php.php
index 8e293cd..42e5f5a 100644
--- a/application/errors/error_php.php
+++ b/application/errors/error_php.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php
index acc36b6..0dd8924 100644
--- a/application/views/welcome_message.php
+++ b/application/views/welcome_message.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/index.php b/index.php
index a378266..5a11901 100644
--- a/index.php
+++ b/index.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/readme.rst b/readme.rst
index 2369a8d..4707847 100644
--- a/readme.rst
+++ b/readme.rst
@@ -29,7 +29,7 @@
 Server Requirements
 *******************
 
--  PHP version 5.1.6 or newer.
+-  PHP version 5.2.4 or newer.
 
 ************
 Installation
@@ -90,9 +90,9 @@
 Compatibility
 =============
 
-CodeIgniter is compatible with PHP 5.1.6 so all code supplied must stick to
-this requirement. If PHP 5.2 or 5.3 functions or features are used then there
-must be a fallback for PHP 5.1.6.
+CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to
+this requirement. If PHP 5.3 or 5.4 functions or features are used then there
+must be a fallback for PHP 5.2.4.
 
 Branching
 =========
diff --git a/system/core/Benchmark.php b/system/core/Benchmark.php
index f4dfd3d..f6b634d 100755
--- a/system/core/Benchmark.php
+++ b/system/core/Benchmark.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 7af3c48..a79a695 100755
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Common.php b/system/core/Common.php
index 225227d..f20acaf 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -56,7 +56,7 @@
 	function is_php($version = '5.0.0')
 	{
 		static $_is_php;
-		$version = (string)$version;
+		$version = (string) $version;
 
 		if ( ! isset($_is_php[$version]))
 		{
@@ -84,7 +84,7 @@
 	function is_really_writable($file)
 	{
 		// If we're on a Unix server with safe_mode off we call is_writable
-		if (DIRECTORY_SEPARATOR === '/' AND @ini_get('safe_mode') == FALSE)
+		if (DIRECTORY_SEPARATOR === '/' && (bool) @ini_get('safe_mode') === FALSE)
 		{
 			return is_writable($file);
 		}
@@ -120,7 +120,7 @@
 /**
 * Class registry
 *
-* This function acts as a singleton.  If the requested class does not
+* This function acts as a singleton. If the requested class does not
 * exist it is instantiated and set to a static variable.  If it has
 * previously been instantiated the variable is returned.
 *
@@ -192,7 +192,7 @@
 // --------------------------------------------------------------------
 
 /**
-* Keeps track of which libraries have been loaded.  This function is
+* Keeps track of which libraries have been loaded. This function is
 * called by the load_class() function above
 *
 * @access	public
@@ -437,7 +437,7 @@
 			show_error('Status codes must be numeric', 500);
 		}
 
-		if (isset($stati[$code]) AND $text == '')
+		if (isset($stati[$code]) && $text == '')
 		{
 			$text = $stati[$code];
 		}
@@ -447,19 +447,19 @@
 			show_error('No status text available. Please check your status code number or supply your own message text.', 500);
 		}
 
-		$server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
+		$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
 
 		if (strpos(php_sapi_name(), 'cgi') === 0)
 		{
-			header("Status: {$code} {$text}", TRUE);
+			header('Status: '.$code.' '.$text, TRUE);
 		}
-		elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0')
+		elseif ($server_protocol === 'HTTP/1.0')
 		{
-			header($server_protocol." {$code} {$text}", TRUE, $code);
+			header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
 		}
 		else
 		{
-			header("HTTP/1.1 {$code} {$text}", TRUE, $code);
+			header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
 		}
 	}
 }
@@ -564,14 +564,9 @@
 {
 	function html_escape($var)
 	{
-		if (is_array($var))
-		{
-			return array_map('html_escape', $var);
-		}
-		else
-		{
-			return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
-		}
+		return is_array($var)
+			? array_map('html_escape', $var)
+			: htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
 	}
 }
 
diff --git a/system/core/Config.php b/system/core/Config.php
index 6841743..1e149d0 100755
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Controller.php b/system/core/Controller.php
index 0dc1317..05e1bf5 100644
--- a/system/core/Controller.php
+++ b/system/core/Controller.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
index bf99012..d7282b1 100755
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index e1ac58e..493822f 100755
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Input.php b/system/core/Input.php
index ee15f40..901b414 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -366,36 +366,7 @@
 	*/
 	public function valid_ip($ip)
 	{
-		// if php version >= 5.2, use filter_var to check validate ip.
-		if (function_exists('filter_var'))
-		{
-			return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
-		}
-
-		$ip_segments = explode('.', $ip);
-
-		// Always 4 segments needed
-		if (count($ip_segments) !== 4)
-		{
-			return FALSE;
-		}
-		// IP can not start with 0
-		if ($ip_segments[0][0] == '0')
-		{
-			return FALSE;
-		}
-		// Check each segment
-		foreach ($ip_segments as $segment)
-		{
-			// IP segments must be digits and can not be
-			// longer than 3 digits or greater then 255
-			if ($segment == '' OR preg_match('/[^0-9]/', $segment) OR $segment > 255 OR strlen($segment) > 3)
-			{
-				return FALSE;
-			}
-		}
-
-		return TRUE;
+		return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
 	}
 
 	// --------------------------------------------------------------------
@@ -699,6 +670,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/Lang.php b/system/core/Lang.php
index c40a685..9ef76f4 100755
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 12daaa9..9b9cc2f 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -615,13 +615,22 @@
 	 *
 	 * Loads a driver library
 	 *
-	 * @param	string	the name of the class
+	 * @param	mixed	the name of the class or array of classes
 	 * @param	mixed	the optional parameters
 	 * @param	string	an optional object name
 	 * @return	void
 	 */
 	public function driver($library = '', $params = NULL, $object_name = NULL)
 	{
+		if (is_array($library))
+		{
+			foreach ($library as $driver)
+			{
+				$this->driver($driver);
+			}
+			return FALSE;
+		}
+
 		if ( ! class_exists('CI_Driver_Library'))
 		{
 			// we aren't instantiating an object here, that'll be done by the Library itself
@@ -833,7 +842,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/Model.php b/system/core/Model.php
index a595a6a..49b8d34 100755
--- a/system/core/Model.php
+++ b/system/core/Model.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Output.php b/system/core/Output.php
index abd8a0e..faebbbe 100755
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Router.php b/system/core/Router.php
index d213195..b251abb 100755
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/core/Security.php b/system/core/Security.php
index 1007f61..cd8a610 100755
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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/core/URI.php b/system/core/URI.php
index b28ee19..4a2e87c 100755
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -444,9 +444,7 @@
 				return array();
 			}
 
-			return function_exists('array_fill_keys')
-				? array_fill_keys($default, FALSE)
-				: array_combine($default, array_fill(0, count($default), FALSE));
+			return array_fill_keys($default, FALSE);
 		}
 
 		$segments = array_slice($this->$segment_array(), ($n - 1));
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index 0e180d3..ba35674 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/DB.php b/system/database/DB.php
index d06ffb4..116116b 100755
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/DB_active_rec.php b/system/database/DB_active_rec.php
index 4247351..7567096 100644
--- a/system/database/DB_active_rec.php
+++ b/system/database/DB_active_rec.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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)
@@ -236,7 +236,8 @@
 	{
 		if (strpos($item, '.') !== FALSE)
 		{
-			return end(explode('.', $item));
+			$item = explode('.', $item);
+			return end($item);
 		}
 
 		return $item;
@@ -278,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)
 					{
@@ -294,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)
 				{
@@ -340,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)
 		{
@@ -432,7 +433,7 @@
 			{
 				if ($escape === TRUE)
 				{
-					$k = $this->_protect_identifiers($k, FALSE, $escape);
+					$k = $this->protect_identifiers($k, FALSE, $escape);
 					$v = ' '.$this->escape($v);
 				}
 
@@ -443,7 +444,7 @@
 			}
 			else
 			{
-				$k = $this->_protect_identifiers($k, FALSE, $escape);
+				$k = $this->protect_identifiers($k, FALSE, $escape);
 			}
 
 			$this->ar_where[] = $prefix.$k.$v;
@@ -561,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)
 		{
@@ -665,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);
 
@@ -826,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)
 				{
@@ -895,7 +896,7 @@
 
 			if ($escape === TRUE)
 			{
-				$k = $this->_protect_identifiers($k);
+				$k = $this->protect_identifiers($k);
 			}
 
 			if ( ! $this->_has_operator($k))
@@ -950,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;
@@ -962,7 +963,7 @@
 		{
 			if ($escape === TRUE)
 			{
-				$orderby = $this->_protect_identifiers($orderby);
+				$orderby = $this->protect_identifiers($orderby);
 			}
 		}
 
@@ -1035,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);
 			}
 		}
 
@@ -1124,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)
@@ -1210,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();
@@ -1268,7 +1269,7 @@
 
 		foreach ($keys as $k)
 		{
-			$this->ar_keys[] = $this->_protect_identifiers($k);
+			$this->ar_keys[] = $this->protect_identifiers($k);
 		}
 
 		return $this;
@@ -1294,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)
 		);
@@ -1334,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)
 		);
@@ -1413,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);
 	}
@@ -1440,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)
 		{
@@ -1487,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);
 	}
@@ -1572,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();
@@ -1613,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)
@@ -1650,7 +1647,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_delete($table);
@@ -1683,7 +1680,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_truncate($table);
@@ -1750,7 +1747,7 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		if ($where != '')
@@ -1893,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_cache.php b/system/database/DB_cache.php
index 79651fc..fb0cfa8 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 271a70e..12cd391 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
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * 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))
 		{
@@ -177,7 +165,7 @@
 		}
 
 		// Now we set the character set and that's all
-		return $this->db_set_charset($this->char_set, $this->dbcollat);
+		return $this->db_set_charset($this->char_set);
 	}
 
 	// --------------------------------------------------------------------
@@ -185,20 +173,19 @@
 	/**
 	 * Set client character set
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	resource
+	 * @return	bool
 	 */
-	function db_set_charset($charset, $collation)
+	public function db_set_charset($charset)
 	{
-		if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat))
+		if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset))
 		{
-			log_message('error', 'Unable to set database connection charset: '.$this->char_set);
+			log_message('error', 'Unable to set database connection charset: '.$charset);
 
 			if ($this->db_debug)
 			{
-				$this->display_error('db_unable_to_set_charset', $this->char_set);
+				$this->display_error('db_unable_to_set_charset', $charset);
 			}
 
 			return FALSE;
@@ -212,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;
 	}
@@ -223,36 +209,40 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Database Version Number.  Returns a string containing the
-	 * version of the database being used
+	 * Database version number
 	 *
-	 * @access	public
+	 * Returns a string containing the version of the database being used.
+	 * Most drivers will override this method.
+	 *
 	 * @return	string
 	 */
-	function version()
+	public function version()
 	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
 		if (FALSE === ($sql = $this->_version()))
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_unsupported_function');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
 		}
 
-		// Some DBs have functions that return the version, and don't run special
-		// SQL queries per se. In these instances, just return the result.
-		$driver_version_exceptions = array('oci8', 'sqlite', 'cubrid', 'pdo', 'mysqli');
+		$query = $this->query($sql);
+		$query = $query->row();
+		return $this->data_cache['version'] = $query->ver;
+	}
 
-		if (in_array($this->dbdriver, $driver_version_exceptions))
-		{
-			return $sql;
-		}
-		else
-		{
-			$query = $this->query($sql);
-			return $query->row('ver');
-		}
+	// --------------------------------------------------------------------
+
+	/**
+	 * Version number query string
+	 *
+	 * @return	string
+	 */
+	protected function _version()
+	{
+		return 'SELECT VERSION() AS ver';
 	}
 
 	// --------------------------------------------------------------------
@@ -261,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 == '')
 		{
@@ -290,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'))
@@ -305,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)
 		{
@@ -331,30 +320,28 @@
 			// This will trigger a rollback if transactions are being used
 			$this->_trans_status = FALSE;
 
-			// Grab the error number and message now, as we might run some
-			// additional queries before displaying the error
-			$error_no = $this->_error_number();
-			$error_msg = $this->_error_message();
+			// Grab the error now, as we might run some additional queries before displaying the error
+			$error = $this->error();
 
 			// Log errors
-			log_message('error', 'Query error: '.$error_msg);
+			log_message('error', 'Query error: '.$error['message']);
 
 			if ($this->db_debug)
 			{
 				// We call this function in order to roll-back queries
-				// if transactions are enabled.  If we don't call this here
+				// if transactions are enabled. If we don't call this here
 				// the error message will trigger an exit, causing the
 				// transactions to remain in limbo.
 				$this->trans_complete();
 
 				// Display errors
 				return $this->display_error(
-										array(
-												'Error Number: '.$error_no,
-												$error_msg,
-												$sql
-											)
-										);
+								array(
+									'Error Number: '.$error['code'],
+									$error['message'],
+									$sql
+								)
+							);
 			}
 
 			return FALSE;
@@ -395,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
@@ -442,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';
 
@@ -462,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)
 		{
@@ -486,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;
 	}
@@ -503,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;
 	}
@@ -516,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)
 		{
@@ -542,10 +512,9 @@
 	/**
 	 * Complete Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_complete()
+	public function trans_complete()
 	{
 		if ( ! $this->trans_enabled)
 		{
@@ -589,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;
 	}
@@ -602,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)
 		{
@@ -645,17 +612,12 @@
 	/**
 	 * Determines if a query is a "write" type.
 	 *
-	 * @access	public
 	 * @param	string	An SQL query string
-	 * @return	boolean
+	 * @return	bool
 	 */
-	function is_write_type($sql)
+	public function is_write_type($sql)
 	{
-		if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
-		{
-			return FALSE;
-		}
-		return TRUE;
+		return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|OPTIMIZE|REINDEX)\s+/i', $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -663,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);
 	}
@@ -677,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;
 	}
@@ -690,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);
 	}
@@ -706,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))
 		{
@@ -736,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);
 	}
@@ -750,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);
 
@@ -774,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']))
@@ -815,7 +770,7 @@
 		}
 
 		$this->data_cache['table_names'] = $retval;
-		
+
 		return $this->data_cache['table_names'];
 	}
 
@@ -823,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());
 	}
 
 	// --------------------------------------------------------------------
@@ -836,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]))
@@ -889,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;
 	}
@@ -904,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 == '')
 		{
@@ -919,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();
 	}
@@ -929,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();
@@ -945,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);
 	}
 
 	// --------------------------------------------------------------------
@@ -953,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))
@@ -982,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 !== '')
 				{
@@ -998,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);
 	}
 
 	// --------------------------------------------------------------------
@@ -1006,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))
@@ -1026,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.'_';
 
@@ -1068,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;
 	}
@@ -1082,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;
@@ -1096,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;
@@ -1111,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())
 		{
@@ -1128,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())
 		{
@@ -1146,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'))
 		{
@@ -1173,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))
 		{
@@ -1190,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');
@@ -1240,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
 	 *
@@ -1273,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))
 		{
@@ -1290,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;
@@ -1313,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)
 		{
@@ -1328,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))
 			{
@@ -1347,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.
@@ -1401,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
@@ -1424,6 +1347,20 @@
 
 		return $item.$alias;
 	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Dummy method that allows Active Record class to be disabled
+	 *
+	 * This function is used extensively by every db driver.
+	 *
+	 * @return	void
+	 */
+	protected function _reset_select()
+	{
+	}
+
 }
 
 /* End of file DB_driver.php */
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index 336e949..fe2a677 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/DB_result.php b/system/database/DB_result.php
index 7304432..c3cdd24 100644
--- a/system/database/DB_result.php
+++ b/system/database/DB_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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/DB_utility.php b/system/database/DB_utility.php
index 4c881d8..c94f93e 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index cde719e..2447073 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -156,37 +156,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
+	 * Database version number
 	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// In CUBRID, there is no need to set charset or collation.
-		// This is why returning true will allow the application continue
-		// its normal process.
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		// To obtain the CUBRID Server version, no need to run the SQL query.
-		// CUBRID PHP API provides a function to determin this value.
-		// This is why we also need to add 'cubrid' value to the list of
-		// $driver_version_exceptions array in DB_driver class in
-		// version() function.
-		return cubrid_get_server_info($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = cubrid_get_server_info($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -362,12 +340,11 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
-		return @cubrid_affected_rows($this->conn_id);
+		return @cubrid_affected_rows();
 	}
 
 	// --------------------------------------------------------------------
@@ -401,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;
@@ -450,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);
 	}
 
 	// --------------------------------------------------------------------
@@ -472,31 +448,18 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		return cubrid_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return cubrid_errno($this->conn_id);
+		return array('code' => cubrid_errno($this->conn_id), 'message' => cubrid_error($this->conn_id));
 	}
 
-	// --------------------------------------------------------------------
-
 	/**
 	 * Escape the SQL Identifiers
 	 *
@@ -801,4 +764,4 @@
 
 
 /* End of file cubrid_driver.php */
-/* Location: ./system/database/drivers/cubrid/cubrid_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/cubrid/cubrid_driver.php */
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index 85e7400..7d606ea 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php
index 4c0fede..a7eeb8a 100644
--- a/system/database/drivers/cubrid/cubrid_result.php
+++ b/system/database/drivers/cubrid/cubrid_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php
index 750c0d8..a13c0a5 100644
--- a/system/database/drivers/cubrid/cubrid_utility.php
+++ b/system/database/drivers/cubrid/cubrid_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/interbase/index.html b/system/database/drivers/interbase/index.html
new file mode 100644
index 0000000..c942a79
--- /dev/null
+++ b/system/database/drivers/interbase/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/interbase/interbase_driver.php
new file mode 100644
index 0000000..a9a6472
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_driver.php
@@ -0,0 +1,626 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Firebird/Interbase Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_driver extends CI_DB {
+
+	public $dbdriver = 'interbase';
+
+	// The character used to escape with
+	protected $_escape_char = '"';
+
+	// clause and character used for LIKE escape sequences
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
+
+	/**
+	 * The syntax to count rows is slightly different across different
+	 * database engines, so this string appears in each driver and is
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	protected $_count_string = "SELECT COUNT(*) AS ";
+	protected $_random_keyword = ' Random()'; // database specific random keyword
+
+	// Keeps track of the resource for the current transaction
+	protected $trans;
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @return	resource
+	 */
+	public function db_connect()
+	{
+		return @ibase_connect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @return	resource
+	 */
+	public function db_pconnect()
+	{
+		return @ibase_pconnect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reconnect
+	 *
+	 * Keep / reestablish the db connection if no queries have been
+	 * sent for a length of time exceeding the server's idle timeout
+	 *
+	 * @return	void
+	 */
+	public function reconnect()
+	{
+		// not implemented in Interbase/Firebird
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select the database
+	 *
+	 * @return	bool
+	 */
+	public function db_select()
+	{
+		// Connection selects the database
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database version number
+	 *
+	 * @return	string
+	 */
+	public function version()
+	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($service = ibase_service_attach($this->hostname, $this->username, $this->password)))
+		{
+			$this->data_cache['version'] = ibase_server_info($service, IBASE_SVC_SERVER_VERSION);
+
+			// Don't keep the service open
+			ibase_service_detach($service);
+			return $this->data_cache['version'];
+		}
+
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Execute the query
+	 *
+	 * @param	string	an SQL query
+	 * @return	resource
+	 */
+	protected function _execute($sql)
+	{
+		$sql = $this->_prep_query($sql);
+		return @ibase_query($this->conn_id, $sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Prep the query
+	 *
+	 * If needed, each database adapter can prep the query string
+	 *
+	 * @param	string	an SQL query
+	 * @return	string
+	 */
+	protected function _prep_query($sql)
+	{
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Begin Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_begin($test_mode = FALSE)
+	{
+		if ( ! $this->trans_enabled)
+		{
+			return TRUE;
+		}
+
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ($this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		// Reset the transaction failure flag.
+		// If the $test_mode flag is set to TRUE transactions will be rolled back
+		// even if the queries produce a successful result.
+		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+
+		$this->trans = @ibase_trans($this->conn_id);
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Commit Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_commit()
+	{
+		if ( ! $this->trans_enabled)
+		{
+			return TRUE;
+		}
+
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ($this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		return @ibase_commit($this->trans);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rollback Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_rollback()
+	{
+		if ( ! $this->trans_enabled)
+		{
+			return TRUE;
+		}
+
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ($this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		return @ibase_rollback($this->trans);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape String
+	 *
+	 * @param	string
+	 * @param	bool	whether or not the string will be used in a LIKE condition
+	 * @return	string
+	 */
+	public function escape_str($str, $like = FALSE)
+	{
+		if (is_array($str))
+		{
+			foreach ($str as $key => $val)
+			{
+				$str[$key] = $this->escape_str($val, $like);
+			}
+
+			return $str;
+		}
+
+		// escape LIKE condition wildcards
+		if ($like === TRUE)
+		{
+			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
+								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
+								$str);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @return	integer
+	 */
+	public function affected_rows()
+	{
+		return @ibase_affected_rows($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @param	string $generator_name
+	 * @param	integer $inc_by
+	 * @return	integer
+	 */
+	public function insert_id($generator_name, $inc_by=0)
+	{
+		//If a generator hasn't been used before it will return 0
+		return ibase_gen_id('"'.$generator_name.'"', $inc_by);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "Count All" query
+	 *
+	 * Generates a platform-specific query string that counts all records in
+	 * the specified database
+	 *
+	 * @param	string
+	 * @return	string
+	 */
+	public function count_all($table = '')
+	{
+		if ($table == '')
+		{
+			return 0;
+		}
+
+		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+		if ($query->num_rows() == 0)
+		{
+			return 0;
+		}
+
+		$row = $query->row();
+		$this->_reset_select();
+		return (int) $row->numrows;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * List table query
+	 *
+	 * Generates a platform-specific query string so that the table names can be fetched
+	 *
+	 * @param	boolean
+	 * @return	string
+	 */
+	protected function _list_tables($prefix_limit = FALSE)
+	{
+		$sql = <<<SQL
+			SELECT "RDB\$RELATION_NAME" FROM "RDB\$RELATIONS" 
+			WHERE "RDB\$RELATION_NAME" NOT LIKE 'RDB$%'
+			AND "RDB\$RELATION_NAME" NOT LIKE 'MON$%'
+SQL;
+
+		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		{
+			$sql .= ' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+		}
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Show column query
+	 *
+	 * Generates a platform-specific query string so that the column names can be fetched
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _list_columns($table = '')
+	{
+		return <<<SQL
+			SELECT "RDB\$FIELD_NAME" FROM "RDB\$RELATION_FIELDS" 
+			WHERE "RDB\$RELATION_NAME"='{$table}';
+SQL;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data query
+	 *
+	 * Generates a platform-specific query so that the column data can be retrieved
+	 *
+	 * @param	string	the table name
+	 * @return	object
+	 */
+	protected function _field_data($table)
+	{
+		// Need to find a more efficient way to do this
+		// but Interbase/Firebird seems to lack the
+		// limit clause
+		return "SELECT * FROM {$table}";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Error
+	 *
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
+	 */
+	public function error()
+	{
+		return array('code' => ibase_errcode(), 'message' => ibase_errmsg());
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape the SQL Identifiers
+	 *
+	 * This public function escapes column and table names
+	 *
+	 * @param	string
+	 * @return	string
+	 */
+	protected function _escape_identifiers($item)
+	{
+		foreach ($this->_reserved_identifiers as $id)
+		{
+			if (strpos($item, '.'.$id) !== FALSE)
+			{
+				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
+
+				// remove duplicates if the user already included the escape
+				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+			}
+		}
+
+		if (strpos($item, '.') !== FALSE)
+		{
+			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
+		}
+		else
+		{
+			$str = $this->_escape_char.$item.$this->_escape_char;
+		}
+
+		// remove duplicates if the user already included the escape
+		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * From Tables
+	 *
+	 * This public function implicitly groups FROM tables so there is no confusion
+	 * about operator precedence in harmony with SQL standards
+	 *
+	 * @param	type
+	 * @return	type
+	 */
+	protected function _from_tables($tables)
+	{
+		if ( ! is_array($tables))
+		{
+			$tables = array($tables);
+		}
+
+		//Interbase/Firebird doesn't like grouped tables
+		return implode(', ', $tables);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert statement
+	 *
+	 * Generates a platform-specific insert string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param	array	the insert values
+	 * @return	string
+	 */
+	protected function _insert($table, $keys, $values)
+	{
+		return "INSERT INTO {$table} (".implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Update statement
+	 *
+	 * Generates a platform-specific update string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the update data
+	 * @param	array	the where clause
+	 * @param	array	the orderby clause
+	 * @param	array	the limit clause
+	 * @return	string
+	 */
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
+	{
+		foreach ($values as $key => $val)
+		{
+			$valstr[] = $key." = ".$val;
+		}
+
+		//$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
+
+		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
+
+		$sql = "UPDATE {$table} SET ".implode(', ', $valstr);
+
+		$sql .= ($where != '' AND count($where) >=1) ? ' WHERE '.implode(' ', $where) : '';
+
+		$sql .= $orderby;
+
+		return $sql;
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Truncate statement
+	 *
+	 * Generates a platform-specific truncate string from the supplied data
+	 * If the database does not support the truncate() command
+	 * This public function maps to "DELETE FROM table"
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _truncate($table)
+	{
+		return $this->_delete($table);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete statement
+	 *
+	 * Generates a platform-specific delete string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the where clause
+	 * @param	string	the limit clause
+	 * @return	string
+	 */
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	{
+		$conditions = '';
+
+		if (count($where) > 0 OR count($like) > 0)
+		{
+			$conditions = "\nWHERE ";
+			$conditions .= implode("\n", $this->ar_where);
+
+			if (count($where) > 0 && count($like) > 0)
+			{
+				$conditions .= ' AND ';
+			}
+			$conditions .= implode("\n", $like);
+		}
+
+		//$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
+
+		return "DELETE FROM {$table}{$conditions}";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Limit string
+	 *
+	 * Generates a platform-specific LIMIT clause
+	 *
+	 * @param	string	the sql query string
+	 * @param	integer	the number of rows to limit the query to
+	 * @param	integer	the offset value
+	 * @return	string
+	 */
+	protected function _limit($sql, $limit, $offset)
+	{
+		// Keep the current sql string safe for a moment
+		$orig_sql = $sql;
+
+		// Limit clause depends on if Interbase or Firebird
+		if (stripos($this->version(), 'firebird') !== FALSE)
+		{
+			$sql = 'FIRST '. (int) $limit;
+
+			if ($offset > 0)
+			{
+				$sql .= ' SKIP '. (int) $offset;
+			}
+		}
+		else
+		{
+			$sql = 'ROWS ' . (int) $limit;
+
+			if ($offset > 0)
+			{
+				$sql = 'ROWS '. (int) $offset . ' TO ' . ($limit + $offset);
+			}
+		}
+
+		return preg_replace('`SELECT`i', "SELECT {$sql}", $orig_sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @param	resource
+	 * @return	void
+	 */
+	protected function _close($conn_id)
+	{
+		@ibase_close($conn_id);
+	}
+
+}
+
+/* End of file interbase_driver.php */
+/* Location: ./system/database/drivers/interbase/interbase_driver.php */
diff --git a/system/database/drivers/interbase/interbase_forge.php b/system/database/drivers/interbase/interbase_forge.php
new file mode 100644
index 0000000..f460435
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_forge.php
@@ -0,0 +1,243 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Interbase/Firebird Forge Class
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_forge extends CI_DB_forge {
+
+	/**
+	 * Create database
+	 *
+	 * @param	string	the database name
+	 * @return	string
+	 */
+	protected function _create_database($filename='')
+	{
+		// Firebird databases are flat files, so a path is required 
+		// Hostname is needed for remote access
+		return 'CREATE DATABASE "'.$this->hostname.':'.$filename.'"';
+		
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop database
+	 *
+	 * @param	string	the database name - not used in this driver 
+	 *	- the current db is dropped
+	 * @return	bool
+	 */
+	protected function _drop_database($name='')
+	{
+		return ibase_drop_db($this->conn_id);
+	}
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create Table
+	 *
+	 * @param	string	the table name
+	 * @param	array	the fields
+	 * @param	mixed	primary key(s)
+	 * @param	mixed	key(s)
+	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	string
+	 */
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	{
+		$sql = 'CREATE TABLE ';
+
+		$sql .= $this->db->protect_identifiers($table)."(";
+		$current_field_count = 0;
+
+		foreach ($fields as $field => $attributes)
+		{
+			// Numeric field names aren't allowed in databases, so if the key is
+			// numeric, we know it was assigned by PHP and the developer manually
+			// entered the field information, so we'll simply add it to the list
+			if (is_numeric($field))
+			{
+				$sql .= "\n\t$attributes";
+			}
+			else
+			{
+				$attributes = array_change_key_case($attributes, CASE_UPPER);
+
+				$sql .= "\n\t".$this->db->protect_identifiers($field);
+
+				$sql .=  ' '.$attributes['TYPE'];
+
+				if (array_key_exists('CONSTRAINT', $attributes))
+				{
+					$sql .= '('.$attributes['CONSTRAINT'].')';
+				}
+
+				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (array_key_exists('DEFAULT', $attributes))
+				{
+					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+				}
+
+				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
+				{
+					$sql .= ' NULL';
+				}
+				else
+				{
+					$sql .= ' NOT NULL';
+				}
+
+				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
+			}
+
+			// don't add a comma on the end of the last field
+			if (++$current_field_count < count($fields))
+			{
+				$sql .= ',';
+			}
+		}
+
+		if (count($primary_keys) > 0)
+		{
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+		}
+
+		if (is_array($keys) && count($keys) > 0)
+		{
+			foreach ($keys as $key)
+			{
+				if (is_array($key))
+				{
+					$key = $this->db->protect_identifiers($key);
+				}
+				else
+				{
+					$key = array($this->db->protect_identifiers($key));
+				}
+
+				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+			}
+		}
+
+		$sql .= "\n)";
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop Table
+	 *
+	 * @return	string
+	 */
+	protected function _drop_table($table)
+	{
+		return 'DROP TABLE '.$name;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Alter table query
+	 *
+	 * Generates a platform-specific query so that a table can be altered
+	 * Called by add_column(), drop_column(), and column_alter(),
+	 *
+	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
+	 * @param	string	the column name
+	 * @param	string	the table name
+	 * @param	string	the column definition
+	 * @param	string	the default value
+	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	string	the field after which we should add the new field
+	 * @return	string
+	 */
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	{
+		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table)." $alter_type ".$this->db->protect_identifiers($column_name);
+
+		$sql .= " {$column_definition}";
+
+		if ($default_value != '')
+		{
+			$sql .= " DEFAULT \"{$default_value}\"";
+		}
+
+		if ($null === NULL)
+		{
+			$sql .= ' NULL';
+		}
+		else
+		{
+			$sql .= ' NOT NULL';
+		}
+
+		if ($after_field != '')
+		{
+			$sql .= ' AFTER ' . $this->db->protect_identifiers($after_field);
+		}
+
+		return $sql;
+
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rename a table
+	 *
+	 * Generates a platform-specific query so that a table can be renamed
+	 *
+	 * @param	string	the old table name
+	 * @param	string	the new table name
+	 * @return	string
+	 */
+	protected function _rename_table($table_name, $new_table_name)
+	{
+		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
+	}
+}
+
+/* End of file interbase_forge.php */
+/* Location: ./system/database/drivers/interbase/interbase_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_result.php b/system/database/drivers/interbase/interbase_result.php
new file mode 100644
index 0000000..5bf0c90
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_result.php
@@ -0,0 +1,294 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Interbase/Firebird Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_result extends CI_DB_result {
+
+	public $num_rows;
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @return	integer
+	 */
+	public function num_rows()
+	{
+		if( ! is_null($this->num_rows))
+		{
+			return $this->num_rows;
+		}
+		
+		//Get the results so that you can get an accurate rowcount
+		$this->result();
+		
+		return $this->num_rows;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @return	integer
+	 */
+	public function num_fields()
+	{
+		return @ibase_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @return	array
+	 */
+	public function list_fields()
+	{
+		$field_names = array();
+		for ($i = 0, $num_fields = $this->num_fields(); $i < $num_fields; $i++)
+		{
+			$info = ibase_field_info($this->result_id, $i);
+			$field_names[] = $info['name'];
+		}
+
+		return $field_names;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data
+	 *
+	 * Generates an array of objects containing field meta-data
+	 *
+	 * @return	array
+	 */
+	public function field_data()
+	{
+		
+		$retval = array();
+		for ($i = 0, $num_fields = $this->num_fields(); $i < $num_fields; $i++)
+		{
+			$info = ibase_field_info($this->result_id, $i);
+		
+			$F				= new stdClass();
+			$F->name		= $info['name'];
+			$F->type		= $info['type'];
+			$F->max_length	= $info['length'];
+			$F->primary_key = 0;
+			$F->default		= '';
+
+			$retval[] = $F;
+		}
+
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	null
+	 */
+	public function free_result()
+	{
+		@ibase_free_result($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Data Seek
+	 *
+	 * Moves the internal pointer to the desired offset.  We call
+	 * this internally before fetching results to make sure the
+	 * result set starts at zero
+	 *
+	 * @return	array
+	 */
+	protected function _data_seek($n = 0)
+	{
+		//Set the row count to 0
+		$this->num_rows = 0;
+	
+		//Interbase driver doesn't implement a suitable function
+		return FALSE;	
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @return	array
+	 */
+	protected function _fetch_assoc()
+	{
+		if (($row = @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
+		{
+			//Increment row count
+			$this->num_rows++;
+		}
+	
+		return $row;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @return	object
+	 */
+	protected function _fetch_object()
+	{
+		if (($row = @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
+		{
+			//Increment row count
+			$this->num_rows++;
+		}
+		
+		return $row;
+	}
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "object" version.
+	 *
+	 * @return	object
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) > 0)
+		{
+			return $this->result_object;
+		}
+		
+		// Convert result array to object so that 
+		// We don't have to get the result again
+		if (count($this->result_array) > 0)
+		{
+			$i = 0;
+		
+			foreach ($this->result_array as $array)
+			{
+				$this->result_object[$i] = new StdClass();
+			
+				foreach ($array as $key => $val)
+				{
+					$this->result_object[$i]->{$key} = $val;
+				}
+				
+				++$i;
+			}
+			
+			return $this->result_object;
+		}
+
+		// In the event that query caching is on the result_id variable
+		// will return FALSE since there isn't a valid SQL resource so
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE)
+		{
+			return array();
+		}
+
+		$this->num_rows = 0;
+		while ($row = $this->_fetch_object())
+		{
+			$this->result_object[] = $row;
+		}
+
+		return $this->result_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "array" version.
+	 *
+	 * @return	array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) > 0)
+		{
+			return $this->result_array;
+		}
+		
+		// Since the object and array are really similar, just case
+		// the result object to an array  if need be
+		if (count($this->result_object) > 0)
+		{
+			foreach ($this->result_object as $obj)
+			{
+				$this->result_array[] = (array) $obj;
+			}
+		
+			return $this->result_array;
+		}
+
+		// In the event that query caching is on the result_id variable
+		// will return FALSE since there isn't a valid SQL resource so
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE)
+		{
+			return array();
+		}
+
+		$this->num_rows = 0;
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->result_array[] = $row;
+		}
+
+		return $this->result_array;
+	}
+
+}
+
+/* End of file interbase_result.php */
+/* Location: ./system/database/drivers/interbase/interbase_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_utility.php b/system/database/drivers/interbase/interbase_utility.php
new file mode 100644
index 0000000..a88055e
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_utility.php
@@ -0,0 +1,115 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Interbase/Firebird Utility Class
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * I don't believe you can do a database listing with Firebird
+	 * since each database is its own file.  I suppose we could
+	 * try reading a directory looking for Firebird files, but
+	 * that doesn't seem like a terribly good idea
+	 *
+	 * @return	bool
+	 */
+	public function _list_databases()
+	{
+		if ($this->db_debug)
+		{
+			return $this->db->display_error('db_unsuported_feature');
+		}
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Optimize table query
+	 *
+	 * Is optimization even supported in Interbase/Firebird?
+	 *
+	 * @param	string	the table name
+	 * @return	object
+	 */
+	public function _optimize_table($table)
+	{
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Repair table query
+	 *
+	 * Table repairs are not supported in Interbase/Firebird
+	 *
+	 * @param	string	the table name
+	 * @return	object
+	 */
+	public function _repair_table($table)
+	{
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Interbase/Firebird Export
+	 *
+	 * @param	string	$filename
+	 * @return	mixed
+	 */
+	public function backup($filename)
+	{
+		if ($service = ibase_service_attach($this->db->hostname, $this->db->username, $this->db->password))
+		{
+			$res = ibase_backup($service, $this->db->database, $filename.'.fbk');
+			
+			//Close the service connection	
+			ibase_service_detach($service);
+			
+			return $res;
+		}
+		else
+		{
+			return FALSE;
+		}
+	}
+}
+
+/* End of file interbase_utility.php */
+/* Location: ./system/database/drivers/interbase/interbase_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 25a32f3..b6b64cc 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -138,22 +138,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Execute the query
 	 *
 	 * @access	private called by the base class
@@ -355,12 +339,11 @@
 	/**
 	* Version number query string
 	*
-	* @access public
-	* @return string
+	* @return	string
 	*/
-	function _version()
+	protected function _version()
 	{
-		return "SELECT @@VERSION AS ver";
+		return 'SELECT @@VERSION AS ver';
 	}
 
 	// --------------------------------------------------------------------
@@ -382,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;
@@ -454,28 +436,18 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		return mssql_get_last_message();
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		// Are error numbers supported?
-		return '';
+		$query = $this->query('SELECT @@ERROR AS code');
+		$query = $query->row();
+		return array('code' => $query->code, 'message' => mssql_get_last_message());
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index dd8aa34..4a8089b 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index bba2e62..b205ce2 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php
index be6ed5b..28f34b9 100644
--- a/system/database/drivers/mssql/mssql_utility.php
+++ b/system/database/drivers/mssql/mssql_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index c88a8a7..ba646d2 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -144,26 +144,25 @@
 	 * Set client character set
 	 *
 	 * @param	string
-	 * @param	string
 	 * @return	bool
 	 */
-	public function db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		return function_exists('mysql_set_charset')
-			? @mysql_set_charset($charset, $this->conn_id)
-			: @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id);
+		return @mysql_set_charset($charset, $this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
 	 * @return	string
 	 */
-	protected function _version()
+	public function version()
 	{
-		return 'SELECT version() AS ver';
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = @mysql_get_server_info($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -287,18 +286,7 @@
 	   		return $str;
 	   	}
 
-		if (function_exists('mysql_real_escape_string') && is_resource($this->conn_id))
-		{
-			$str = mysql_real_escape_string($str, $this->conn_id);
-		}
-		elseif (function_exists('mysql_escape_string'))
-		{
-			$str = mysql_escape_string($str);
-		}
-		else
-		{
-			$str = addslashes($str);
-		}
+		$str = is_resource($this->conn_id) ? mysql_real_escape_string($str, $this->conn_id) : addslashes($str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
@@ -402,40 +390,50 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * 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;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @return	string
-	 */
-	protected function _error_message()
-	{
-		return mysql_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @return	int
+	 * @return	array
 	 */
-	protected function _error_number()
+	public function error()
 	{
-		return mysql_errno($this->conn_id);
+		return array('code' => mysql_errno($this->conn_id), 'message' => mysql_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index 0f251b0..004a5a1 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 8f04a93..cec28dc 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -90,18 +90,14 @@
 	public function field_data()
 	{
 		$retval = array();
-		while ($field = mysql_fetch_object($this->result_id))
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
-			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
-
-			$F		= new stdClass();
-			$F->name	= $field->Field;
-			$F->type	= ( ! empty($matches[1])) ? $matches[1] : NULL;
-			$F->default	= $field->Default;
-			$F->max_length	= ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
-			$F->primary_key = (int) ($field->Key === 'PRI');
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= mysql_field_name($this->result_id, $i);
+			$retval[$i]->type		= mysql_field_type($this->result_id, $i);
+			$retval[$i]->max_length		= mysql_field_len($this->result_id, $i);
+			$retval[$i]->primary_key	= (strpos(mysql_field_flags($this->result_id, $i), 'primary_key') === FALSE) ? 0 : 1;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index 952f887..d716b00 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index dbba12e..f38b94c 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -144,26 +144,25 @@
 	 * Set client character set
 	 *
 	 * @param	string
-	 * @param	string
 	 * @return	bool
 	 */
-	protected function _db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		return function_exists('mysqli_set_charset')
-			? @mysqli_set_charset($this->conn_id, $charset)
-			: @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
+		return @mysqli_set_charset($this->conn_id, $charset);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
 	 * @return	string
 	 */
-	protected function _version()
+	public function version()
 	{
-		return @mysqli_get_server_info($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = @mysqli_get_server_info($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -287,18 +286,7 @@
 			return $str;
 		}
 
-		if (function_exists('mysqli_real_escape_string') && is_object($this->conn_id))
-		{
-			$str = mysqli_real_escape_string($this->conn_id, $str);
-		}
-		elseif (function_exists('mysql_escape_string'))
-		{
-			$str = mysql_escape_string($str);
-		}
-		else
-		{
-			$str = addslashes($str);
-		}
+		$str = is_object($this->conn_id) ? mysqli_real_escape_string($this->conn_id, $str) : addslashes($str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
@@ -351,7 +339,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;
@@ -397,46 +385,56 @@
 	 */
 	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;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @return	string
-	 */
-	protected function _error_message()
-	{
-		return mysqli_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @return	int
+	 * @return	array
 	 */
-	protected function _error_number()
+	public function error()
 	{
-		return mysqli_errno($this->conn_id);
+		return array('code' => mysqli_errno($this->conn_id), 'message' => mysqli_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index 7de0361..9cb1a0c 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -86,9 +86,32 @@
 
 				$sql .= "\n\t".$this->db->protect_identifiers($field)
 					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '')
-					.( ! empty($attributes['TYPE']) ? ' '.$attributes['TYPE'] : '')
-					.( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '')
-					.(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
+				;
+
+				if ( ! empty($attributes['TYPE']))
+				{
+					$sql .=  ' '.$attributes['TYPE'];
+
+					if ( ! empty($attributes['CONSTRAINT']))
+					{
+						switch (strtolower($attributes['TYPE']))
+						{
+							case 'decimal':
+							case 'float':
+							case 'numeric':
+								$sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
+								break;
+							case 'enum':
+							case 'set':
+								$sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
+								break;
+							default:
+								$sql .= '('.$attributes['CONSTRAINT'].')';
+						}
+					}
+				}
+
+				$sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
 					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
 					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
 					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
@@ -183,7 +206,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/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index 0a50ccc..f135f4d 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -90,18 +90,15 @@
 	public function field_data()
 	{
 		$retval = array();
-		while ($field = mysqli_fetch_object($this->result_id))
+		$field_data = mysqli_fetch_fields($this->result_id);
+		for ($i = 0, $c = count($field_data); $i < $c; $i++)
 		{
-			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
-
-			$F		= new stdClass();
-			$F->name	= $field->Field;
-			$F->type	= ( ! empty($matches[1])) ? $matches[1] : NULL;
-			$F->default	= $field->Default;
-			$F->max_length	= ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
-			$F->primary_key = (int) ($field->Key === 'PRI');
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $field_data[$i]->name;
+			$retval[$i]->type		= $field_data[$i]->type;
+			$retval[$i]->max_length		= $field_data[$i]->max_length;
+			$retval[$i]->primary_key	= (int) ($field_data[$i]->flags & 2);
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php
index 3fdc5c7..650ddfd 100644
--- a/system/database/drivers/mysqli/mysqli_utility.php
+++ b/system/database/drivers/mysqli/mysqli_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index c662190..070d58a 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -139,30 +139,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
+	 * Database version number
 	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
+	 * @return	string
 	 */
-	public function db_set_charset($charset, $collation)
+	public function version()
 	{
-		// this is done upon connect
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access  protected
-	 * @return  string
-	 */
-	protected function _version()
-	{
-		return oci_server_version($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = oci_server_version($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -398,10 +383,9 @@
 	/**
 	 * Escape String
 	 *
-	 * @access  public
-	 * @param   string
+	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
-	 * @return  string
+	 * @return	string
 	 */
 	public function escape_str($str, $like = FALSE)
 	{
@@ -415,15 +399,14 @@
 			return $str;
 		}
 
-		$str = remove_invisible_characters($str);
-		$str = str_replace("'", "''", $str);
+		$str = str_replace("'", "''", remove_invisible_characters($str));
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -475,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;
@@ -545,31 +527,32 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access  protected
-	 * @return  string
-	 */
-	protected function _error_message()
-	{
-		// If the error was during connection, no conn_id should be passed
-		$error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
-		return $error['message'];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access  protected
-	 * @return  integer
+	 * @return	array
 	 */
-	protected function _error_number()
+	public function error()
 	{
-		// Same as _error_message()
-		$error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
-		return $error['code'];
+		/* oci_error() returns an array that already contains the
+		 * 'code' and 'message' keys, so we can just return it.
+		 */
+		if (is_resource($this->curs_id))
+		{
+			return oci_error($this->curs_id);
+		}
+		elseif (is_resource($this->stmt_id))
+		{
+			return oci_error($this->stmt_id);
+		}
+		elseif (is_resource($this->conn_id))
+		{
+			return oci_error($this->conn_id);
+		}
+
+		return oci_error();
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index b4a24cd..7fcc809 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -67,15 +67,14 @@
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	public function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -84,54 +83,27 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
+		$sql .= $this->db->_escape_identifiers($table).' (';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
-
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
-				{
-					$sql .= ' UNSIGNED';
-				}
-
-				if (array_key_exists('DEFAULT', $attributes))
-				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
-				}
-
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
-
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
-				{
-					$sql .= ' AUTO_INCREMENT';
-				}
+				$sql .= "\n\t".$this->db->protect_identifiers($field).' '.$attributes['TYPE']
+					.((isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
+					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
+					.((isset($attributes['NULL']) && $attributes['NULL'] === TRUE) ? '' : ' NOT NULL')
+					.(isset($attributes['CONSTRAINT']) ? ' CONSTRAINT '.$attributes['CONSTRAINT'] : '');
 			}
 
 			// don't add a comma on the end of the last field
@@ -143,8 +115,8 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$primary_keys = $this->db->protect_identifiers($primary_keys);
+			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $primary_keys).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -153,20 +125,18 @@
 			{
 				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 COLUMNS (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).")";
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -202,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')
@@ -228,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;
@@ -249,12 +219,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 oci8_forge.php */
-/* Location: ./system/database/drivers/oci8/oci8_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/oci8/oci8_forge.php */
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index 0f69fa9..6f1b8b4 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php
index d60f98b..62dfb2f 100644
--- a/system/database/drivers/oci8/oci8_utility.php
+++ b/system/database/drivers/oci8/oci8_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 6ba39f0..acc2838 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -124,35 +124,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
-	 * @return	string
-	 */
-	function _version()
-	{
-		return "SELECT version() AS ver";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Execute the query
 	 *
 	 * @access	private called by the base class
@@ -316,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;
 	}
 
 	// --------------------------------------------------------------------
@@ -343,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)
 		{
@@ -414,27 +384,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		return odbc_errormsg($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return odbc_error($this->conn_id);
+		return array('code' => odbc_error($this->conn_id), 'message' => odbc_errormsg($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
@@ -646,4 +605,4 @@
 
 
 /* End of file odbc_driver.php */
-/* Location: ./system/database/drivers/odbc/odbc_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/odbc/odbc_driver.php */
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index e0ec687..acc2cad 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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 ba66085..d19fa24 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -38,15 +38,27 @@
  */
 class CI_DB_odbc_result extends CI_DB_result {
 
+	public $num_rows;
+
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
-		return @odbc_num_rows($this->result_id);
+		if (is_int($this->num_rows))
+		{
+			return $this->num_rows;
+		}
+
+		// Work-around for ODBC subdrivers that don't support num_rows()
+		if (($this->num_rows = @odbc_num_rows($this->result_id)) === -1)
+		{
+			$this->num_rows = count($this->result_array());
+		}
+
+		return $this->num_rows;
 	}
 
 	// --------------------------------------------------------------------
@@ -54,10 +66,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @odbc_num_fields($this->result_id);
 	}
@@ -69,15 +80,19 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		$num_fields = $this->num_fields();
+
+		if ($num_fields > 0)
 		{
-			$field_names[]	= odbc_field_name($this->result_id, $i);
+			for ($i = 1; $i <= $num_fields; $i++)
+			{
+				$field_names[] = odbc_field_name($this->result_id, $i);
+			}
 		}
 
 		return $field_names;
@@ -90,22 +105,19 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $odbc_index = 1, $c = $this->num_fields(); $i < $c; $i++, $odbc_index++)
 		{
-			$F				= new stdClass();
-			$F->name		= odbc_field_name($this->result_id, $i);
-			$F->type		= odbc_field_type($this->result_id, $i);
-			$F->max_length	= odbc_field_len($this->result_id, $i);
-			$F->primary_key = 0;
-			$F->default		= '';
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= odbc_field_name($this->result_id, $odbc_index);
+			$retval[$i]->type		= odbc_field_type($this->result_id, $odbc_index);
+			$retval[$i]->max_length		= odbc_field_len($this->result_id, $odbc_index);
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -233,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 */
\ No newline at end of file
+/* Location: ./system/database/drivers/odbc/odbc_result.php */
diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php
index bae3fe8..c146c17 100644
--- a/system/database/drivers/odbc/odbc_utility.php
+++ b/system/database/drivers/odbc/odbc_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index de2b0ab..0976477 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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();
 
@@ -289,29 +288,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
+	 * Database version number
 	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return $this->conn_id->getAttribute(PDO::ATTR_CLIENT_VERSION);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
 	}
 
 	// --------------------------------------------------------------------
@@ -510,33 +495,19 @@
 
 	/**
 	 * Insert ID
-	 * 
-	 * @access	public
-	 * @return	integer
+	 *
+	 * @return	int
 	 */
-	function insert_id($name=NULL)
+	public function insert_id($name = NULL)
 	{
-		if ($this->pdodriver == 'pgsql')
+		if ($this->pdodriver === 'pgsql' && $name === NULL && $this->version() >= '8.1')
 		{
-			//Convenience method for postgres insertid
-			$v = $this->_version();
-
-			$table	= func_num_args() > 0 ? func_get_arg(0) : NULL;
-
-			if ($table == NULL && $v >= '8.1')
-			{
-				$sql='SELECT LASTVAL() as ins_id';
-			}
-
-			$query = $this->query($sql);
-			$row   = $query->row();
-
-			return $row->ins_id;
+			$query = $this->query('SELECT LASTVAL() AS ins_id');
+			$query = $query->row();
+			return $query->ins_id;
 		}
-		else
-		{
-			return $this->conn_id->lastInsertId($name);
-		}
+
+		return $this->conn_id->lastInsertId($name);
 	}
 
 	// --------------------------------------------------------------------
@@ -558,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)
@@ -639,29 +609,30 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		$error_array = $this->conn_id->errorInfo();
-
-		return $error_array[2];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return $this->conn_id->errorCode();
+		$error = array('code' => '00000', 'message' => '');
+		$pdo_error = $this->conn_id->errorInfo();
+
+		if (empty($pdo_error[0]))
+		{
+			return $error;
+		}
+
+		$error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
+		if (isset($pdo_error[2]))
+		{
+			 $error['message'] = $pdo_error[2];
+		}
+
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
@@ -950,4 +921,4 @@
 }
 
 /* End of file pdo_driver.php */
-/* Location: ./system/database/drivers/pdo/pdo_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/pdo/pdo_driver.php */
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index 478b2db..87b6385 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php
index c333abc..309f194 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php
index 971ec88..c278c51 100644
--- a/system/database/drivers/pdo/pdo_utility.php
+++ b/system/database/drivers/pdo/pdo_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 42329bd..5d22af2 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -149,28 +149,41 @@
 	/**
 	 * Set client character set
 	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
+	 * @param       string
+	 * @return      bool
 	 */
-	function db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		// @todo - add support if needed
-		return TRUE;
+		return (pg_set_client_encoding($this->conn_id, $charset) === 0);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return "SELECT version() AS ver";
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($pg_version = pg_version($this->conn_id)) === FALSE)
+		{
+			return FALSE;
+		}
+
+		/* If PHP was compiled with PostgreSQL lib versions earlier
+		 * than 7.4, pg_version() won't return the server version
+		 * and so we'll have to fall back to running a query in
+		 * order to get it.
+		 */
+		return isset($pg_version['server'])
+			? $this->data_cache['version'] = $pg_version['server']
+			: parent::version();
 	}
 
 	// --------------------------------------------------------------------
@@ -209,18 +222,12 @@
 	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -228,9 +235,9 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
-		return @pg_exec($this->conn_id, "begin");
+		return @pg_query($this->conn_id, 'BEGIN');
 	}
 
 	// --------------------------------------------------------------------
@@ -238,23 +245,17 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		return @pg_exec($this->conn_id, "commit");
+		return @pg_query($this->conn_id, 'COMMIT');
 	}
 
 	// --------------------------------------------------------------------
@@ -262,23 +263,17 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		return @pg_exec($this->conn_id, "rollback");
+		return @pg_query($this->conn_id, 'ROLLBACK');
 	}
 
 	// --------------------------------------------------------------------
@@ -339,8 +334,7 @@
 	 */
 	function insert_id()
 	{
-		$v = $this->_version();
-		$v = $v['server'];
+		$v = $this->version();
 
 		$table	= func_num_args() > 0 ? func_get_arg(0) : NULL;
 		$column	= func_num_args() > 1 ? func_get_arg(1) : NULL;
@@ -389,8 +383,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;
@@ -459,27 +452,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		return pg_last_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return '';
+		return array('code' => '', 'message' => pg_last_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
@@ -604,16 +586,10 @@
 			$valstr[] = $key." = ".$val;
 		}
 
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
 		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
 
 		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
 
-		$sql .= $orderby.$limit;
-
 		return $sql;
 	}
 
@@ -664,9 +640,7 @@
 			$conditions .= implode("\n", $like);
 		}
 
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return "DELETE FROM ".$table.$conditions;
 	}
 
 	// --------------------------------------------------------------------
@@ -712,4 +686,4 @@
 
 
 /* End of file postgre_driver.php */
-/* Location: ./system/database/drivers/postgre/postgre_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/postgre/postgre_driver.php */
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index 756fd34..5771005 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -88,7 +88,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);
 
 				$is_unsigned = (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE);
 
@@ -203,10 +203,10 @@
 
 		if (count($primary_keys) > 0)
 		{
-			// Something seems to break when passing an array to _protect_identifiers()
+			// Something seems to break when passing an array to protect_identifiers()
 			foreach ($primary_keys as $index => $key)
 			{
-				$primary_keys[$index] = $this->db->_protect_identifiers($key);
+				$primary_keys[$index] = $this->db->protect_identifiers($key);
 			}
 
 			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
@@ -220,11 +220,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));
 				}
 
 				foreach ($key as $field)
@@ -267,19 +267,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;
@@ -299,10 +299,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 postgre_forge.php */
-/* Location: ./system/database/drivers/postgre/postgre_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/postgre/postgre_forge.php */
diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index 9161bf9..12d7547 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php
index dffd8c5..e31a6db 100644
--- a/system/database/drivers/postgre/postgre_utility.php
+++ b/system/database/drivers/postgre/postgre_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Postgre Utility Class
  *
@@ -39,12 +37,11 @@
 	/**
 	 * List databases
 	 *
-	 * @access	private
-	 * @return	bool
+	 * @return	string
 	 */
-	function _list_databases()
+	public function _list_databases()
 	{
-		return "SELECT datname FROM pg_database";
+		return 'SELECT datname FROM pg_database';
 	}
 
 	// --------------------------------------------------------------------
@@ -52,15 +49,12 @@
 	/**
 	 * Optimize table query
 	 *
-	 * Is table optimization supported in Postgre?
-	 *
-	 * @access	private
 	 * @param	string	the table name
-	 * @return	object
+	 * @return	string
 	 */
-	function _optimize_table($table)
+	public function _optimize_table($table)
 	{
-		return FALSE;
+		return 'REINDEX TABLE '.$this->db->protect_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
@@ -68,13 +62,10 @@
 	/**
 	 * Repair table query
 	 *
-	 * Are table repairs supported in Postgre?
-	 *
-	 * @access	private
 	 * @param	string	the table name
-	 * @return	object
+	 * @return	bool
 	 */
-	function _repair_table($table)
+	public function _repair_table($table)
 	{
 		return FALSE;
 	}
@@ -84,7 +75,6 @@
 	/**
 	 * Postgre Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
@@ -95,6 +85,5 @@
 	}
 }
 
-
 /* End of file postgre_utility.php */
-/* Location: ./system/database/drivers/postgre/postgre_utility.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/postgre/postgre_utility.php */
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 28c3cae..55d9bfd 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -141,30 +141,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
+	 * Database version number
 	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return sqlite_libversion();
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = sqlite_libversion();
 	}
 
 	// --------------------------------------------------------------------
@@ -358,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;
@@ -428,27 +412,18 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		return sqlite_error_string(sqlite_last_error($this->conn_id));
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return sqlite_last_error($this->conn_id);
+		$error = array('code' => sqlite_last_error($this->conn_id));
+		$error['message'] = sqlite_error_string($error['code']);
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
@@ -667,4 +642,4 @@
 
 
 /* End of file sqlite_driver.php */
-/* Location: ./system/database/drivers/sqlite/sqlite_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/sqlite/sqlite_driver.php */
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index 2b723be..7fc5314 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -89,7 +89,7 @@
 		$sql = 'CREATE TABLE ';
 
 		// IF NOT EXISTS added to SQLite in 3.3.0
-		if ($if_not_exists === TRUE && version_compare($this->db->_version(), '3.3.0', '>=') === TRUE)
+		if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE)
 		{
 			$sql .= 'IF NOT EXISTS ';
 		}
@@ -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,10 +268,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 sqlite_forge.php */
-/* Location: ./system/database/drivers/sqlite/sqlite_forge.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/sqlite/sqlite_forge.php */
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
index 74c0dc5..ac2235c 100644
--- a/system/database/drivers/sqlite/sqlite_result.php
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php
index f00687e..9f9ddca 100644
--- a/system/database/drivers/sqlite/sqlite_utility.php
+++ b/system/database/drivers/sqlite/sqlite_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLite Utility Class
  *
@@ -40,20 +38,15 @@
 	 * List databases
 	 *
 	 * I don't believe you can do a database listing with SQLite
-	 * since each database is its own file.  I suppose we could
+	 * since each database is its own file. I suppose we could
 	 * try reading a directory looking for SQLite files, but
 	 * that doesn't seem like a terribly good idea
 	 *
-	 * @access	private
 	 * @return	bool
 	 */
-	function _list_databases()
+	public function _list_databases()
 	{
-		if ($this->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return array();
+		return ($this->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -61,14 +54,12 @@
 	/**
 	 * Optimize table query
 	 *
-	 * Is optimization even supported in SQLite?
-	 *
-	 * @access	private
 	 * @param	string	the table name
-	 * @return	object
+	 * @return	bool
 	 */
-	function _optimize_table($table)
+	public function _optimize_table($table)
 	{
+		// Not supported
 		return FALSE;
 	}
 
@@ -77,14 +68,12 @@
 	/**
 	 * Repair table query
 	 *
-	 * Are table repairs even supported in SQLite?
-	 *
-	 * @access	private
 	 * @param	string	the table name
-	 * @return	object
+	 * @return	bool
 	 */
-	function _repair_table($table)
+	public function _repair_table($table)
 	{
+		// Not supported
 		return FALSE;
 	}
 
@@ -93,16 +82,16 @@
 	/**
 	 * SQLite Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	public function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
 	}
+
 }
 
 /* End of file sqlite_utility.php */
-/* Location: ./system/database/drivers/sqlite/sqlite_utility.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/sqlite/sqlite_utility.php */
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 9c50209..5e920cb 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -144,22 +144,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Execute the query
 	 *
 	 * @access	private called by the base class
@@ -333,15 +317,23 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Version number query string
-	*
-	* @access public
-	* @return string
-	*/
-	function _version()
+	 * Database version number
+	 *
+	 * @return	string
+	 */
+	public function version()
 	{
-		$info = sqlsrv_server_info($this->conn_id);
-		return sprintf("select '%s' as ver", $info['SQLServerVersion']);
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($info = sqlsrv_server_info($this->conn_id)) === FALSE)
+		{
+			return FALSE;
+		}
+
+		return $this->data_cache['version'] = $info['SQLServerVersion'];
 	}
 
 	// --------------------------------------------------------------------
@@ -422,29 +414,39 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		$error = array_shift(sqlsrv_errors());
-		return !empty($error['message']) ? $error['message'] : null;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @return	integer
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		$error = array_shift(sqlsrv_errors());
-		return isset($error['SQLSTATE']) ? $error['SQLSTATE'] : null;
+		$error = array('code' => '00000', 'message' => '');
+		$sqlsrv_errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
+
+		if ( ! is_array($sqlsrv_errors))
+		{
+			return $error;
+		}
+
+		$sqlsrv_error = array_shift($sqlsrv_errors);
+		if (isset($sqlsrv_error['SQLSTATE']))
+		{
+			$error['code'] = isset($sqlsrv_error['code']) ? $sqlsrv_error['SQLSTATE'].'/'.$sqlsrv_error['code'] : $sqlsrv_error['SQLSTATE'];
+		}
+		elseif (isset($sqlsrv_error['code']))
+		{
+			$error['code'] = $sqlsrv_error['code'];
+		}
+
+		if (isset($sqlsrv_error['message']))
+		{
+			$error['message'] = $sqlsrv_error['message'];
+		}
+
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index 2a77669..cd061dd 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index 1ee19c2..52d338a 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php
index e96df96..44e6faf 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_utility.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php
index c46c4d1..e5e32c4 100644
--- a/system/helpers/array_helper.php
+++ b/system/helpers/array_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 668b034..5787965 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -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/cookie_helper.php b/system/helpers/cookie_helper.php
index 7b439c4..b46f805 100644
--- a/system/helpers/cookie_helper.php
+++ b/system/helpers/cookie_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index 9e58d86..2a34cf9 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php
index be65b38..1d67e05 100644
--- a/system/helpers/directory_helper.php
+++ b/system/helpers/directory_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index aea948d..96ff29d 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Download Helpers
  *
@@ -47,67 +45,84 @@
  * @access	public
  * @param	string	filename
  * @param	mixed	the data to be downloaded
+ * @param	bool	wether to try and send the actual file MIME type
  * @return	void
  */
 if ( ! function_exists('force_download'))
 {
-	function force_download($filename = '', $data = '')
+	function force_download($filename = '', $data = '', $set_mime = FALSE)
 	{
 		if ($filename == '' OR $data == '')
 		{
 			return FALSE;
 		}
 
-		// Try to determine if the filename includes a file extension.
-		// We need it in order to set the MIME type
-		if (FALSE === strpos($filename, '.'))
-		{
-			return FALSE;
-		}
+		// Set the default MIME type to send
+		$mime = 'application/octet-stream';
 
-		// Grab the file extension
 		$x = explode('.', $filename);
 		$extension = end($x);
 
-		// Load the mime types
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+		if ($set_mime === TRUE)
 		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-		}
-		elseif (is_file(APPPATH.'config/mimes.php'))
-		{
-			include(APPPATH.'config/mimes.php');
+			if (count($x) === 1 OR $extension === '')
+			{
+				/* If we're going to detect the MIME type,
+				 * we'll need a file extension.
+				 */
+				return FALSE;
+			}
+
+			// Load the mime types
+			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
+			}
+			elseif (is_file(APPPATH.'config/mimes.php'))
+			{
+				include(APPPATH.'config/mimes.php');
+			}
+
+			// Only change the default MIME if we can find one
+			if (isset($mimes[$extension]))
+			{
+				$mime = is_array($mimes[$extension]) ? $mimes[$extension][0] : $mimes[$extension];
+			}
 		}
 
-		// Set a default mime if we can't find it
-		if ( ! isset($mimes[$extension]))
+		/* It was reported that browsers on Android 2.1 (and possibly older as well)
+		 * need to have the filename extension upper-cased in order to be able to
+		 * download it.
+		 *
+		 * Reference: http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
+		 */
+		if (count($x) !== 1 && isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Android\s(1|2\.[01])/', $_SERVER['HTTP_USER_AGENT']))
 		{
-			$mime = 'application/octet-stream';
+			$x[count($x) - 1] = strtoupper($extension);
+			$filename = implode('.', $x);
 		}
-		else
-		{
-			$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
-		}
-		
+
 		// Generate the server headers
-		header('Content-Type: "'.$mime.'"');
+		header('Content-Type: '.$mime);
 		header('Content-Disposition: attachment; filename="'.$filename.'"');
 		header('Expires: 0');
-		header("Content-Transfer-Encoding: binary");
-		header("Content-Length: ".strlen($data));
-		header('Pragma: no-cache');
+		header('Content-Transfer-Encoding: binary');
+		header('Content-Length: '.strlen($data));
 
-		// Internet Explorer-specific headers.
-		if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
+		// Internet Explorer-specific headers
+		if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
 		{
 			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 			header('Pragma: public');
 		}
+		else
+		{
+			header('Pragma: no-cache');
+		}
 
 		exit($data);
 	}
 }
 
-
 /* End of file download_helper.php */
-/* Location: ./system/helpers/download_helper.php */
\ No newline at end of file
+/* Location: ./system/helpers/download_helper.php */
diff --git a/system/helpers/email_helper.php b/system/helpers/email_helper.php
index f184031..b87bce6 100644
--- a/system/helpers/email_helper.php
+++ b/system/helpers/email_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 2d4b10e..3fd6b82 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index bed2cb2..37337d9 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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();
 		}
@@ -315,6 +314,28 @@
 {
 	function form_dropdown($name = '', $options = array(), $selected = array(), $extra = '')
 	{
+    // If name is really an array then we'll call the function again using the array
+    if (is_array($name) && isset($name['name']))
+    {
+      
+      if ( ! isset($name['options'])) 
+      {
+        $name['options'] = array();
+      }
+      
+      if ( ! isset($name['selected'])) 
+      {
+        $name['selected'] = array();
+      }
+      
+      if ( ! isset($name['extra'])) 
+      {
+        $name['extra'] = '';
+      }
+      
+      return form_dropdown($name['name'], $name['options'], $name['selected'], $name['extra']);
+    }
+    
 		if ( ! is_array($selected))
 		{
 			$selected = array($selected);
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index 72970d9..b8c4f36 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/inflector_helper.php b/system/helpers/inflector_helper.php
index 2069a19..9cf015d 100644
--- a/system/helpers/inflector_helper.php
+++ b/system/helpers/inflector_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Inflector Helpers
  *
@@ -34,10 +32,9 @@
  * @subpackage	Helpers
  * @category	Helpers
  * @author		EllisLab Dev Team
- * @link		http://codeigniter.com/user_guide/helpers/directory_helper.html
+ * @link		http://codeigniter.com/user_guide/helpers/inflector_helper.html
  */
 
-
 // --------------------------------------------------------------------
 
 /**
@@ -45,7 +42,6 @@
  *
  * Takes a plural word and makes it singular
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -55,37 +51,51 @@
 	{
 		$result = strval($str);
 
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
+
 		$singular_rules = array(
-			'/(matr)ices$/'			=> '\1ix',
-			'/(vert|ind)ices$/'		=> '\1ex',
-			'/^(ox)en/'				=> '\1',
-			'/(alias)es$/'			=> '\1',
-			'/([octop|vir])i$/'		=> '\1us',
-			'/(cris|ax|test)es$/'	=> '\1is',
-			'/(shoe)s$/'			=> '\1',
-			'/(o)es$/'				=> '\1',
-			'/(bus|campus)es$/'		=> '\1',
-			'/([m|l])ice$/'			=> '\1ouse',
-			'/(x|ch|ss|sh)es$/'		=> '\1',
-			'/(m)ovies$/'			=> '\1\2ovie',
-			'/(s)eries$/'			=> '\1\2eries',
-			'/([^aeiouy]|qu)ies$/'	=> '\1y',
-			'/([lr])ves$/'			=> '\1f',
-			'/(tive)s$/'			=> '\1',
-			'/(hive)s$/'			=> '\1',
-			'/([^f])ves$/'			=> '\1fe',
-			'/(^analy)ses$/'		=> '\1sis',
+			'/(matr)ices$/'         => '\1ix',
+			'/(vert|ind)ices$/'     => '\1ex',
+			'/^(ox)en/'             => '\1',
+			'/(alias)es$/'          => '\1',
+			'/([octop|vir])i$/'     => '\1us',
+			'/(cris|ax|test)es$/'   => '\1is',
+			'/(shoe)s$/'            => '\1',
+			'/(o)es$/'              => '\1',
+			'/(bus|campus)es$/'     => '\1',
+			'/([m|l])ice$/'         => '\1ouse',
+			'/(x|ch|ss|sh)es$/'     => '\1',
+			'/(m)ovies$/'           => '\1\2ovie',
+			'/(s)eries$/'           => '\1\2eries',
+			'/([^aeiouy]|qu)ies$/'  => '\1y',
+			'/([lr])ves$/'          => '\1f',
+			'/(tive)s$/'            => '\1',
+			'/(hive)s$/'            => '\1',
+			'/([^f])ves$/'          => '\1fe',
+			'/(^analy)ses$/'        => '\1sis',
 			'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
-			'/([ti])a$/'			=> '\1um',
-			'/(p)eople$/'			=> '\1\2erson',
-			'/(m)en$/'				=> '\1an',
-			'/(s)tatuses$/'			=> '\1\2tatus',
-			'/(c)hildren$/'			=> '\1\2hild',
-			'/(n)ews$/'				=> '\1\2ews',
-			'/([^u])s$/'			=> '\1',
+			'/([ti])a$/'            => '\1um',
+			'/(p)eople$/'           => '\1\2erson',
+			'/(m)en$/'              => '\1an',
+			'/(s)tatuses$/'         => '\1\2tatus',
+			'/(c)hildren$/'         => '\1\2hild',
+			'/(n)ews$/'             => '\1\2ews',
+			'/([^us])s$/'           => '\1',
 		);
 
-		return preg_replace(array_keys($singular_rules), $singular_rules, $result);
+		foreach ($singular_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
@@ -96,7 +106,6 @@
  *
  * Takes a singular word and makes it plural
  *
- * @access	public
  * @param	string
  * @param	bool
  * @return	str
@@ -107,29 +116,43 @@
 	{
 		$result = strval($str);
 
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
+
 		$plural_rules = array(
-			'/^(ox)$/'					=> '\1\2en',	 // ox
-			'/([m|l])ouse$/'			=> '\1ice',	  // mouse, louse
-			'/(matr|vert|ind)ix|ex$/'	=> '\1ices',	 // matrix, vertex, index
-			'/(x|ch|ss|sh)$/'			=> '\1es',	   // search, switch, fix, box, process, address
-			'/([^aeiouy]|qu)y$/'		=> '\1ies',	  // query, ability, agency
-			'/(hive)$/'					=> '\1s',		// archive, hive
-			'/(?:([^f])fe|([lr])f)$/'	=> '\1\2ves',	// half, safe, wife
-			'/sis$/'					=> 'ses',		// basis, diagnosis
-			'/([ti])um$/'				=> '\1a',		// datum, medium
-			'/(p)erson$/'				=> '\1eople',	// person, salesperson
-			'/(m)an$/'					=> '\1en',	   // man, woman, spokesman
-			'/(c)hild$/'				=> '\1hildren',  // child
-			'/(buffal|tomat)o$/'		=> '\1\2oes',	// buffalo, tomato
-			'/(bu|campu)s$/'			=> '\1\2ses',	// bus, campus
-			'/(alias|status|virus)/'	=> '\1es',	   // alias
-			'/(octop)us$/'				=> '\1i',		// octopus
-			'/(ax|cris|test)is$/'		=> '\1es',	   // axis, crisis
-			'/s$/'						=> 's',		  // no change (compatibility)
-			'/$/'						=> 's',
+			'/^(ox)$/'                 => '\1\2en',     // ox
+			'/([m|l])ouse$/'           => '\1ice',      // mouse, louse
+			'/(matr|vert|ind)ix|ex$/'  => '\1ices',     // matrix, vertex, index
+			'/(x|ch|ss|sh)$/'          => '\1es',       // search, switch, fix, box, process, address
+			'/([^aeiouy]|qu)y$/'       => '\1ies',      // query, ability, agency
+			'/(hive)$/'                => '\1s',        // archive, hive
+			'/(?:([^f])fe|([lr])f)$/'  => '\1\2ves',    // half, safe, wife
+			'/sis$/'                   => 'ses',        // basis, diagnosis
+			'/([ti])um$/'              => '\1a',        // datum, medium
+			'/(p)erson$/'              => '\1eople',    // person, salesperson
+			'/(m)an$/'                 => '\1en',       // man, woman, spokesman
+			'/(c)hild$/'               => '\1hildren',  // child
+			'/(buffal|tomat)o$/'       => '\1\2oes',    // buffalo, tomato
+			'/(bu|campu)s$/'           => '\1\2ses',    // bus, campus
+			'/(alias|status|virus)$/'  => '\1es',       // alias
+			'/(octop)us$/'             => '\1i',        // octopus
+			'/(ax|cris|test)is$/'      => '\1es',       // axis, crisis
+			'/s$/'                     => 's',          // no change (compatibility)
+			'/$/'                      => 's',
 		);
 
-		return preg_replace(array_keys($plural_rules), $plural_rules, $result);
+		foreach ($plural_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
@@ -140,7 +163,6 @@
  *
  * Takes multiple words separated by spaces or underscores and camelizes them
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -148,7 +170,7 @@
 {
 	function camelize($str)
 	{
-		return substr(str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', $str))), 1);
+		return str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', strtolower($str))));
 	}
 }
 
@@ -159,7 +181,6 @@
  *
  * Takes multiple words separated by spaces and underscores them
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -178,7 +199,6 @@
  *
  * Takes multiple words separated by the separator and changes them to spaces
  *
- * @access	public
  * @param	string $str
  * @param 	string $separator
  * @return	str
@@ -191,5 +211,22 @@
 	}
 }
 
+/**
+ * Checks if the given word has a plural version.
+ *
+ * @param   string  the word to check
+ * @return  bool    if the word is countable
+ */
+if ( ! function_exists('is_countable'))
+{
+	function is_countable($word)
+	{
+		return ! (in_array(strtolower(strval($word)), array(
+			'equipment', 'information', 'rice', 'money',
+			'species', 'series', 'fish', 'meta'
+		)));
+	}
+}
+
 /* End of file inflector_helper.php */
 /* Location: ./system/helpers/inflector_helper.php */
diff --git a/system/helpers/language_helper.php b/system/helpers/language_helper.php
index a83580a..1d66df5 100644
--- a/system/helpers/language_helper.php
+++ b/system/helpers/language_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/number_helper.php b/system/helpers/number_helper.php
index 331b468..b6c823d 100644
--- a/system/helpers/number_helper.php
+++ b/system/helpers/number_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php
index cd87a73..2eb85fe 100644
--- a/system/helpers/path_helper.php
+++ b/system/helpers/path_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 99fda56..e05e947 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php
index 700f448..cc903bc 100644
--- a/system/helpers/smiley_helper.php
+++ b/system/helpers/smiley_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php
index 04d51c2..607a12b 100644
--- a/system/helpers/string_helper.php
+++ b/system/helpers/string_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 842a31d..7591bac 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -300,9 +300,9 @@
 
 		// Replace any existing PHP tags to temporary markers so they don't accidentally
 		// break the string out of PHP, and thus, thwart the highlighting.
-
 		$str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'),
-							array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str);
+					array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
+					$str);
 
 		// The highlight_string function requires that the text be surrounded
 		// by PHP tags, which we will remove later
@@ -311,25 +311,15 @@
 		// All the magic happens here, baby!
 		$str = highlight_string($str, TRUE);
 
-		// Prior to PHP 5, the highligh function used icky <font> tags
-		// so we'll replace them with <span> tags.
-
-		if (abs(PHP_VERSION) < 5)
-		{
-			$str = str_replace(array('<font ', '</font>'), array('<span ', '</span>'), $str);
-			$str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str);
-		}
-
 		// Remove our artificially added PHP, and the syntax highlighting that came with it
 		$str = preg_replace('/<span style="color: #([A-Z0-9]+)">&lt;\?php(&nbsp;| )/i', '<span style="color: #$1">', $str);
 		$str = preg_replace('/(<span style="color: #[A-Z0-9]+">.*?)\?&gt;<\/span>\n<\/span>\n<\/code>/is', "$1</span>\n</span>\n</code>", $str);
 		$str = preg_replace('/<span style="color: #[A-Z0-9]+"\><\/span>/i', '', $str);
 
 		// Replace our markers back to PHP tags.
-		$str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
-							array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'), $str);
-
-		return $str;
+		return str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
+					array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'),
+					$str);
 	}
 }
 
@@ -544,4 +534,4 @@
 }
 
 /* End of file text_helper.php */
-/* Location: ./system/helpers/text_helper.php */
\ No newline at end of file
+/* Location: ./system/helpers/text_helper.php */
diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php
index c49348e..9b19c7c 100644
--- a/system/helpers/typography_helper.php
+++ b/system/helpers/typography_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 2cbcd9d..2ae1fd3 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -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/helpers/xml_helper.php b/system/helpers/xml_helper.php
index 5242193..f3ff576 100644
--- a/system/helpers/xml_helper.php
+++ b/system/helpers/xml_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php
index bf61db0..2d477e6 100644
--- a/system/language/english/calendar_lang.php
+++ b/system/language/english/calendar_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index cd6cf39..5335637 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/db_lang.php b/system/language/english/db_lang.php
index 2a91597..a135d1a 100644
--- a/system/language/english/db_lang.php
+++ b/system/language/english/db_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/email_lang.php b/system/language/english/email_lang.php
index e0ef427..23296a2 100644
--- a/system/language/english/email_lang.php
+++ b/system/language/english/email_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 6afa37a..6cf0b46 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
@@ -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/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index 18ca927..4e39e43 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/imglib_lang.php b/system/language/english/imglib_lang.php
index fbb92ab..67ca942 100644
--- a/system/language/english/imglib_lang.php
+++ b/system/language/english/imglib_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php
index 9765562..2085cee 100644
--- a/system/language/english/migration_lang.php
+++ b/system/language/english/migration_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/number_lang.php b/system/language/english/number_lang.php
index 5dfd882..0c19ec6 100644
--- a/system/language/english/number_lang.php
+++ b/system/language/english/number_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php
index 1d10efa..11d7912 100644
--- a/system/language/english/profiler_lang.php
+++ b/system/language/english/profiler_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/unit_test_lang.php b/system/language/english/unit_test_lang.php
index ed98439..3a8e144 100644
--- a/system/language/english/unit_test_lang.php
+++ b/system/language/english/unit_test_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/language/english/upload_lang.php b/system/language/english/upload_lang.php
index a9a2fe7..ec5de1e 100644
--- a/system/language/english/upload_lang.php
+++ b/system/language/english/upload_lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php
index e9cc110..b89e5ab 100644
--- a/system/libraries/Cache/Cache.php
+++ b/system/libraries/Cache/Cache.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php
index a3dd469..c387a30 100644
--- a/system/libraries/Cache/drivers/Cache_apc.php
+++ b/system/libraries/Cache/drivers/Cache_apc.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php
index fcd55da..c9767e4 100644
--- a/system/libraries/Cache/drivers/Cache_dummy.php
+++ b/system/libraries/Cache/drivers/Cache_dummy.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index a960730..c0be0de 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php
index ffe6f2f..b8f2d7e 100644
--- a/system/libraries/Cache/drivers/Cache_memcached.php
+++ b/system/libraries/Cache/drivers/Cache_memcached.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php
index a05a7ba..6c04de8 100644
--- a/system/libraries/Calendar.php
+++ b/system/libraries/Calendar.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php
index 10b5362..60a1e52 100644
--- a/system/libraries/Cart.php
+++ b/system/libraries/Cart.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index 4e89443..9a073b3 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 922107e..f30fe40 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Email Class
  *
@@ -40,55 +38,55 @@
  */
 class CI_Email {
 
-	public $useragent		= "CodeIgniter";
-	public $mailpath		= "/usr/sbin/sendmail";	// Sendmail path
-	public $protocol		= "mail";	// mail/sendmail/smtp
-	public $smtp_host		= "";		// SMTP Server.  Example: mail.earthlink.net
-	public $smtp_user		= "";		// SMTP Username
-	public $smtp_pass		= "";		// SMTP Password
-	public $smtp_port		= "25";		// SMTP Port
-	public $smtp_timeout	= 5;		// SMTP Timeout in seconds
-	public $smtp_crypto	= "";		// SMTP Encryption. Can be null, tls or ssl.
-	public $wordwrap		= TRUE;		// TRUE/FALSE  Turns word-wrap on/off
-	public $wrapchars		= "76";		// Number of characters to wrap at.
-	public $mailtype		= "text";	// text/html  Defines email formatting
-	public $charset		= "utf-8";	// Default char set: iso-8859-1 or us-ascii
-	public $multipart		= "mixed";	// "mixed" (in the body) or "related" (separate)
-	public $alt_message	= '';		// Alternative message for HTML emails
-	public $validate		= FALSE;	// TRUE/FALSE.  Enables email validation
-	public $priority		= "3";		// Default priority (1 - 5)
-	public $newline		= "\n";		// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
-	public $crlf			= "\n";		// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
+	public $useragent	= 'CodeIgniter';
+	public $mailpath	= '/usr/sbin/sendmail';	// Sendmail path
+	public $protocol	= 'mail';		// mail/sendmail/smtp
+	public $smtp_host	= '';			// SMTP Server. Example: mail.earthlink.net
+	public $smtp_user	= '';			// SMTP Username
+	public $smtp_pass	= '';			// SMTP Password
+	public $smtp_port	= 25;			// SMTP Port
+	public $smtp_timeout	= 5;			// SMTP Timeout in seconds
+	public $smtp_crypto	= '';			// SMTP Encryption. Can be null, tls or ssl.
+	public $wordwrap	= TRUE;			// TRUE/FALSE  Turns word-wrap on/off
+	public $wrapchars	= 76;			// Number of characters to wrap at.
+	public $mailtype	= 'text';		// text/html  Defines email formatting
+	public $charset		= 'utf-8';		// Default char set: iso-8859-1 or us-ascii
+	public $multipart	= 'mixed';		// "mixed" (in the body) or "related" (separate)
+	public $alt_message	= '';			// Alternative message for HTML emails
+	public $validate	= FALSE;		// TRUE/FALSE.  Enables email validation
+	public $priority	= 3;			// Default priority (1 - 5)
+	public $newline		= "\n";			// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
+	public $crlf		= "\n";			// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
 									// even on the receiving end think they need to muck with CRLFs, so using "\n", while
 									// distasteful, is the only thing that seems to work for all environments.
 	public $send_multipart	= TRUE;		// TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.
-	public $bcc_batch_mode	= FALSE;	// TRUE/FALSE  Turns on/off Bcc batch feature
+	public $bcc_batch_mode	= FALSE;	// TRUE/FALSE - Turns on/off Bcc batch feature
 	public $bcc_batch_size	= 200;		// If bcc_batch_mode = TRUE, sets max number of Bccs in each batch
-	private $_safe_mode		= FALSE;
-	private $_subject		= "";
-	private $_body			= "";
-	private $_finalbody		= "";
-	private $_alt_boundary	= "";
-	private $_atc_boundary	= "";
-	private $_header_str	= "";
-	private $_smtp_connect	= "";
-	private $_encoding		= "8bit";
-	private $_IP			= FALSE;
-	private $_smtp_auth		= FALSE;
-	private $_replyto_flag	= FALSE;
-	private $_debug_msg		= array();
-	private $_recipients	= array();
-	private $_cc_array		= array();
-	private $_bcc_array		= array();
-	private $_headers		= array();
-	private $_attach_name	= array();
-	private $_attach_type	= array();
-	private $_attach_disp	= array();
-	private $_protocols		= array('mail', 'sendmail', 'smtp');
-	private $_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)
-	private $_bit_depths	= array('7bit', '8bit');
-	private $_priorities	= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
 
+	protected $_safe_mode		= FALSE;
+	protected $_subject		= '';
+	protected $_body		= '';
+	protected $_finalbody		= '';
+	protected $_alt_boundary	= '';
+	protected $_atc_boundary	= '';
+	protected $_header_str		= '';
+	protected $_smtp_connect	= '';
+	protected $_encoding		= '8bit';
+	protected $_IP			= FALSE;
+	protected $_smtp_auth		= FALSE;
+	protected $_replyto_flag	= FALSE;
+	protected $_debug_msg		= array();
+	protected $_recipients		= array();
+	protected $_cc_array		= array();
+	protected $_bcc_array		= array();
+	protected $_headers		= array();
+	protected $_attach_name		= array();
+	protected $_attach_type		= array();
+	protected $_attach_disp		= array();
+	protected $_protocols		= array('mail', 'sendmail', 'smtp');
+	protected $_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)
+	protected $_bit_depths		= array('7bit', '8bit');
+	protected $_priorities		= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
 
 	/**
 	 * Constructor - Sets Email Preferences
@@ -103,11 +101,11 @@
 		}
 		else
 		{
-			$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-			$this->_safe_mode = (bool) @ini_get("safe_mode");
+			$this->_smtp_auth = ! ($this->smtp_user == '' && $this->smtp_pass == '');
+			$this->_safe_mode = (bool) @ini_get('safe_mode');
 		}
 
-		log_message('debug', "Email Class Initialized");
+		log_message('debug', 'Email Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -115,7 +113,6 @@
 	/**
 	 * Initialize preferences
 	 *
-	 * @access	public
 	 * @param	array
 	 * @return	void
 	 */
@@ -139,8 +136,8 @@
 		}
 		$this->clear();
 
-		$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-		$this->_safe_mode = (bool) @ini_get("safe_mode");
+		$this->_smtp_auth = ! ($this->smtp_user == '' && $this->smtp_pass == '');
+		$this->_safe_mode = (bool) @ini_get('safe_mode');
 
 		return $this;
 	}
@@ -150,17 +147,16 @@
 	/**
 	 * Initialize the Email Data
 	 *
-	 * @access	public
 	 * @param	bool
-	 * @return	void
+	 * @return	object
 	 */
 	public function clear($clear_attachments = FALSE)
 	{
-		$this->_subject		= "";
-		$this->_body		= "";
-		$this->_finalbody	= "";
-		$this->_header_str	= "";
-		$this->_replyto_flag = FALSE;
+		$this->_subject		= '';
+		$this->_body		= '';
+		$this->_finalbody	= '';
+		$this->_header_str	= '';
+		$this->_replyto_flag	= FALSE;
 		$this->_recipients	= array();
 		$this->_cc_array	= array();
 		$this->_bcc_array	= array();
@@ -185,14 +181,13 @@
 	/**
 	 * Set FROM
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function from($from, $name = '')
 	{
-		if (preg_match( '/\<(.*)\>/', $from, $match))
+		if (preg_match('/\<(.*)\>/', $from, $match))
 		{
 			$from = $match[1];
 		}
@@ -228,14 +223,13 @@
 	/**
 	 * Set Reply-to
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function reply_to($replyto, $name = '')
 	{
-		if (preg_match( '/\<(.*)\>/', $replyto, $match))
+		if (preg_match('/\<(.*)\>/', $replyto, $match))
 		{
 			$replyto = $match[1];
 		}
@@ -266,9 +260,8 @@
 	/**
 	 * Set Recipients
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function to($to)
 	{
@@ -282,17 +275,17 @@
 
 		if ($this->_get_protocol() !== 'mail')
 		{
-			$this->_set_header('To', implode(", ", $to));
+			$this->_set_header('To', implode(', ', $to));
 		}
 
 		switch ($this->_get_protocol())
 		{
-			case 'smtp'		:
+			case 'smtp':
 				$this->_recipients = $to;
 			break;
-			case 'sendmail'	:
-			case 'mail'		:
-				$this->_recipients = implode(", ", $to);
+			case 'sendmail':
+			case 'mail':
+				$this->_recipients = implode(', ', $to);
 			break;
 		}
 
@@ -304,9 +297,8 @@
 	/**
 	 * Set CC
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function cc($cc)
 	{
@@ -318,7 +310,7 @@
 			$this->validate_email($cc);
 		}
 
-		$this->_set_header('Cc', implode(", ", $cc));
+		$this->_set_header('Cc', implode(', ', $cc));
 
 		if ($this->_get_protocol() === 'smtp')
 		{
@@ -333,10 +325,9 @@
 	/**
 	 * Set BCC
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function bcc($bcc, $limit = '')
 	{
@@ -360,7 +351,7 @@
 		}
 		else
 		{
-			$this->_set_header('Bcc', implode(", ", $bcc));
+			$this->_set_header('Bcc', implode(', ', $bcc));
 		}
 
 		return $this;
@@ -371,9 +362,8 @@
 	/**
 	 * Set Email Subject
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function subject($subject)
 	{
@@ -387,13 +377,12 @@
 	/**
 	 * Set Body
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function message($body)
 	{
-		$this->_body = rtrim(str_replace("\r", "", $body));
+		$this->_body = rtrim(str_replace("\r", '', $body));
 
 		/* strip slashes only if magic quotes is ON
 		   if we do it with magic quotes OFF, it strips real, user-inputted chars.
@@ -414,9 +403,8 @@
 	/**
 	 * Assign file attachments
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function attach($filename, $disposition = '', $newname = NULL)
 	{
@@ -431,7 +419,6 @@
 	/**
 	 * Add a Header Item
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @param	string
 	 * @return	void
@@ -446,7 +433,6 @@
 	/**
 	 * Convert a String to an Array
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	array
 	 */
@@ -460,8 +446,7 @@
 			}
 			else
 			{
-				$email = trim($email);
-				settype($email, "array");
+				$email = (array) trim($email);
 			}
 		}
 		return $email;
@@ -472,9 +457,8 @@
 	/**
 	 * Set Multipart Value
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_alt_message($str = '')
 	{
@@ -487,9 +471,8 @@
 	/**
 	 * Set Mailtype
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_mailtype($type = 'text')
 	{
@@ -502,9 +485,8 @@
 	/**
 	 * Set Wordwrap
 	 *
-	 * @access	public
 	 * @param	bool
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_wordwrap($wordwrap = TRUE)
 	{
@@ -517,13 +499,12 @@
 	/**
 	 * Set Protocol
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_protocol($protocol = 'mail')
 	{
-		$this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol);
+		$this->protocol = in_array($protocol, $this->_protocols, TRUE) ? strtolower($protocol) : 'mail';
 		return $this;
 	}
 
@@ -532,19 +513,12 @@
 	/**
 	 * Set Priority
 	 *
-	 * @access	public
-	 * @param	integer
-	 * @return	void
+	 * @param	int
+	 * @return	object
 	 */
 	public function set_priority($n = 3)
 	{
-		if ( ! is_numeric($n) OR $n < 1 OR $n > 5)
-		{
-			$this->priority = 3;
-			return;
-		}
-
-		$this->priority = (int) $n;
+		$this->priority = preg_match('/^[1-5]$/', $n) ? (int) $n : 3;
 		return $this;
 	}
 
@@ -553,9 +527,8 @@
 	/**
 	 * Set Newline Character
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_newline($newline = "\n")
 	{
@@ -568,13 +541,12 @@
 	/**
 	 * Set CRLF
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_crlf($crlf = "\n")
 	{
-		$this->crlf = ($crlf !== "\n" AND $crlf !== "\r\n" AND $crlf !== "\r") ? "\n" : $crlf;
+		$this->crlf = ($crlf !== "\n" && $crlf !== "\r\n" && $crlf !== "\r") ? "\n" : $crlf;
 		return $this;
 	}
 
@@ -583,13 +555,12 @@
 	/**
 	 * Set Message Boundary
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _set_boundaries()
 	{
-		$this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative
-		$this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
+		$this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative
+		$this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary
 	}
 
 	// --------------------------------------------------------------------
@@ -597,14 +568,12 @@
 	/**
 	 * Get the Message ID
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_message_id()
 	{
 		$from = str_replace(array('>', '<'), '', $this->_headers['Return-Path']);
-
-		return  "<".uniqid('').strstr($from, '@').">";
+		return  '<'.uniqid('').strstr($from, '@').'>';
 	}
 
 	// --------------------------------------------------------------------
@@ -612,14 +581,13 @@
 	/**
 	 * Get Mail Protocol
 	 *
-	 * @access	protected
 	 * @param	bool
-	 * @return	string
+	 * @return	mixed
 	 */
 	protected function _get_protocol($return = TRUE)
 	{
 		$this->protocol = strtolower($this->protocol);
-		$this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol;
+		in_array($this->protocol, $this->_protocols, TRUE) OR $this->protocol = 'mail';
 
 		if ($return == TRUE)
 		{
@@ -632,13 +600,12 @@
 	/**
 	 * Get Mail Encoding
 	 *
-	 * @access	protected
 	 * @param	bool
 	 * @return	string
 	 */
 	protected function _get_encoding($return = TRUE)
 	{
-		$this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding;
+		in_array($this->_encoding, $this->_bit_depths) OR $this->_encoding = '8bit';
 
 		foreach ($this->_base_charsets as $charset)
 		{
@@ -659,7 +626,6 @@
 	/**
 	 * Get content type (text/html/attachment)
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_content_type()
@@ -687,17 +653,16 @@
 	/**
 	 * Set RFC 822 Date
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _set_date()
 	{
-		$timezone = date("Z");
+		$timezone = date('Z');
 		$operator = (strncmp($timezone, '-', 1) === 0) ? '-' : '+';
 		$timezone = abs($timezone);
 		$timezone = floor($timezone/3600) * 100 + ($timezone % 3600) / 60;
 
-		return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
+		return sprintf('%s %s%04d', date('D, j M Y H:i:s'), $operator, $timezone);
 	}
 
 	// --------------------------------------------------------------------
@@ -705,12 +670,11 @@
 	/**
 	 * Mime message
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_mime_message()
 	{
-		return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
+		return 'This is a multi-part message in MIME format.'.$this->newline.'Your email application may not support this format.';
 	}
 
 	// --------------------------------------------------------------------
@@ -718,7 +682,6 @@
 	/**
 	 * Validate Email Address
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
@@ -747,13 +710,12 @@
 	/**
 	 * Email Validation
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
 	public function valid_email($address)
 	{
-		return (bool) preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address);
+		return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $address);
 	}
 
 	// --------------------------------------------------------------------
@@ -761,7 +723,6 @@
 	/**
 	 * Clean Extended Email Address: Joe Smith <joe@smith.com>
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	string
 	 */
@@ -776,7 +737,7 @@
 
 		foreach ($email as $addy)
 		{
-			$clean_email[] = (preg_match( '/\<(.*)\>/', $addy, $match)) ? $match[1] : $addy;
+			$clean_email[] = preg_match('/\<(.*)\>/', $addy, $match) ? $match[1] : $addy;
 		}
 
 		return $clean_email;
@@ -792,12 +753,11 @@
 	 * If the user hasn't specified his own alternative message
 	 * it creates one by stripping the HTML
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_alt_message()
 	{
-		if ($this->alt_message != "")
+		if ($this->alt_message != '')
 		{
 			return $this->word_wrap($this->alt_message, '76');
 		}
@@ -818,9 +778,8 @@
 	/**
 	 * Word Wrap
 	 *
-	 * @access	public
 	 * @param	string
-	 * @param	integer
+	 * @param	int
 	 * @return	string
 	 */
 	public function word_wrap($str, $charlim = '')
@@ -911,8 +870,6 @@
 	/**
 	 * Build final headers
 	 *
-	 * @access	protected
-	 * @param	string
 	 * @return	string
 	 */
 	protected function _build_headers()
@@ -929,7 +886,6 @@
 	/**
 	 * Write Headers as a string
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _write_headers()
@@ -964,12 +920,11 @@
 	/**
 	 * Build Final Body and attachments
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _build_message()
 	{
-		if ($this->wordwrap === TRUE AND $this->mailtype !== 'html')
+		if ($this->wordwrap === TRUE && $this->mailtype !== 'html')
 		{
 			$this->_body = $this->word_wrap($this->_body);
 		}
@@ -1131,9 +1086,8 @@
 	 * Prepares string for Quoted-Printable Content-Transfer-Encoding
 	 * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
 	 *
-	 * @access	protected
 	 * @param	string
-	 * @param	integer
+	 * @param	int
 	 * @return	string
 	 */
 	protected function _prep_quoted_printable($str, $charlim = '')
@@ -1203,9 +1157,7 @@
 		}
 
 		// get rid of extra CRLF tacked onto the end
-		$output = substr($output, 0, strlen($this->crlf) * -1);
-
-		return $output;
+		return substr($output, 0, strlen($this->crlf) * -1);
 	}
 
 	// --------------------------------------------------------------------
@@ -1216,10 +1168,9 @@
 	 * Performs "Q Encoding" on a string for use in email headers.  It's related
 	 * but not identical to quoted-printable, so it has its own method
 	 *
-	 * @access	public
-	 * @param	str
-	 * @param	bool	// set to TRUE for processing From: headers
-	 * @return	str
+	 * @param	string
+	 * @param	bool	set to TRUE for processing From: headers
+	 * @return	string
 	 */
 	protected function _prep_q_encoding($str, $from = FALSE)
 	{
@@ -1275,9 +1226,7 @@
 
 		// wrap each line with the shebang, charset, and transfer encoding
 		// the preceding space on successive lines is required for header "folding"
-		$str = trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str));
-
-		return $str;
+		return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1285,7 +1234,6 @@
 	/**
 	 * Send Email
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function send()
@@ -1295,9 +1243,9 @@
 			$this->reply_to($this->_headers['From']);
 		}
 
-		if (( ! isset($this->_recipients) AND ! isset($this->_headers['To']))  AND
-			( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND
-			( ! isset($this->_headers['Cc'])))
+		if ( ! isset($this->_recipients) && ! isset($this->_headers['To'])
+			&& ! isset($this->_bcc_array) && ! isset($this->_headers['Bcc'])
+			&& ! isset($this->_headers['Cc']))
 		{
 			$this->_set_error_message('lang:email_no_recipients');
 			return FALSE;
@@ -1305,44 +1253,40 @@
 
 		$this->_build_headers();
 
-		if ($this->bcc_batch_mode AND count($this->_bcc_array) > $this->bcc_batch_size)
+		if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size)
 		{
 			return $this->batch_bcc_send();
 		}
 
 		$this->_build_message();
-
 		return $this->_spool_email();
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Batch Bcc Send.  Sends groups of BCCs in batches
+	 * Batch Bcc Send. Sends groups of BCCs in batches
 	 *
-	 * @access	public
-	 * @return	bool
+	 * @return	void
 	 */
 	public function batch_bcc_send()
 	{
-		$float = $this->bcc_batch_size -1;
-
-		$set = "";
-
+		$float = $this->bcc_batch_size - 1;
+		$set = '';
 		$chunk = array();
 
 		for ($i = 0, $c = count($this->_bcc_array); $i < $c; $i++)
 		{
 			if (isset($this->_bcc_array[$i]))
 			{
-				$set .= ", ".$this->_bcc_array[$i];
+				$set .= ', '.$this->_bcc_array[$i];
 			}
 
 			if ($i == $float)
 			{
 				$chunk[] = substr($set, 1);
 				$float += $this->bcc_batch_size;
-				$set = "";
+				$set = '';
 			}
 
 			if ($i === $c-1)
@@ -1359,7 +1303,7 @@
 
 			if ($this->protocol !== 'smtp')
 			{
-				$this->_set_header('Bcc', implode(", ", $bcc));
+				$this->_set_header('Bcc', implode(', ', $bcc));
 			}
 			else
 			{
@@ -1376,7 +1320,6 @@
 	/**
 	 * Unwrap special elements
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _unwrap_specials()
@@ -1389,7 +1332,6 @@
 	/**
 	 * Strip line-breaks via callback
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _remove_nl_callback($matches)
@@ -1407,7 +1349,6 @@
 	/**
 	 * Spool mail to the mail server
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _spool_email()
@@ -1418,6 +1359,7 @@
 		if ( ! $this->$method())
 		{
 			$this->_set_error_message('lang:email_send_failure_' . ($this->_get_protocol() === 'mail' ? 'phpmail' : $this->_get_protocol()));
+			return FALSE;
 		}
 
 		$this->_set_error_message('lang:email_sent', $this->_get_protocol());
@@ -1429,7 +1371,6 @@
 	/**
 	 * Send using mail()
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_mail()
@@ -1451,7 +1392,6 @@
 	/**
 	 * Send using Sendmail
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_sendmail()
@@ -1484,7 +1424,6 @@
 	/**
 	 * Send using SMTP
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_smtp()
@@ -1495,8 +1434,10 @@
 			return FALSE;
 		}
 
-		$this->_smtp_connect();
-		$this->_smtp_authenticate();
+		if ( ! $this->_smtp_connect() OR ! $this->_smtp_authenticate())
+		{
+			return FALSE;
+		}
 
 		$this->_send_command('from', $this->clean_email($this->_headers['From']));
 
@@ -1553,7 +1494,6 @@
 	/**
 	 * SMTP Connect
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	string
 	 */
@@ -1597,7 +1537,6 @@
 	/**
 	 * Send SMTP command
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @param	string
 	 * @return	string
@@ -1670,7 +1609,6 @@
 	/**
 	 *  SMTP Authenticate
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _smtp_authenticate()
@@ -1680,7 +1618,7 @@
 			return TRUE;
 		}
 
-		if ($this->smtp_user == ""  AND  $this->smtp_pass == "")
+		if ($this->smtp_user == '' && $this->smtp_pass == '')
 		{
 			$this->_set_error_message('lang:email_no_smtp_unpw');
 			return FALSE;
@@ -1724,7 +1662,6 @@
 	/**
 	 * Send SMTP data
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_data($data)
@@ -1743,7 +1680,6 @@
 	/**
 	 * Get SMTP data
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_smtp_data()
@@ -1768,12 +1704,11 @@
 	/**
 	 * Get Hostname
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_hostname()
 	{
-		return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
+		return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
 	}
 
 	// --------------------------------------------------------------------
@@ -1781,7 +1716,6 @@
 	/**
 	 * Get IP
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_ip()
@@ -1791,13 +1725,13 @@
 			return $this->_IP;
 		}
 
-		$cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
-		$rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;
+		$cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
+		$rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE;
 		if ($cip) $this->_IP = $cip;
 		elseif ($rip) $this->_IP = $rip;
 		else
 		{
-			$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
+			$fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
 			if ($fip)
 			{
 				$this->_IP = $fip;
@@ -1810,7 +1744,7 @@
 			$this->_IP = end($x);
 		}
 
-		if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))
+		if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP))
 		{
 			$this->_IP = '0.0.0.0';
 		}
@@ -1823,7 +1757,6 @@
 	/**
 	 * Get Debug Message
 	 *
-	 * @access	public
 	 * @return	string
 	 */
 	public function print_debugger()
@@ -1838,8 +1771,7 @@
 			}
 		}
 
-		$msg .= "<pre>".$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
-		return $msg;
+		return $msg.'<pre>'.$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
 	}
 
 	// --------------------------------------------------------------------
@@ -1847,16 +1779,15 @@
 	/**
 	 * Set Message
 	 *
-	 * @access	protected
 	 * @param	string
-	 * @return	string
+	 * @return	void
 	 */
 	protected function _set_error_message($msg, $val = '')
 	{
 		$CI =& get_instance();
 		$CI->lang->load('email');
 
-		if (substr($msg, 0, 5) !== 'lang:' || FALSE === ($line = $CI->lang->line(substr($msg, 5))))
+		if (substr($msg, 0, 5) !== 'lang:' OR FALSE === ($line = $CI->lang->line(substr($msg, 5))))
 		{
 			$this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
 		}
@@ -1871,13 +1802,13 @@
 	/**
 	 * Mime Types
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	string
 	 */
-	protected function _mime_types($ext = "")
+	protected function _mime_types($ext = '')
 	{
-		$mimes = array(	'hqx'	=>	'application/mac-binhex40',
+		$mimes = array(
+						'hqx'	=>	'application/mac-binhex40',
 						'cpt'	=>	'application/mac-compactpro',
 						'doc'	=>	'application/msword',
 						'bin'	=>	'application/macbinary',
@@ -1966,11 +1897,10 @@
 						'eml'	=>	'message/rfc822'
 					);
 
-		return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
+		return isset($mimes[strtolower($ext)]) ? $mimes[strtolower($ext)] : 'application/x-unknown-content-type';
 	}
 
 }
-// END CI_Email class
 
 /* End of file Email.php */
 /* Location: ./system/libraries/Email.php */
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 0b06189..b29eb47 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 0a6a2af..826d94f 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -47,14 +47,24 @@
 	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();
 
+		// applies delimiters set in config file.
+		if (isset($rules['error_prefix']))
+		{
+			$this->_error_prefix = $rules['error_prefix'];
+			unset($rules['error_prefix']);
+		}
+		if (isset($rules['error_suffix']))
+		{
+			$this->_error_suffix = $rules['error_suffix'];
+			unset($rules['error_suffix']);
+		}
+		
 		// Validation rules can be stored in a config file.
 		$this->_config_rules = $rules;
 
@@ -67,7 +77,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 +95,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 +173,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
@@ -235,6 +269,20 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Get Array of Error Messages
+	 *
+	 * Returns the error messages as an array
+	 *
+	 * @return	array
+	 */
+	public function error_array()
+	{
+		return $this->_error_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Error String
 	 *
 	 * Returns the error messages as a string, wrapped in the error delimiters
@@ -286,7 +334,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;
 		}
@@ -328,18 +377,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];
 				}
 			}
 
@@ -703,11 +752,11 @@
 	 *
 	 * @param	string	the field name
 	 * @param	string
-	 * @return	void
+	 * @return	string
 	 */
 	public function set_value($field = '', $default = '')
 	{
-		if ( ! isset($this->_field_data[$field]))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
 			return $default;
 		}
@@ -736,13 +785,9 @@
 	 */
 	public function set_select($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' selected="selected"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' selected="selected"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
@@ -754,12 +799,9 @@
 				return '';
 			}
 		}
-		else
+		elseif (($field == '' OR $value == '') OR ($field != $value))
 		{
-			if (($field == '' OR $value == '') OR ($field != $value))
-			{
-				return '';
-			}
+			return '';
 		}
 
 		return ' selected="selected"';
@@ -779,13 +821,9 @@
 	 */
 	public function set_radio($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' checked="checked"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' checked="checked"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
@@ -864,14 +902,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;
 		}
 
-		$field = $_POST[$field];
-
-		return ($str === $field);
+		return ($str === $validation_array[$field]);
 	}
 
 	// --------------------------------------------------------------------
@@ -908,7 +945,7 @@
 	 */
 	public function min_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -932,7 +969,7 @@
 	 */
 	public function max_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -956,7 +993,7 @@
 	 */
 	public function exact_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -1116,7 +1153,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Greather than
+	 * Greater than
 	 *
 	 * @param	string
 	 * @return	bool
@@ -1133,6 +1170,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
@@ -1150,6 +1204,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
@@ -1170,7 +1241,7 @@
 	 */
 	public function is_natural_no_zero($str)
 	{
-		return ($str != 0 AND preg_match('/^[0-9]+$/', $str));
+		return ($str != 0 && preg_match('/^[0-9]+$/', $str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1217,7 +1288,7 @@
 			return $data;
 		}
 
-		return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '&lt;', '&gt;'), stripslashes($data));
+		return str_replace(array("'", '"', '<', '>'), array('&#39;', '&quot;', '&lt;', '&gt;'), stripslashes($data));
 	}
 
 	// --------------------------------------------------------------------
@@ -1282,8 +1353,26 @@
 		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 Form Validation Class
 
 /* End of file Form_validation.php */
 /* Location: ./system/libraries/Form_validation.php */
diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php
index ab395b0..4d96c00 100644
--- a/system/libraries/Ftp.php
+++ b/system/libraries/Ftp.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 5ea830f..86b77bf 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -251,7 +251,7 @@
 		}
 		else
 		{
-			if (function_exists('realpath') && @realpath($this->new_image) !== FALSE)
+			if (strpos($this->new_image, '/') === FALSE AND strpos($this->new_image, '\\') === FALSE)
 			{
 				$full_dest_path = str_replace('\\', '/', realpath($this->new_image));
 			}
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 33df600..9ba9300 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Log.php b/system/libraries/Log.php
index 944173f..955277a 100644
--- a/system/libraries/Log.php
+++ b/system/libraries/Log.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php
index d070972..c045ac0 100644
--- a/system/libraries/Migration.php
+++ b/system/libraries/Migration.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 35ac541..86b8d79 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php
index 3212482..290e17f 100644
--- a/system/libraries/Parser.php
+++ b/system/libraries/Parser.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index 89c6165..d84e5d3 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -270,7 +270,7 @@
 				}
 
 				$output .= "<tr><td style='width:50%;color:#000;background-color:#ddd;padding:5px'>&#36;_GET[".$key."]&nbsp;&nbsp; </td><td style='width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;'>"
-					. (is_array($val) ? "<pre>" . htmlspecialchars(stripslashes(print_r($val, true))) . "</pre>" : htmlspecialchars(stripslashes($val)))
+					. ((is_array($val) OR is_object($val)) ? "<pre>" . htmlspecialchars(stripslashes(print_r($val, true))) . "</pre>" : htmlspecialchars(stripslashes($val)))
 					. "</td></tr>\n";
 			}
 
@@ -311,7 +311,7 @@
 				}
 
 				$output .= "<tr><td style='width:50%;padding:5px;color:#000;background-color:#ddd;'>&#36;_POST[".$key."]&nbsp;&nbsp; </td><td style='width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;'>";
-				if (is_array($val))
+				if (is_array($val) OR is_object($val))
 				{
 					$output .= "<pre>" . htmlspecialchars(stripslashes(print_r($val, TRUE))) . "</pre>";
 				}
@@ -426,9 +426,9 @@
 			. '<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_config').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_config_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
 			. "\n\n\n<table style='width:100%; display:none' id='ci_profiler_config_table'>\n";
 
-		foreach ($this->CI->config->config as $config=>$val)
+		foreach ($this->CI->config->config as $config => $val)
 		{
-			if (is_array($val))
+			if (is_array($val) OR is_object($val))
 			{
 				$val = print_r($val, TRUE);
 			}
@@ -459,7 +459,7 @@
 
 		foreach ($this->CI->session->all_userdata() as $key => $val)
 		{
-			if (is_array($val) || is_object($val))
+			if (is_array($val) OR is_object($val))
 			{
 				$val = print_r($val, TRUE);
 			}
@@ -501,7 +501,5 @@
 	}
 }
 
-// END CI_Profiler class
-
 /* End of file Profiler.php */
 /* Location: ./system/libraries/Profiler.php */
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index 66b39a6..0b9d45b 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -219,7 +219,7 @@
 				$this->CI->db->where('user_agent', $session['user_agent']);
 			}
 
-			$query = $this->CI->db->get($this->sess_table_name);
+			$query = $this->CI->db->limit(1)->get($this->sess_table_name);
 
 			// No result? Kill it!
 			if ($query->num_rows() === 0)
@@ -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/Table.php b/system/libraries/Table.php
index fb154e5..99d001c 100644
--- a/system/libraries/Table.php
+++ b/system/libraries/Table.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * HTML Table Generating Class
  *
@@ -49,9 +47,21 @@
 	public $empty_cells		= '';
 	public $function		= FALSE;
 
-	public function __construct()
+	/**
+	 * Set the template from the table config file if it exists
+	 *
+	 * @param	array	$config	(default: array())
+	 * @return	void
+	 */
+	public function __construct($config = array())
 	{
-		log_message('debug', "Table Class Initialized");
+		log_message('debug', 'Table Class Initialized');
+
+		// initialize config
+		foreach ($config as $key => $val)
+		{
+			$this->template[$key] = $val;
+		}
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php
index 79a0091..3bea5f9 100644
--- a/system/libraries/Trackback.php
+++ b/system/libraries/Trackback.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php
index 46c73ef..65e30b0 100644
--- a/system/libraries/Typography.php
+++ b/system/libraries/Typography.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index 38d767c..2eb8df3 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 0c63886..42664a5 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -1,8 +1,8 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -593,16 +593,17 @@
 	/**
 	 * Verify that the filetype is allowed
 	 *
+	 * @param	bool
 	 * @return	bool
 	 */
 	public function is_allowed_filetype($ignore_mime = FALSE)
 	{
-		if ($this->allowed_types == '*')
+		if ($this->allowed_types === '*')
 		{
 			return TRUE;
 		}
 
-		if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
+		if ( ! is_array($this->allowed_types) OR count($this->allowed_types) === 0)
 		{
 			$this->set_error('upload_no_file_types');
 			return FALSE;
@@ -618,12 +619,9 @@
 		// Images get some additional checks
 		$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
 
-		if (in_array($ext, $image_types))
+		if (in_array($ext, $image_types) && @getimagesize($this->file_temp) === FALSE)
 		{
-			if (getimagesize($this->file_temp) === FALSE)
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 
 		if ($ignore_mime === TRUE)
@@ -640,7 +638,7 @@
 				return TRUE;
 			}
 		}
-		elseif ($mime == $this->file_type)
+		elseif ($mime === $this->file_type)
 		{
 				return TRUE;
 		}
@@ -960,7 +958,7 @@
 			}
 			elseif (is_file(APPPATH.'config/mimes.php'))
 			{
-				include(APPPATH.'config//mimes.php');
+				include(APPPATH.'config/mimes.php');
 			}
 			else
 			{
@@ -1026,47 +1024,104 @@
 	 */
 	protected function _file_mime_type($file)
 	{
-		// Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
-		if ( (float) substr(phpversion(), 0, 3) >= 5.3 && function_exists('finfo_file'))
+		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
+		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
+
+		/* Fileinfo extension - most reliable method
+		 *
+		 * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
+		 * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
+		 */
+		if (function_exists('finfo_file'))
 		{
-			$finfo = new finfo(FILEINFO_MIME_TYPE);
-			if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
+			$finfo = finfo_open(FILEINFO_MIME);
+			if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
 			{
-				$file_type = $finfo->file($file['tmp_name']);
+				$mime = @finfo_file($finfo, $file['tmp_name']);
+				finfo_close($finfo);
 
 				/* According to the comments section of the PHP manual page,
 				 * it is possible that this function returns an empty string
 				 * for some files (e.g. if they don't exist in the magic MIME database)
 				 */
-				if (strlen($file_type) > 1)
+				if (is_string($mime) && preg_match($regexp, $mime, $matches))
 				{
-					$this->file_type = $file_type;
+					$this->file_type = $matches[1];
 					return;
 				}
 			}
 		}
 
-		// Fall back to the deprecated mime_content_type(), if available
+		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
+		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
+		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
+		 * than mime_content_type() as well, hence the attempts to try calling the command line with
+		 * three different functions.
+		 *
+		 * Notes:
+		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
+		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
+		 *	  due to security concerns, hence the function_exists() checks
+		 */
+		if (DIRECTORY_SEPARATOR !== '\\')
+		{
+			$cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1';
+
+			if (function_exists('exec'))
+			{
+				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
+				 * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
+				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
+				 * value, which is only put to allow us to get the return status code.
+				 */
+				$mime = @exec($cmd, $mime, $return_status);
+				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
+				{
+					$this->file_type = $matches[1];
+					return;
+				}
+			}
+
+			if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec'))
+			{
+				$mime = @shell_exec($cmd);
+				if (strlen($mime) > 0)
+				{
+					$mime = explode("\n", trim($mime));
+					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+					{
+						$this->file_type = $matches[1];
+						return;
+					}
+				}
+			}
+
+			if (function_exists('popen'))
+			{
+				$proc = @popen($cmd, 'r');
+				if (is_resource($proc))
+				{
+					$mime = @fread($proc, 512);
+					@pclose($proc);
+					if ($mime !== FALSE)
+					{
+						$mime = explode("\n", trim($mime));
+						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+						{
+							$this->file_type = $matches[1];
+							return;
+						}
+					}
+				}
+			}
+		}
+
+		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
 		if (function_exists('mime_content_type'))
 		{
 			$this->file_type = @mime_content_type($file['tmp_name']);
-			return;
-		}
-
-		/* This is an ugly hack, but UNIX-type systems provide a native way to detect the file type,
-		 * which is still more secure than depending on the value of $_FILES[$field]['type'].
-		 *
-		 * Notes:
-		 *	- a 'W' in the substr() expression bellow, would mean that we're using Windows
-		 *	- many system admins would disable the exec() function due to security concerns, hence the function_exists() check
-		 */
-		if (DIRECTORY_SEPARATOR !== '\\' && function_exists('exec'))
-		{
-			$output = array();
-			@exec('file --brief --mime-type ' . escapeshellarg($file['tmp_path']), $output, $return_code);
-			if ($return_code === 0 && strlen($output[0]) > 0) // A return status code != 0 would mean failed execution
+			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
 			{
-				$this->file_type = rtrim($output[0]);
 				return;
 			}
 		}
diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php
index cd644c0..9109edd 100644
--- a/system/libraries/User_agent.php
+++ b/system/libraries/User_agent.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index 730a0fc..32e2e52 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index 355d43f..fc41444 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index 50e8492..e33eb4e 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  * 
diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php
index 03574c6..f30d7c6 100644
--- a/system/libraries/javascript/Jquery.php
+++ b/system/libraries/javascript/Jquery.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/user_guide_src/cilexer/cilexer/cilexer.py b/user_guide_src/cilexer/cilexer/cilexer.py
index 713268e..1c41f2a 100644
--- a/user_guide_src/cilexer/cilexer/cilexer.py
+++ b/user_guide_src/cilexer/cilexer/cilexer.py
@@ -1,7 +1,7 @@
 # CodeIgniter
 # http://codeigniter.com
 # 
-# An open source application development framework for PHP 5.1.6 or newer
+# An open source application development framework for PHP 5.2.4 or newer
 # 
 # NOTICE OF LICENSE
 # 
diff --git a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
index b9e28ae..66768ba 100644
--- a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
+++ b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
@@ -2,7 +2,7 @@
 CodeIgniter
 http://codeigniter.com
 
-An open source application development framework for PHP 5.1.6 or newer
+An open source application development framework for PHP 5.2.4 or newer
 
 NOTICE OF LICENSE
 
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index e879568..0b462b3 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -19,6 +19,7 @@
 
 -  General Changes
 
+   -  PHP 5.1.6 is no longer supported. CodeIgniter now requires PHP 5.2.4.
    -  Added an optional backtrace to php-error template.
    -  Added Android to the list of user agents.
    -  Added Windows 7 to the list of user platforms.
@@ -28,6 +29,7 @@
    -  Added support for 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php.
    -  Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php.
    -  Added support for kmz and kml (Google Earth) files to mimes.php.
+   -  Updated support for doc files in mimes.php.
    -  Added application/xml for xml and application/xml, text/xsl for xsl in mimes.php.
    -  Added support for Wincache PHP extension
    -  Changed logger to only chmod when file is first created.
@@ -40,6 +42,10 @@
    -  url_title() will now trim extra dashes from beginning and end.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
    -  Changed humanize to include a second param for the separator.
+   -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
+   -  Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default).
+   -  Added a work-around in force_download() for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
+   -  form_dropdown() will now also take an array for unity with other form helpers.
 
 -  Database
 
@@ -52,13 +58,24 @@
    -  MySQLi driver now supports persistent connections when running on PHP >= 5.3.
    -  Added dsn if the group connections in the config use PDO or any driver which need DSN.
    -  Improved PDO database support.
-   -  An optional database name parameter was added db_select().
+   -  Added Interbase/Firebird database support via the "interbase" driver
+   -  Added an optional database name parameter to db_select().
+   -  Replaced the _error_message() and _error_number() methods with error(), that returns an array containing the last database error code and message.
+   -  Improved version() implementation so that drivers that have a native function to get the version number don't have to be defined in the core DB_driver class.
+   -  Improved support of the PostgreSQL driver, including:
+	 -  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.
+   -  MySQL and MySQLi drivers now require at least MySQL version 5.1.
+   -  db_set_charset() now only requires one parameter (collation was only needed due to legacy support for MySQL versions prior to 5.1).
 
 -  Libraries
 
    -  Added max_filename_increment config setting for Upload library.
    -  CI_Loader::_ci_autoloader() is now a protected method.
-   -  Modified valid_ip() to use PHP's filter_var() when possible (>= PHP 5.2) in the :doc:`Form Validation library <libraries/form_validation>`.
    -  Added custom filename to Email::attach() as $this->email->attach($filename, $disposition, $newname)
    -  Cart library changes include:
 	 -  It now auto-increments quantity's instead of just resetting it, this is the default behaviour of large e-commerce sites.
@@ -73,6 +90,12 @@
    -  Minor speed optimizations and method & property visibility declarations in the Calendar Library.
    -  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.
+   -  Allowed for setting table class defaults in a config file.
+   -  Form Validation library now allows setting of error delimiters in the config file via $config['error_prefix'] and $config['error_suffix'].
+   -  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
 
@@ -80,13 +103,15 @@
    -  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'].
+   -  Modified valid_ip() to use PHP's filter_var() in the :doc:`Input Library <libraries/input>`.
 
 Bug fixes for 3.0
 ------------------
 
 -  Unlink raised an error if cache file did not exist when you try to delete it.
--  Fixed a bug (#181) where a mis-spelling was in the form validation
-   language file.
+-  Fixed a bug (#181) where a mis-spelling was in the form validation language file.
 -  Fixed a bug (#159, #163) that mishandled Active Record nested transactions because _trans_depth was not getting incremented.
 -  Fixed a bug (#737, #75) where pagination anchor class was not set properly when using initialize method.
 -  Fixed a bug (#419) - auto_link() now recognizes URLs that come after a word boundary.
@@ -109,11 +134,57 @@
 -  Fixed a possible bug in ``CI_Input::is_ajax_request()`` where some clients might not send the X-Requested-With HTTP header value exactly as 'XmlHttpRequest'.
 -  Fixed a bug (#1039) - MySQL's _backup() method failed due to a table name not being escaped.
 -  Fixed a bug (#1070) - CI_DB_driver::initialize() didn't set a character set if a database is not selected.
+-  Fixed a bug (#177) - CI_Form_validation::set_value() didn't set the default value if POST data is NULL.
+-  Fixed a bug (#68, #414) - Oracle's escape_str() didn't properly escape LIKE wild characters.
+-  Fixed a bug (#81) - ODBC's list_fields() and field_data() methods skipped the first column due to odbc_field_*() functions' index starting at 1 instead of 0.
+-  Fixed a bug (#129) - ODBC's num_rows() returned -1 in some cases, due to not all subdrivers supporting the odbc_num_rows() function.
+-  Fixed a bug (#153) - E_NOTICE being generated by getimagesize() in the :doc:`File Uploading Library <libraries/file_uploading>`.
+-  Fixed a bug (#611) - SQLSRV's error handling methods used to issue warnings when there's no actual error.
+-  Fixed a bug (#1036) - is_write_type() method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME and OPTIMIZE queries.
+-  Fixed a bug in PDO's _version() method where it used to return the client version as opposed to the server one.
+-  Fixed a bug in PDO's insert_id() method where it could've failed if it's used with Postgre versions prior to 8.1.
+-  Fixed a bug in CUBRID's affected_rows() method where a connection resource was passed to cubrid_affected_rows() instead of a result.
+-  Fixed a bug (#638) - db_set_charset() ignored its arguments and always used the configured charset instead.
+-  Fixed a bug (#413) - Oracle's error handling methods used to only return connection-related errors.
+-  Fixed a bug (#804) - Profiler library was trying to handle objects as strings in some cases, resulting in warnings being issued by htmlspecialchars().
+-  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
+=============
+
+Release Date: Not Released
+
+-  General Changes
+   -  Fixed support for docx, xlsx files in mimes.php.
+
+-  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
+-------------------
+
+-  Fixed a bug (#697) - A wrong array key was used in the Upload library to check for mime-types.
+-  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
 =============
 
-Release Date: Not Released
+Release Date: November 14, 2011
 
 -  General Changes
 
diff --git a/user_guide_src/source/database/helpers.rst b/user_guide_src/source/database/helpers.rst
index 7ea19e9..e8a5ac8 100644
--- a/user_guide_src/source/database/helpers.rst
+++ b/user_guide_src/source/database/helpers.rst
@@ -7,9 +7,9 @@
 
 The insert ID number when performing database inserts.
 
-.. note:: If using the PDO driver with PostgreSQL, this function requires
-	a $name parameter, which specifies the appropriate sequence to check
-	for the insert id.
+.. note:: If using the PDO driver with PostgreSQL, or using the Interbase
+	driver, this function requires a $name parameter, which specifies the 
+	appropriate sequence to check for the insert id.
 
 $this->db->affected_rows()
 ===========================
diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst
index 971d5d6..15a7361 100644
--- a/user_guide_src/source/database/queries.rst
+++ b/user_guide_src/source/database/queries.rst
@@ -112,3 +112,20 @@
 automatically escaped, producing safer queries. You don't have to
 remember to manually escape data; the engine does it automatically for
 you.
+
+***************
+Handling Errors
+***************
+
+$this->db->error();
+===================
+
+If you need to get the last error that has occured, the error() method
+will return an array containing its code and message. Here's a quick
+example::
+
+	if ( ! $this->db->simple_query('SELECT `example_field` FROM `example_table`'))
+	{
+		$error = $this->db->error(); // Has keys 'code' and 'message'
+	}
+
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/database/utilities.rst b/user_guide_src/source/database/utilities.rst
index b092010..3805ffb 100644
--- a/user_guide_src/source/database/utilities.rst
+++ b/user_guide_src/source/database/utilities.rst
@@ -161,7 +161,11 @@
 Permits you to backup your full database or individual tables. The
 backup data can be compressed in either Zip or Gzip format.
 
-.. note:: This features is only available for MySQL databases.
+.. note:: This features is only available for MySQL and Interbase/Firebird databases.
+
+.. note:: For Interbase/Firebird databases, the backup file name is the only parameter.
+	
+		Eg. $this->dbutil->backup('db_backup_filename');
 
 .. note:: Due to the limited execution time and memory available to PHP,
 	backing up very large databases may not be possible. If your database is
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/general/requirements.rst b/user_guide_src/source/general/requirements.rst
index 3862355..05e8796 100644
--- a/user_guide_src/source/general/requirements.rst
+++ b/user_guide_src/source/general/requirements.rst
@@ -2,7 +2,7 @@
 Server Requirements
 ###################
 
--  `PHP <http://www.php.net/>`_ version 5.1.6 or newer.
+-  `PHP <http://www.php.net/>`_ version 5.2.4 or newer.
 -  A Database is required for most web application programming. Current
-   supported databases are MySQL (4.1+), MySQLi, MS SQL, Postgres, Oracle,
-   SQLite, ODBC and CUBRID.
\ No newline at end of file
+   supported databases are MySQL (5.1+), MySQLi, MS SQL, SQLSRV, Oracle,
+   PostgreSQL, SQLite, CUBRID, Interbase, ODBC and PDO.
diff --git a/user_guide_src/source/installation/upgrade_200.rst b/user_guide_src/source/installation/upgrade_200.rst
index 0bcbd5c..b39f4fd 100644
--- a/user_guide_src/source/installation/upgrade_200.rst
+++ b/user_guide_src/source/installation/upgrade_200.rst
@@ -102,7 +102,7 @@
 details, but here are some of the larger changes that are more likely to
 impact your code:
 
-- CodeIgniter now requires PHP 5.1.6.
+- CodeIgniter now requires PHP 5.2.4.
 - Scaffolding has been removed.
 - The CAPTCHA plugin in now a :doc:`helper </helpers/captcha_helper>`.
 - The JavaScript calendar plugin was removed.
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index e7875bc..5d7368c 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -523,7 +523,7 @@
 
 By default, the Form Validation class adds a paragraph tag (<p>) around
 each error message shown. You can either change these delimiters
-globally or individually.
+globally, individually, or change the defaults in a config file.
 
 #. **Changing delimiters Globally**
    To globally change the error delimiters, in your controller function,
@@ -543,6 +543,12 @@
 
       <?php echo validation_errors('<div class="error">', '</div>'); ?>
 
+#. **Set delimiters in a config file**
+   You can add your error delimiters in application/config/form_validation.php as follows::
+   
+      $config['error_prefix'] = '<div class="error_prefix">';
+      $config['error_suffix'] = '</div>';
+
 
 Showing Errors Individually
 ===========================
@@ -579,7 +585,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 +852,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 +965,33 @@
 
 		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();
+========================================
+	
+	.. php:method:: error_array ()
+
+		:rtype: Array
+
+		Returns the error messages as an array.
+
 .. _helper-functions:
 
 ****************
@@ -1011,4 +1073,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/libraries/table.rst b/user_guide_src/source/libraries/table.rst
index 9bc3f34..6a808ab 100644
--- a/user_guide_src/source/libraries/table.rst
+++ b/user_guide_src/source/libraries/table.rst
@@ -116,6 +116,8 @@
 	$tmpl = array ( 'table_open'  => '<table border="1" cellpadding="2" cellspacing="1" class="mytable">' );
 
 	$this->table->set_template($tmpl);
+	
+You can also set defaults for these in a config file.
 
 ******************
 Function Reference
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