Merge pull request #1433 from jjaffeux/test-encryption-class

Test encryption class
diff --git a/application/config/mimes.php b/application/config/mimes.php
index b9160d9..15493af 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -162,7 +162,8 @@
 	'flac'  =>	'audio/x-flac',
 	'ogg'   =>	'audio/ogg',
 	'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
-	'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml')
+	'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
+	'ics'	=>	'text/calendar'
 );
 
 /* End of file mimes.php */
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 39c19cd..6188c94 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -934,8 +934,8 @@
 	 *
 	 * This function escapes column and table names
 	 *
-	 * @param	string
-	 * @return	string
+	 * @param	mixed
+	 * @return	mixed
 	 */
 	public function escape_identifiers($item)
 	{
@@ -943,25 +943,39 @@
 		{
 			return $item;
 		}
+		elseif (is_array($item))
+		{
+			foreach ($item as $key => $value)
+			{
+				$item[$key] = $this->escape_identifiers($value);
+			}
+
+			return $item;
+		}
+
+		static $preg_ec = array();
+
+		if (empty($preg_ec))
+		{
+			if (is_array($this->_escape_char))
+			{
+				$preg_ec = array(preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]));
+			}
+			else
+			{
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+			}
+		}
 
 		foreach ($this->_reserved_identifiers as $id)
 		{
 			if (strpos($item, '.'.$id) !== FALSE)
 			{
-				$item = str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
+				return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[0].'$1'.$preg_ec[1], $item);
 			}
 		}
 
