Fixed a number of bug reports related to table/db names not being escaped or prefixed correctly.
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index db04c6d..34b6012 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -32,6 +32,9 @@
 

 	var $dbdriver = 'mysql';

 

+	// The character used for escaping

+	var	$_escape_char = '`';

+	

 	/**

 	 * Whether to use the MySQL "delete hack" which allows the number

 	 * of affected rows to be shown. Uses a preg_replace when enabled,

@@ -314,7 +317,7 @@
 		if ($table == '')

 			return '0';

 	

-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));

+		$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';

@@ -336,7 +339,7 @@
 	 */

 	function _list_tables($prefix_limit = FALSE)

 	{

-		$sql = "SHOW TABLES FROM `".$this->database."`";	

+		$sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;	

 

 		if ($prefix_limit !== FALSE AND $this->dbprefix != '')

 		{

@@ -359,7 +362,7 @@
 	 */

 	function _list_columns($table = '')

 	{

-		return "SHOW COLUMNS FROM ".$this->_escape_table($table);

+		return "SHOW COLUMNS FROM ".$table;

 	}

 

 	// --------------------------------------------------------------------

@@ -375,7 +378,7 @@
 	 */

 	function _field_data($table)

 	{

-		return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";

+		return "SELECT * FROM ".$table." LIMIT 1";

 	}

 

 	// --------------------------------------------------------------------

@@ -407,99 +410,32 @@
 	// --------------------------------------------------------------------

 

 	/**

-	 * Escape Column Name

+	 * Escape the SQL Identifiers

 	 *

-	 * This function adds backticks around supplied column name

+	 * This function escapes column and table names

 	 *

 	 * @access	private

-	 * @param	string	the column name

+	 * @param	string

 	 * @return	string

 	 */

-	function _escape_column($column)

+	function _escape_identifiers($item)

 	{

-		return '`' .$column. '`';

-	}

-	

-	// --------------------------------------------------------------------

-

-	/**

-	 * Escape Table Name

-	 *

-	 * This function adds backticks if the table name has a period

-	 * in it. Some DBs will get cranky unless periods are escaped

-	 *

-	 * @access	private

-	 * @param	string	the table name

-	 * @return	string

-	 */

-	function _escape_table($table)

-	{

-		if (strpos($table, '.') !== FALSE)

+		if ($this->_escape_char == '')

 		{

-			$table = '`' . str_replace('.', '`.`', $table) . '`';

+			return $item;

 		}

-		

-		return $table;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Protect Identifiers

-	 *

-	 * This function adds backticks if appropriate based on db type

-	 *

-	 * @access	private

-	 * @param	mixed	the item to escape

-	 * @param	boolean	only affect the first word

-	 * @return	mixed	the item with backticks

-	 */

-	function _protect_identifiers($item, $first_word_only = FALSE)

-	{

-		if (is_array($item))

+	

+		if (strpos($item, '.') !== FALSE)

 		{

-			$escaped_array = array();

-

-			foreach($item as $k=>$v)

-			{

-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);

-			}

-

-			return $escaped_array;

-		}	

-

-		// This function may get "item1 item2" as a string, and so

-		// we may need "`item1` `item2`" and not "`item1 item2`"

-		if (ctype_alnum($item) === FALSE)

-		{

-			if (strpos($item, '.') !== FALSE)

-			{

-				$aliased_tables = implode(".",$this->ar_aliased_tables).'.';

-				$table_name =  substr($item, 0, strpos($item, '.')+1);

-				$item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;

-			}

-

-			// This function may get "field >= 1", and need it to return "`field` >= 1"

-			$lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';

-

-			$item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1`$2`$3', $item);

+			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;			

 		}

 		else

 		{

-			return "`{$item}`";

+			$str = $this->_escape_char.$item.$this->_escape_char;

 		}

-

-		$exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');

 		

-		foreach ($exceptions as $exception)

-		{

-		

-			if (stristr($item, " `{$exception}` ") !== FALSE)

-			{

-				$item = preg_replace('/ `('.preg_quote($exception).')` /i', ' $1 ', $item);

-			}

-		}

-		return $item;

+		// remove duplicates if the user already included the escape

+		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);

 	}

 			

 	// --------------------------------------------------------------------

@@ -539,7 +475,7 @@
 	 */

 	function _insert($table, $keys, $values)

 	{	

-		return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

+		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

 	}

 	

 	// --------------------------------------------------------------------

@@ -568,8 +504,10 @@
 		

 		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';

 	

-		$sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);

