Added and documented Active Record caching.
Made AR fully database-prefix aware
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index ad747d4..ecd404b 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -433,6 +433,13 @@
 	function _protect_identifiers($item, $affect_spaces = TRUE, $first_word_only = FALSE)

 	{

 		// MSSQL doesn't use backticks

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

+		}

+

 		return $item;

 	}

 			

diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index f002572..a5082d1 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -454,6 +454,13 @@
 		// 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|\(';

 

diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index b2e97f9..9e7cc0c 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -448,6 +448,13 @@
 		// 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|\(';

 

diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index ddc0fba..aa2aeca 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -559,6 +559,13 @@
 		// 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|\(';

 

diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 03c0e6a..88fff43 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -424,6 +424,13 @@
 		// 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|\(';

 

diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index e729813..ae8bd86 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -444,6 +444,13 @@
 		// 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|\(';

 

@@ -486,7 +493,7 @@
 			$tables = array($tables);

 		}

 		

-		return implode(', ', $tables);

+		return '('.implode(', ', $tables).')';

 	}

 

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

diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 38febca..dad5eee 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -440,6 +440,13 @@
 		// 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|\(';