-		if (strpos($item, '.') !== FALSE)
-		{
-			$item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
+		return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[0].'$1'.$preg_ec[1].'$2', $item);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 7a0ea0c..3ed5562 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -1475,6 +1475,24 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * From Tables
+	 *
+	 * This public function implicitly groups FROM tables so there is no confusion
+	 * about operator precedence in harmony with SQL standards
+	 *
+	 * @param       array
+	 * @return      string
+	 */
+	protected function _from_tables($tables)
+	{
+		is_array($tables) OR $tables = array($tables);
+
+		return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Get UPDATE query string
 	 *
 	 * Compiles an update query and returns the sql
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index 6b9286f..6b67b75 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -396,27 +396,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index fb97162..d328aa2 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -60,8 +60,10 @@
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '');
+
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
@@ -69,7 +71,7 @@
 
 					if ( ! empty($attributes['CONSTRAINT']))
 					{
-						switch ($attributes['TYPE'])
+						switch (strtolower($attributes['TYPE']))
 						{
 							case 'decimal':
 							case 'float':
@@ -98,10 +100,23 @@
 				}
 			 */
 
-				$sql .= (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' : '')
-					.(( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) ? ' UNIQUE' : '');
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
+
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+				{
+					$sql .= ' UNIQUE';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -142,8 +157,8 @@
 		// If there is a PK defined
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
-			$sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
+			$sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -152,12 +167,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers('idx_'.$table.implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers('idx_'.$table.$key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.$key);
 					$key = array($key_name);
 				}
 
@@ -184,16 +199,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_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->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/interbase/interbase_driver.php
index 8cbbfa1..5a03607 100644
--- a/system/database/drivers/interbase/interbase_driver.php
+++ b/system/database/drivers/interbase/interbase_driver.php
@@ -324,13 +324,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		//Interbase/Firebird doesn't like grouped tables
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/interbase/interbase_forge.php b/system/database/drivers/interbase/interbase_forge.php
index 5470179..3f9967f 100644
--- a/system/database/drivers/interbase/interbase_forge.php
+++ b/system/database/drivers/interbase/interbase_forge.php
@@ -87,7 +87,7 @@
 	{
 		$sql = 'CREATE TABLE ';
 
-		$sql .= $this->db->protect_identifiers($table)."(";
+		$sql .= $this->db->escape_identifiers($table).'(';
 		$current_field_count = 0;
 
 		foreach ($fields as $field => $attributes)
@@ -97,41 +97,30 @@
 			// 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 .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -146,30 +135,23 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$primary_keys = $this->db->escape_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -191,31 +173,11 @@
 	 */
 	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;
-
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 697b2fd..87094e7 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -43,7 +43,7 @@
 	public $dbdriver = 'mssql';
 
 	// The character used for escaping
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -57,6 +57,29 @@
 	protected $_count_string = 'SELECT COUNT(*) AS ';
 	protected $_random_keyword = ' NEWID()';
 
+	// MSSQL-specific properties
+	protected $_quoted_identifier = TRUE;
+
+	/*
+	 * Constructor
+	 *
+	 * Appends the port number to the hostname, if needed.
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	public function __construct($params)
+	{
+		parent::__construct($params);
+
+		if ( ! empty($this->port))
+		{
+			$this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
 	/**
 	 * Non-persistent database connection
 	 *
@@ -64,12 +87,7 @@
 	 */
 	public function db_connect()
 	{
-		if ( ! empty($this->port))
-		{
-			$this->hostname .= ','.$this->port;
-		}
-
-		return @mssql_connect($this->hostname, $this->username, $this->password);
+		return $this->_mssql_connect();
 	}
 
 	// --------------------------------------------------------------------
@@ -81,12 +99,35 @@
 	 */
 	public function db_pconnect()
 	{
-		if ( ! empty($this->port))
+		return $this->_mssql_connect(TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/*
+	 * MSSQL Connect
+	 *
+	 * @param	bool
+	 * @return	resource
+	 */
+	protected function _mssql_connect($persistent = FALSE)
+	{
+		$conn_id = ($persistent)
+				? @mssql_pconnect($this->hostname, $this->username, $this->password)
+				: @mssql_connect($this->hostname, $this->username, $this->password);
+
+		if ( ! $conn_id)
 		{
-			$this->hostname .= ','.$this->port;
+			return FALSE;
 		}
 
-		return @mssql_pconnect($this->hostname, $this->username, $this->password);
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -106,7 +147,7 @@
 
 		// Note: The brackets are required in the event that the DB name
 		// contains reserved characters
-		if (@mssql_select_db('['.$database.']', $this->conn_id))
+		if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id))
 		{
 			$this->database = $database;
 			return TRUE;
@@ -121,7 +162,7 @@
 	 * Execute the query
 	 *
 	 * @param	string	an SQL query
-	 * @return	resource
+	 * @return	mixed	resource if rows are returned, bool otherwise
 	 */
 	protected function _execute($sql)
 	{
@@ -137,13 +178,8 @@
 	 */
 	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;
 		}
@@ -151,10 +187,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);
 
-		$this->simple_query('BEGIN TRAN');
-		return TRUE;
+		return $this->simple_query('BEGIN TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -166,19 +201,13 @@
 	 */
 	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;
 		}
 
-		$this->simple_query('COMMIT TRAN');
-		return TRUE;
+		return $this->simple_query('COMMIT TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -190,19 +219,13 @@
 	 */
 	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;
 		}
 
-		$this->simple_query('ROLLBACK TRAN');
-		return TRUE;
+		return $this->simple_query('ROLLBACK TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -232,7 +255,7 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(
+			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
@@ -265,11 +288,13 @@
 	 */
 	public function insert_id()
 	{
-		$ver = self::_parse_major_version($this->version());
-		$sql = ($ver >= 8 ? "SELECT SCOPE_IDENTITY() AS last_id" : "SELECT @@IDENTITY AS last_id");
-		$query = $this->query($sql);
-		$row = $query->row();
-		return $row->last_id;
+		$query = (self::_parse_major_version($this->version()) > 7)
+			? 'SELECT SCOPE_IDENTITY() AS last_id'
+			: 'SELECT @@IDENTITY AS last_id';
+
+		$query = $this->query($query);
+		$query = $query->row();
+		return $query->last_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -352,7 +377,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT TOP 1 * FROM ".$table;
+		return 'SELECT TOP 1 * FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -385,12 +410,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -484,9 +504,7 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		$i = $limit + $offset;
-
-		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql);
+		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.($limit + $offset).' ', $sql);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index e6227e1..3a3528f 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -75,26 +75,20 @@
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -109,22 +103,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
@@ -152,7 +140,7 @@
 	 */
 	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 = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -160,21 +148,10 @@
 			return $sql;
 		}
 
-		$sql .= " ".$column_definition;
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT '".$default_value."'";
-		}
-
-		$sql .= ($null === NULL) ? ' NULL' : ' NOT NULL';
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index 4cc87f4..5929306 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -92,12 +92,12 @@
 		$retval = array();
 		while ($field = mssql_fetch_field($this->result_id))
 		{
-			$F				= new stdClass();
-			$F->name		= $field->name;
-			$F->type		= $field->type;
+			$F		= new stdClass();
+			$F->name	= $field->name;
+			$F->type	= $field->type;
 			$F->max_length	= $field->max_length;
 			$F->primary_key = 0;
-			$F->default		= '';
+			$F->default	= '';
 
 			$retval[] = $F;
 		}
diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php
index 6d47618..69fcec5 100644
--- a/system/database/drivers/mssql/mssql_utility.php
+++ b/system/database/drivers/mssql/mssql_utility.php
@@ -41,7 +41,7 @@
 	 * MSSQL Export
 	 *
 	 * @param	array	Preferences
-	 * @return	mixed
+	 * @return	bool
 	 */
 	protected function _backup($params = array())
 	{
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 5937b22..8938d22 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -412,27 +412,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string	table name
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index ffd374f..d22454d 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -60,8 +60,9 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
@@ -86,10 +87,23 @@
 					}
 				}
 
-				$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' : '');
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -123,12 +137,12 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->protect_identifiers($table).' ('.$this->_process_fields($fields);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -137,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers(implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -169,16 +183,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_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->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index 643682f..f0bbc66 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -65,7 +65,7 @@
 			}
 
 			// Get the table schema
-			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->protect_identifiers($this->db->database).'.'.$this->db->protect_identifiers($table));
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table));
 
 			// No result means the table name was invalid
 			if ($query === FALSE)