+		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);

+

 		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';

+

 		$sql .= $orderby.$limit;

 		

 		return $sql;

@@ -590,7 +528,7 @@
 	 */	

 	function _truncate($table)

 	{

-		return "TRUNCATE ".$this->_escape_table($table);

+		return "TRUNCATE ".$table;

 	}

 	

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index e2a2225..28a77b3 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -147,7 +147,7 @@
 			$sql .= 'IF NOT EXISTS ';

 		}

 		

-		$sql .= $this->db->_escape_table($table)." (";

+		$sql .= $this->db->_escape_identifiers($table)." (";

 

 		$sql .= $this->_process_fields($fields);

 

@@ -192,7 +192,7 @@
 	 */

 	function _drop_table($table)

 	{

-		return "DROP TABLE IF EXISTS ".$this->db->_escape_table($table);

+		return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index ec75955..a28a198 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -70,12 +70,6 @@
 		

 		return $field_names;

 	}

-	

-	// Deprecated

-	function field_names()

-	{

-		return $this->list_fields();

-	}

 

 	// --------------------------------------------------------------------

 

diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index e035e0c..62a77b7 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -48,7 +48,7 @@
 	 */

 	function _optimize_table($table)

 	{

-		return "OPTIMIZE TABLE ".$this->db->_escape_table($table);

+		return "OPTIMIZE TABLE ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

@@ -64,7 +64,7 @@
 	 */

 	function _repair_table($table)

 	{

-		return "REPAIR TABLE ".$this->db->_escape_table($table);

+		return "REPAIR TABLE ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index a5d104c..f7c986f 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -31,6 +31,9 @@
 class CI_DB_mysqli_driver extends CI_DB {

 

 	var $dbdriver = 'mysqli';

+	

+	// The character used for escaping

+	var $_escape_char = '`';

 

 	/**

 	 * The syntax to count rows is slightly different across different

@@ -91,12 +94,12 @@
 	/**

 	 * Set client character set

 	 *

-	 * @access	public

+	 * @access	private

 	 * @param	string

 	 * @param	string

 	 * @return	resource

 	 */

-	function db_set_charset($charset, $collation)

+	function _db_set_charset($charset, $collation)

 	{

 		return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");

 	}

@@ -306,8 +309,8 @@
 	{

 		if ($table == '')

 			return '0';

-	

-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));

+		

+		$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';

@@ -329,7 +332,7 @@
 	 */

 	function _list_tables($prefix_limit = FALSE)

 	{

-		$sql = "SHOW TABLES FROM `".$this->database."`";	

+		$sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;	

 		

 		if ($prefix_limit !== FALSE AND $this->dbprefix != '')

 		{

@@ -352,7 +355,7 @@
 	 */

 	function _list_columns($table = '')

 	{

-		return "SHOW COLUMNS FROM ".$this->_escape_table($table);

+		return "SHOW COLUMNS FROM ".$table;

 	}

 

 	// --------------------------------------------------------------------

@@ -368,7 +371,7 @@
 	 */

 	function _field_data($table)

 	{

-		return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";

+		return "SELECT * FROM ".$table." LIMIT 1";

 	}

 

 	// --------------------------------------------------------------------

@@ -400,99 +403,32 @@
 	// --------------------------------------------------------------------

 

 	/**

-	 * Escape Column Name

+	 * Escape the SQL Identifiers

 	 *

-	 * This function adds backticks around supplied column name

+	 * This function escapes column and table names

 	 *

 	 * @access	private

-	 * @param	string	the column name

+	 * @param	string

 	 * @return	string

 	 */

-	function _escape_column($column)

+	function _escape_identifiers($item)

 	{

-		return '`' .$column. '`';

-	}

-	

-	// --------------------------------------------------------------------

-

-	/**

-	 * Escape Table Name

-	 *

-	 * This function adds backticks if the table name has a period

-	 * in it. Some DBs will get cranky unless periods are escaped

-	 *

-	 * @access	private

-	 * @param	string	the table name

-	 * @return	string

-	 */

-	function _escape_table($table)

-	{

-		if (strpos($table, '.') !== FALSE)

+		if ($this->_escape_char == '')

 		{

-			$table = '`' . str_replace('.', '`.`', $table) . '`';

+			return $item;

 		}

-		

-		return $table;

-	}

-		

-	// --------------------------------------------------------------------

-

-	/**

-	 * Protect Identifiers

-	 *

-	 * This function adds backticks if appropriate based on db type

-	 *

-	 * @access	private

-	 * @param	mixed	the item to escape

-	 * @param	boolean	only affect the first word

-	 * @return	mixed	the item with backticks

-	 */

-	function _protect_identifiers($item, $first_word_only = FALSE)

-	{

-		if (is_array($item))

+	

+		if (strpos($item, '.') !== FALSE)

 		{

-			$escaped_array = array();

-

-			foreach($item as $k=>$v)

-			{

-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);

-			}

-

-			return $escaped_array;

-		}	

-

-		// This function may get "item1 item2" as a string, and so

-		// we may need "`item1` `item2`" and not "`item1 item2`"

-		if (ctype_alnum($item) === FALSE)

-		{

-			if (strpos($item, '.') !== FALSE)

-			{

-				$aliased_tables = implode(".",$this->ar_aliased_tables).'.';

-				$table_name =  substr($item, 0, strpos($item, '.')+1);

-				$item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;

-			}

-

-			// This function may get "field >= 1", and need it to return "`field` >= 1"

-			$lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';

-

-			$item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1`$2`$3', $item);

+			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;			

 		}

 		else

 		{

-			return "`{$item}`";

+			$str = $this->_escape_char.$item.$this->_escape_char;

 		}

-

-		$exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');

 		

-		foreach ($exceptions as $exception)

-		{

-		

-			if (stristr($item, " `{$exception}` ") !== FALSE)

-			{

-				$item = preg_replace('/ `('.preg_quote($exception).')` /i', ' $1 ', $item);

-			}

-		}

-		return $item;

+		// remove duplicates if the user already included the escape

+		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);

 	}

 			

 	// --------------------------------------------------------------------

@@ -532,7 +468,7 @@
 	 */

 	function _insert($table, $keys, $values)

 	{	

-		return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

+		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

 	}

 	

 	// --------------------------------------------------------------------

@@ -561,8 +497,10 @@
 		

 		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';

 	

-		$sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);

+		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);

+		

 		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';

+		

 		$sql .= $orderby.$limit;

 		

 		return $sql;

@@ -584,7 +522,7 @@
 	 */	

 	function _truncate($table)

 	{

-		return "TRUNCATE ".$this->_escape_table($table);

+		return "TRUNCATE ".$table;

 	}

 	

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index ce6ab45..c7889bf 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -147,7 +147,7 @@
 			$sql .= 'IF NOT EXISTS ';

 		}

 		

-		$sql .= $this->db->_escape_table($table)." (";

+		$sql .= $this->db->_escape_identifiers($table)." (";

 

 		$sql .= $this->_process_fields($fields);

 

@@ -192,7 +192,7 @@
 	 */

 	function _drop_table($table)

 	{

-		return "DROP TABLE IF EXISTS ".$this->db->_escape_table($table);

+		return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index 0a97454..b690914 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -71,12 +71,6 @@
 		return $field_names;

 	}

 

-	// Deprecated

-	function field_names()

-	{

-		return $this->list_fields();

-	}

-

 	// --------------------------------------------------------------------

 

 	/**

diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php
index 0080bfc..d19b643 100644
--- a/system/database/drivers/mysqli/mysqli_utility.php
+++ b/system/database/drivers/mysqli/mysqli_utility.php
@@ -48,7 +48,7 @@
 	 */

 	function _optimize_table($table)

 	{

-		return "OPTIMIZE TABLE ".$this->db->_escape_table($table);

+		return "OPTIMIZE TABLE ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

@@ -64,7 +64,7 @@
 	 */

 	function _repair_table($table)

 	{

-		return "REPAIR TABLE ".$this->db->_escape_table($table);

+		return "REPAIR TABLE ".$this->db->_escape_identifiers($table);

 	}

 

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 1a66978..4b073d0 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -72,7 +72,7 @@
 			$sql .= 'IF NOT EXISTS ';

 		}

 		