@@ -120,7 +120,7 @@
 							TRUE);
 
 				// Create a string of field names
-				$field_str .= $this->db->protect_identifiers($field->name).', ';
+				$field_str .= $this->db->escape_identifiers($field->name).', ';
 				$i++;
 			}
 
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index 02f8937..d3fb77a 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -412,27 +412,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index b00bfde..b74c775 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -60,13 +60,13 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '')
-				;
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
-					$sql .=  ' '.$attributes['TYPE'];
+					$sql .= ' '.$attributes['TYPE'];
 
 					if ( ! empty($attributes['CONSTRAINT']))
 					{
@@ -87,10 +87,23 @@
 					}
 				}
 
-				$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' : '');
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -128,8 +141,8 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -138,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers(implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -170,16 +183,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_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->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 837e7ea..92e8c02 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -73,11 +73,22 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$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'] : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				if (isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= (isset($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? '' : ' NOT NULL';
+
+				empty($attributes['CONSTRAINT']) OR ' CONSTRAINT '.$attributes['CONSTRAINT'];
 			}
 
 			// don't add a comma on the end of the last field
@@ -89,22 +100,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $primary_keys).')';
+			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')';
 			}
@@ -132,7 +137,7 @@
 	 */
 	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 = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -143,7 +148,7 @@
 		return $sql.' '.$column_definition
 			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
 			.($null === NULL ? ' NULL' : ' NOT NULL')
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 
 	}
 
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index c3735da..222c311 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -114,13 +114,8 @@
 	 */
 	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;
 		}
@@ -128,7 +123,7 @@
 		// 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 odbc_autocommit($this->conn_id, FALSE);
 	}
@@ -142,13 +137,8 @@
 	 */
 	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;
 		}
@@ -167,13 +157,8 @@
 	 */
 	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;
 		}
@@ -204,7 +189,6 @@
 			return $str;
 		}
 
-		// ODBC doesn't require escaping
 		$str = remove_invisible_characters($str);
 
 		// escape LIKE condition wildcards
@@ -277,7 +261,7 @@
 	 */
 	protected function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$table;
+		return 'SHOW COLUMNS FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -292,7 +276,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT TOP 1 FROM ".$table;
+		return 'SELECT TOP 1 FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -323,12 +307,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -363,8 +342,7 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		// Does ODBC doesn't use the LIMIT clause?
-		return $sql;
+		return $sql.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index ce7a1d2..b074c58 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -66,41 +66,30 @@
 			// 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 .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -115,30 +104,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -160,7 +141,7 @@
 	 */
 	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 = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -168,29 +149,10 @@
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index ecba597..227fe4f 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -59,8 +59,6 @@
 		return $this->num_rows;
 	}
 