-		$sql .= $this->db->_escape_table($table)." (";

+		$sql .= $this->db->_escape_identifiers($table)." (";

 		$current_field_count = 0;

 

 		foreach ($fields as $field=>$attributes)

diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index 9bc982f..4cfbfa4 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -95,12 +95,6 @@
 		return $field_names;

 	}

 

-	// Deprecated

-	function field_names()

-	{

-		return $this->list_fields();

-	}

-

 	// --------------------------------------------------------------------

 

 	/**

diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index cc8d334..5041268 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -31,6 +31,9 @@
 class CI_DB_odbc_driver extends CI_DB {

 

 	var $dbdriver = 'odbc';

+	

+	// the character used to excape - not necessary for ODBC

+	var $_escape_char = '';

 

 	/**

 	 * The syntax to count rows is slightly different across different

@@ -294,7 +297,7 @@
 		if ($table == '')

 			return '0';

 	

-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));

+		$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';

@@ -340,7 +343,7 @@
 	 */

 	function _list_columns($table = '')

 	{

-		return "SHOW COLUMNS FROM ".$this->_escape_table($table);

+		return "SHOW COLUMNS FROM ".$table;

 	}

 

 	// --------------------------------------------------------------------

@@ -356,7 +359,7 @@
 	 */

 	function _field_data($table)

 	{

-		return "SELECT TOP 1 FROM ".$this->_escape_table($table);

+		return "SELECT TOP 1 FROM ".$table;

 	}

 

 	// --------------------------------------------------------------------

@@ -384,99 +387,36 @@
 	{

 		return odbc_error($this->conn_id);

 	}

+

 	// --------------------------------------------------------------------

 

 	/**

-	 * Escape Column Name

+	 * Escape the SQL Identifiers

 	 *

-	 * This function adds backticks around supplied column name

+	 * This function escapes column and table names

 	 *

 	 * @access	private

-	 * @param	string	the column name

+	 * @param	string

 	 * @return	string

 	 */

-	function _escape_column($column)

+	function _escape_identifiers($item)

 	{

-		// Not necessary with ODBC so we simply return the value

-		return $column;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Escape Table Name

-	 *

-	 * This function adds backticks if the table name has a period

-	 * in it. Some DBs will get cranky unless periods are escaped

-	 *

-	 * @access	private

-	 * @param	string	the table name

-	 * @return	string

-	 */

-	function _escape_table($table)

-	{

-		// Not necessary with ODBC so we simply return the value

-		return $table;

-	}	

-		

-	// --------------------------------------------------------------------

-

-	/**

-	 * Protect Identifiers

-	 *

-	 * This function adds backticks if appropriate based on db type

-	 *

-	 * @access	private

-	 * @param	mixed	the item to escape

-	 * @param	boolean	only affect the first word

-	 * @return	mixed	the item with backticks

-	 */

-	function _protect_identifiers($item, $first_word_only = FALSE)

-	{

-		if (is_array($item))

+		if ($this->_escape_char == '')

 		{

-			$escaped_array = array();

-

-			foreach($item as $k=>$v)

-			{

-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);

-			}

-

-			return $escaped_array;

-		}	

-

-		// This function may get "item1 item2" as a string, and so

-		// we may need "`item1` `item2`" and not "`item1 item2`"

-		if (ctype_alnum($item) === FALSE)

+			return $item;

+		}

+	

+		if (strpos($item, '.') !== FALSE)

 		{

-			if (strpos($item, '.') !== FALSE)

-			{

-				$aliased_tables = implode(".",$this->ar_aliased_tables).'.';

-				$table_name =  substr($item, 0, strpos($item, '.')+1);

-				$item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;

-			}

-

-			// This function may get "field >= 1", and need it to return "`field` >= 1"

-			$lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';

-

-			$item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1`$2`$3', $item);

+			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;			

 		}

 		else

 		{

-			return "{$item}";

+			$str = $this->_escape_char.$item.$this->_escape_char;

 		}

-

-		$exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');

 		

-		foreach ($exceptions as $exception)

-		{

-		

-			if (stristr($item, " {$exception} ") !== FALSE)

-			{

-				$item = preg_replace('/ ('.preg_quote($exception).') /i', ' $1 ', $item);

-			}

-		}

-		return $item;

+		// remove duplicates if the user already included the escape

+		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);

 	}

 			

 	// --------------------------------------------------------------------

@@ -516,7 +456,7 @@
 	 */

 	function _insert($table, $keys, $values)

 	{	

-		return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

+		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

 	}

 	

 	// --------------------------------------------------------------------

@@ -545,8 +485,10 @@
 		

 		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';

 	

-		$sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);

+		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);

+

 		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';

+

 		$sql .= $orderby.$limit;

 		

 		return $sql;

diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index de67b94..099925c 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -84,7 +84,7 @@
 			$sql .= 'IF NOT EXISTS ';

 		}

 		

-		$sql .= $this->db->_escape_table($table)." (";

+		$sql .= $this->db->_escape_identifiers($table)." (";

 		$current_field_count = 0;

 

 		foreach ($fields as $field=>$attributes)

diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index 8b485ec..6d6542e 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -71,12 +71,6 @@
 		return $field_names;

 	}

 

-	// Deprecated

-	function field_names()

-	{

-		return $this->list_fields();

-	}

-

 	// --------------------------------------------------------------------

 

 	/**

diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index c5c70a7..d94cce1 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -31,6 +31,8 @@
 class CI_DB_postgre_driver extends CI_DB {

 

 	var $dbdriver = 'postgre';

+	

+	var $_escape_char = '"';

 

 	/**

 	 * The syntax to count rows is slightly different across different

@@ -329,7 +331,7 @@
 		if ($table == '')

 			return '0';

 

-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));

+		$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';

@@ -374,7 +376,7 @@
 	 */

 	function _list_columns($table = '')

 	{

-		return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$this->_escape_table($table)."'";

+		return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'";

 	}

 

 	// --------------------------------------------------------------------

@@ -390,7 +392,7 @@
 	 */

 	function _field_data($table)

 	{

-		return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";

+		return "SELECT * FROM ".$table." LIMIT 1";

 	}

 

 	// --------------------------------------------------------------------

@@ -418,103 +420,36 @@
 	{

 		return '';

 	}

-	// --------------------------------------------------------------------

-

-	/**

-	 * Escape Column Name

-	 *

-	 * This function adds backticks around supplied column name

-	 *

-	 * @access	private

-	 * @param	string	the column name

-	 * @return	string

-	 */

-	function _escape_column($column)

-	{

-		// Probably not necessary with Postgres so we simply return the value

-		return $column;

-	}

 

 	// --------------------------------------------------------------------

 

 	/**

-	 * Escape Table Name

+	 * Escape the SQL Identifiers

 	 *

-	 * This function adds backticks if the table name has a period

-	 * in it. Some DBs will get cranky unless periods are escaped.

+	 * This function escapes column and table names

 	 *

 	 * @access	private

-	 * @param	string	the table name

+	 * @param	string

 	 * @return	string

 	 */