-	// --------------------------------------------------------------------
-
 	/**
 	 * Number of fields in the result set
 	 *
@@ -148,14 +146,9 @@
 	 */
 	protected function _fetch_assoc()
 	{
-		if (function_exists('odbc_fetch_array'))
-		{
-			return odbc_fetch_array($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_array($this->result_id);
-		}
+		return function_exists('odbc_fetch_array')
+			? odbc_fetch_array($this->result_id)
+			: $this->_odbc_fetch_array($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -169,14 +162,9 @@
 	 */
 	protected function _fetch_object()
 	{
-		if (function_exists('odbc_fetch_object'))
-		{
-			return odbc_fetch_object($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_object($this->result_id);
-		}
+		return function_exists('odbc_fetch_object')
+			? odbc_fetch_object($this->result_id)
+			: $this->_odbc_fetch_object($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -192,15 +180,18 @@
 	protected function _odbc_fetch_object(& $odbc_result)
 	{
 		$rs = array();
-		$rs_obj = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs))
+		if ( ! odbc_fetch_into($odbc_result, $rs))
 		{
-			foreach ($rs as $k => $v)
-			{
-				$field_name = odbc_field_name($odbc_result, $k+1);
-				$rs_obj->$field_name = $v;
-			}
+			return FALSE;
 		}
+
+		$rs_obj = new stdClass();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_obj->$field_name = $v;
+		}
+
 		return $rs_obj;
 	}
 
@@ -217,16 +208,18 @@
 	protected function _odbc_fetch_array(& $odbc_result)
 	{
 		$rs = array();
-		$rs_assoc = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs))
+		if ( ! odbc_fetch_into($odbc_result, $rs))
 		{
-			$rs_assoc = array();
-			foreach ($rs as $k => $v)
-			{
-				$field_name = odbc_field_name($odbc_result, $k+1);
-				$rs_assoc[$field_name] = $v;
-			}
+			return FALSE;
 		}
+
+		$rs_assoc = array();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_assoc[$field_name] = $v;
+		}
+
 		return $rs_assoc;
 	}
 
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index b4ad52a..e25013a 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -519,27 +519,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index aee8f71..02ceb74 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -66,18 +66,16 @@
 			// 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);
-				$numeric    = array('SERIAL', 'INTEGER');
+				$numeric = array('SERIAL', 'INTEGER');
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if ( ! empty($attributes['CONSTRAINT']))
 				{
 					// Exception for Postgre numeric which not too happy with constraint within those type
 					if ( ! ($this->db->pdodriver === 'pgsql' && in_array($attributes['TYPE'], $numeric)))
@@ -86,26 +84,20 @@
 					}
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -120,30 +112,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -165,7 +149,7 @@
 	 */
 	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 = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -173,29 +157,10 @@
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql .' '.$column_definition
+			.($default_value !== '' ? " DEFAULT '".$default_value."'" : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index e5d861b..7375fbf 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -467,12 +467,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index af1c45f..c434e95 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -58,7 +58,7 @@
 			}
 			else
 			{
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
 
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 				$is_unsigned = ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE);
@@ -107,10 +107,19 @@
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				$sql .= (isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					// Added new attribute to create unqite fields. Also works with MySQL
-					.(( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) ? ' UNIQUE' : '');
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				// Added new attribute to create unique fields. Also works with MySQL
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+				{
+					$sql .= ' UNIQUE';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -139,26 +148,17 @@
 	{
 		$sql = 'CREATE TABLE ';
 
-		if ($if_not_exists === TRUE)
+		// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
+		if ($if_not_exists === TRUE && $this->db->table_exists($table))
 		{
-			// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
-			if ($this->db->table_exists($table))
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
 
 		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields, $primary_keys);
 
 		if (count($primary_keys) > 0)
 		{
-			// 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);
-			}
-
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		$sql .= "\n);";
@@ -167,18 +167,14 @@
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				foreach ($key as $field)
 				{
-					$sql .= 'CREATE INDEX '.$table.'_'.str_replace(array('"', "'"), '', $field).'_index ON '.$table.' ('.$field.'); ';
+					$sql .= "\nCREATE INDEX ".$this->db->escape_identifiers($table.'_'.str_replace(array('"', "'"), '', $field).'_index')
+						.' ON '.$this->db->escape_identifiers($table).' ('.$this->db->escape_identifiers($field).');';
 				}
 			}
 		}
@@ -205,16 +201,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
  	{
- 		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+ 		$sql = 'ALTER TABLE '.$this->db->escape_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->escape_identifiers($fields);
  		}
 
  		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
  	}
 
 }
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index f52b1ba..3305f60 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -43,7 +43,7 @@
 	public $dbdriver = 'sqlite';
 
 	// The character used to escape with - not needed for SQLite
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -127,7 +127,9 @@
 	 */
 	protected function _execute($sql)
 	{
-		return @sqlite_query($this->conn_id, $sql);
+		return $this->is_write_type($sql)
+			? @sqlite_exec($this->conn_id, $sql)
+			: @sqlite_query($this->conn_id, $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -139,13 +141,8 @@
 	 */
 	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;
 		}
@@ -153,7 +150,7 @@
 		// 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);
 
 		$this->simple_query('BEGIN TRANSACTION');
 		return TRUE;
@@ -168,13 +165,8 @@
 	 */
 	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;
 		}