-	function _escape_table($table)

+	function _escape_identifiers($item)

 	{

-		if (strpos($table, '.') !== FALSE)

+		if ($this->_escape_char == '')

 		{

-			$table = '"' . str_replace('.', '"."', $table) . '"';

+			return $item;

 		}

-		

-		return $table;

-	}

 	

-	// --------------------------------------------------------------------

-

-	/**

-	 * Protect Identifiers

-	 *

-	 * This function adds backticks if appropriate based on db type

-	 *

-	 * @access	private

-	 * @param	mixed	the item to escape

-	 * @param	boolean	only affect the first word

-	 * @return	mixed	the item with backticks

-	 */

-	function _protect_identifiers($item, $first_word_only = FALSE)

-	{

-		if (is_array($item))

+		if (strpos($item, '.') !== FALSE)

 		{

-			$escaped_array = array();

-

-			foreach($item as $k=>$v)

-			{

-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);

-			}

-

-			return $escaped_array;

-		}	

-

-		// This function may get "item1 item2" as a string, and so

-		// we may need ""item1" "item2"" and not ""item1 item2""

-		if (ctype_alnum($item) === FALSE)

-		{

-			if (strpos($item, '.') !== FALSE)

-			{

-				$aliased_tables = implode(".",$this->ar_aliased_tables).'.';

-				$table_name =  substr($item, 0, strpos($item, '.')+1);

-				$item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;

-			}

-

-			// This function may get "field >= 1", and need it to return ""field" >= 1"

-			$lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';

-

-			$item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1"$2"$3', $item);

+			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;			

 		}

 		else

 		{

-			return "\"{$item}\"";

+			$str = $this->_escape_char.$item.$this->_escape_char;

 		}

-

-		$exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');

 		

-		foreach ($exceptions as $exception)

-		{

-		

-			if (stristr($item, " \"{$exception}\" ") !== FALSE)

-			{

-				$item = preg_replace('/ "('.preg_quote($exception).')" /i', ' $1 ', $item);

-			}

-		}

-		return $item;

+		// remove duplicates if the user already included the escape

+		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);

 	}

 			

 	// --------------------------------------------------------------------

@@ -554,7 +489,7 @@
 	 */

 	function _insert($table, $keys, $values)

 	{	

-		return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

+		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";

 	}

 	

 	// --------------------------------------------------------------------

@@ -583,14 +518,15 @@
 		

 		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';

 	

-		$sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);

+		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);

+

 		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';

+

 		$sql .= $orderby.$limit;

 		

 		return $sql;

 	}

 

-	

 	// --------------------------------------------------------------------

 

 	/**

@@ -606,7 +542,7 @@
 	 */	

 	function _truncate($table)

 	{

-		return "TRUNCATE ".$this->_escape_table($table);

+		return "TRUNCATE ".$table;

 	}

 	

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index b9e1cd9..5b4bcc2 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -72,7 +72,7 @@
 			$sql .= 'IF NOT EXISTS ';

 		}

 		

-		$sql .= $this->db->_escape_table($table)." (";

+		$sql .= $this->db->_escape_identifiers($table)." (";

 		$current_field_count = 0;

 

 		foreach ($fields as $field=>$attributes)

@@ -167,7 +167,7 @@
 	 */

 	function _drop_table($table)

 	{

-		return "DROP TABLE ".$this->db->_escape_table($table)." CASCADE";

+		return "DROP TABLE ".$this->db->_escape_identifiers($table)." CASCADE";

 	}

 

 	// --------------------------------------------------------------------

diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index d018a9b..2e1e003 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -71,12 +71,6 @@
 		return $field_names;

 	}

 

-	// Deprecated

-	function field_names()

-	{

-		return $this->list_fields();

-	}

-

 	// --------------------------------------------------------------------

 

 	/**