@@ -192,13 +184,8 @@
 	 */
 	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;
 		}
@@ -277,12 +264,13 @@
 	 */
 	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SELECT name from sqlite_master WHERE type='table'";
+		$sql = "SELECT name FROM sqlite_master WHERE type='table'";
 
 		if ($prefix_limit !== FALSE && $this->dbprefix != '')
 		{
-			$sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+			return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 		}
+
 		return $sql;
 	}
 
@@ -314,7 +302,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT * FROM ".$table." LIMIT 1";
+		return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1';
 	}
 
 	// --------------------------------------------------------------------
@@ -337,27 +325,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Replace statement
 	 *
 	 * Generates a platform-specific replace string from the supplied data
@@ -404,16 +371,7 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		if ($offset == 0)
-		{
-			$offset = '';
-		}
-		else
-		{
-			$offset .= ', ';
-		}
-
-		return $sql.'LIMIT '.$offset.$limit;
+		return $sql.'LIMIT '.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index 35be1b7..71eed7d 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -97,41 +97,31 @@
 			// 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 .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$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 .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -146,30 +136,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -191,40 +173,21 @@
 	 */
 	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);
-
-		// DROP has everything it needs now.
-		if ($alter_type === 'DROP')
+		/* SQLite only supports adding new columns and it does
+		 * NOT support the AFTER statement. Each new column will
+		 * be added as the last one in the table.
+		 */
+		if ($alter_type !== 'ADD COLUMN')
 		{
-			// SQLite does not support dropping columns
-			// http://www.sqlite.org/omitted.html
-			// http://www.sqlite.org/faq.html#q11
+			// Not supported
 			return FALSE;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value != '' ? " DEFAULT '".$default_value."'" : '')
+			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
+			.(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
 	}
 
 }
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index 2acefbc..bed6189 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -318,27 +318,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Replace statement
 	 *
 	 * Generates a platform-specific replace string from the supplied data
diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php
index 0a5dc92..f8bd116 100644
--- a/system/database/drivers/sqlite3/sqlite3_forge.php
+++ b/system/database/drivers/sqlite3/sqlite3_forge.php
@@ -111,13 +111,27 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.' '.$attributes['TYPE']
-					.( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '')
-					.(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? ' DEFAULT \''.$attributes['DEFAULT'].'\'' : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
+
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -129,22 +143,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
@@ -182,7 +190,7 @@
 			return FALSE;
 		}
 
-		return 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name)
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
 			.' '.$column_definition
 			.($default_value !== '' ? ' DEFAULT '.$default_value : '')
 			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 961066d..d2b73ae 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -43,7 +43,7 @@
 	public $dbdriver = 'sqlsrv';
 
 	// The character used for escaping
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -55,7 +55,10 @@
 	 * used for the count_all() and count_all_results() functions.
 	 */
 	protected $_count_string = 'SELECT COUNT(*) AS ';
-	protected $_random_keyword = ' NEWID()'; // not currently supported
+	protected $_random_keyword = ' NEWID()';
+
+	// SQLSRV-specific properties
+	protected $_quoted_identifier = TRUE;
 
 	/**
 	 * Non-persistent database connection
@@ -83,7 +86,15 @@
 			unset($connection['UID'], $connection['PWD']);
 		}
 
-		return sqlsrv_connect($this->hostname, $connection);
+		$conn_id = sqlsrv_connect($this->hostname, $connection);
+
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -146,13 +157,8 @@
 	 */
 	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;
 		}
@@ -160,7 +166,7 @@
 		// 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 sqlsrv_begin_transaction($this->conn_id);
 	}
@@ -174,13 +180,8 @@
 	 */
 	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;
 		}
@@ -197,13 +198,8 @@
 	 */
 	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;
 		}
@@ -372,12 +368,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -397,7 +388,7 @@
 	 */
 	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
 	{
-		foreach($values as $key => $val)
+		foreach ($values as $key => $val)
 		{
 			$valstr[] = $key.' = '.$val;
 		}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index d8b5193..e6f7e1a 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -44,7 +44,7 @@
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
 	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
-	 * @return	bool
+	 * @return	string
 	 */
 	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
@@ -75,26 +75,20 @@
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attribues['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -109,22 +103,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($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));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->escape_identifiers($key));
 
 				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
@@ -152,7 +140,7 @@
 	 */
 	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 = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -160,21 +148,10 @@
 			return $sql;
 		}
 
-		$sql .= ' '.$column_definition;
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT '".$default_value."'";
-		}
-
-		$sql .= ($null === NULL) ? ' NULL' : ' NOT NULL';
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index 0802677..f802383 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -92,12 +92,12 @@
 		$retval = array();
 		foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field)
 		{
-			$F 				= new stdClass();
-			$F->name 		= $field['Name'];
-			$F->type 		= $field['Type'];
+			$F 		= new stdClass();
+			$F->name 	= $field['Name'];
+			$F->type 	= $field['Type'];
 			$F->max_length	= $field['Size'];
 			$F->primary_key = 0;
-			$F->default		= '';
+			$F->default	= '';
 
 			$retval[] = $F;
 		}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php
index 394964b..5a71b16 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_utility.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php
@@ -41,7 +41,7 @@
 	 * SQLSRV Export
 	 *
 	 * @param	array	Preferences
-	 * @return	mixed
+	 * @return	bool
 	 */
 	protected function _backup($params = array())
 	{
diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php
index 2d477e6..48939d4 100644
--- a/system/language/english/calendar_lang.php
+++ b/system/language/english/calendar_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index 5335637..38532b7 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/db_lang.php b/system/language/english/db_lang.php
index a135d1a..479cbb1 100644
--- a/system/language/english/db_lang.php
+++ b/system/language/english/db_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/email_lang.php b/system/language/english/email_lang.php
index 23296a2..95a16d1 100644
--- a/system/language/english/email_lang.php
+++ b/system/language/english/email_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 6cf0b46..eb4624e 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index 4e39e43..d00126b 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/imglib_lang.php b/system/language/english/imglib_lang.php
index 67ca942..67a36e1 100644
--- a/system/language/english/imglib_lang.php
+++ b/system/language/english/imglib_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php
index 2085cee..9e3e188 100644
--- a/system/language/english/migration_lang.php
+++ b/system/language/english/migration_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/number_lang.php b/system/language/english/number_lang.php
index 0c19ec6..429c647 100644
--- a/system/language/english/number_lang.php
+++ b/system/language/english/number_lang.php
@@ -5,9 +5,9 @@
  * 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,11 +25,11 @@
  * @filesource
  */
 
-$lang['terabyte_abbr'] = "TB";
-$lang['gigabyte_abbr'] = "GB";
-$lang['megabyte_abbr'] = "MB";
-$lang['kilobyte_abbr'] = "KB";
-$lang['bytes'] = "Bytes";
+$lang['terabyte_abbr'] = 'TB';
+$lang['gigabyte_abbr'] = 'GB';
+$lang['megabyte_abbr'] = 'MB';
+$lang['kilobyte_abbr'] = 'KB';
+$lang['bytes'] = 'Bytes';
 
 /* End of file number_lang.php */
 /* Location: ./system/language/english/number_lang.php */
\ No newline at end of file
diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php
index 11d7912..112527f 100644
--- a/system/language/english/profiler_lang.php
+++ b/system/language/english/profiler_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/unit_test_lang.php b/system/language/english/unit_test_lang.php
index 3a8e144..36e9aca 100644
--- a/system/language/english/unit_test_lang.php
+++ b/system/language/english/unit_test_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/upload_lang.php b/system/language/english/upload_lang.php
index 4fa8394..c3cb9c3 100644
--- a/system/language/english/upload_lang.php
+++ b/system/language/english/upload_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/tests/README.md b/tests/README.md
index c8fc608..d600951 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -21,8 +21,8 @@
 
 vfsStream
 
-	pear channel-discover pear.php-tools.net
-	pear install pat/vfsStream-alpha
+	pear channel-discover pear.bovigo.org
+	pear install bovigo/vfsStream-beta
 
 #### Installation of PEAR and PHPUnit on Ubuntu
 
@@ -37,11 +37,11 @@
 	pear channel-discover pear.phpunit.de
 	pear channel-discover pear.symfony-project.com
 	pear channel-discover components.ez.no
-	pear channel-discover pear.php-tools.net 
+	pear channel-discover pear.bovigo.org
 
 	# Finally install PHPUnit and vfsStream (including dependencies)
 	pear install --alldeps phpunit/PHPUnit
-	pear install --alldeps pat/vfsStream-alpha
+	pear install --alldeps bovigo/vfsStream-beta
 
 	# Finally, run 'phpunit' from within the ./tests directory
 	# and you should be on your way!
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 801f0e4..0880247 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -30,9 +30,10 @@
    -  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.
-   -  Added Romanian and Greek characters in foreign_characters.php
+   -  Added support for ics Calendar files to mimes.php
+   -  Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in 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 Romanian and Greek characters in foreign_characters.php.
    -  Changed logger to only chmod when file is first created.
    -  Removed previously deprecated SHA1 Library.
    -  Removed previously deprecated use of ``$autoload['core']`` in application/config/autoload.php.
@@ -87,10 +88,16 @@
    -  Removed protect_identifiers() and renamed internal method _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).
-   -  Added DSN string support for CUBRID.
-   -  Added persistent connections support for CUBRID.
-   -  Added random ordering support for MSSQL, SQLSRV.
    -  Added support for SQLite3 database driver.
+   -  Improved support of the CUBRID driver, including:
+	 - Added DSN string support.
+	 - Added persistent connections support.
+	 - Improved list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned).
+   -  Improved support of the MSSQL and SQLSRV drivers, including:
+	 - Added random ordering support.
+	 - Added support for optimize_table() in :doc:`Database Utility <database/utilities>`.
+	 - Added escaping with QUOTE_IDENTIFIER setting detection.
+	 - Added port handling support for UNIX-based systems (MSSQL driver).
    -  Improved support of the Oracle (OCI8) driver, including:
 	 -  Added DSN string support (Easy Connect and TNS).
 	 -  Added support for dropping tables to :doc:`Database Forge <database/forge>`.
@@ -100,11 +107,10 @@
 	 -  num_rows() is now only called explicitly by the developer and no longer re-executes statements.
    -  Added replace() support for SQLite.
    -  Renamed internal method _escape_identifiers() to escape_identifiers().
+   -  Updated escape_identifiers() to accept an array of fields as well as strings.
    -  Added SQLite support for drop_table() in :doc:`Database Forge <database/forge>`.
    -  Added ODBC support for create_database(), drop_database() and drop_table() in :doc:`Database Forge <database/forge>`.
    -  Added PDO support for create_database(), drop_database and drop_table() in :doc:`Database Forge <database/forge>`.
-   -  Added MSSQL, SQLSRV support for optimize_table() in :doc:`Database Utility <database/utilities>`.
-   -  Improved CUBRID support for list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned).
    -  Added unbuffered_row() method for getting a row without prefetching whole result (consume less memory).
 
 -  Libraries
@@ -236,6 +242,7 @@
 -  Fixed a bug where the magic_quotes_runtime setting wasn't turned off for PHP 5.3 (where it is indeed deprecated, but not non-existent).
 -  Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset.
 -  Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns.
+-  Fixed a bug (#706) - SQLSRV/MSSSQL didn't escape field names.
 
 Version 2.1.1
 =============