Clean-up the separate drivers' DB result classes from no longer needed methods
diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php
index 3eb9f7e..4c39781 100644
--- a/system/database/drivers/cubrid/cubrid_result.php
+++ b/system/database/drivers/cubrid/cubrid_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		Esen Sagynov
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	2.1
  */
 class CI_DB_cubrid_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @cubrid_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @cubrid_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/ibase/ibase_result.php b/system/database/drivers/ibase/ibase_result.php
index 6a607f5..fdf7409 100644
--- a/system/database/drivers/ibase/ibase_result.php
+++ b/system/database/drivers/ibase/ibase_result.php
@@ -38,26 +38,6 @@
 class CI_DB_ibase_result extends CI_DB_result {
 
 	/**
-	 * Number of rows in the result set
-	 *
-	 * @return	int
-	 */
-	public function num_rows()
-	{
-		if (is_int($this->num_rows))
-		{
-			return $this->num_rows;
-		}
-
-		// Get the results so that you can get an accurate rowcount
-		$this->result();
-
-		return $this->num_rows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Number of fields in the result set
 	 *
 	 * @return	int
@@ -138,13 +118,7 @@
 	 */
 	protected function _fetch_assoc()
 	{
-		if (($row = @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
-		{
-			//Increment row count
-			$this->num_rows++;
-		}
-
-		return $row;
+		return @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS);
 	}
 
 	// --------------------------------------------------------------------
@@ -158,99 +132,7 @@
 	 */
 	protected function _fetch_object()
 	{
-		if (($row = @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
-		{
-			//Increment row count
-			$this->num_rows++;
-		}
-
-		return $row;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result.  "object" version.
-	 *
-	 * @return	object
-	 */
-	public function result_object()
-	{
-		if (count($this->result_object) === $this->num_rows)
-		{
-			return $this->result_object;
-		}
-
-		// Convert result array to object so that
-		// We don't have to get the result again
-		if (($c = count($this->result_array)) > 0)
-		{
-			for ($i = 0; $i < $c; $i++)
-			{
-				$this->result_object[$i] = (object) $this->result_array[$i];
-			}
-
-			return $this->result_object;
-		}
-
-		// In the event that query caching is on the result_id variable
-		// will return FALSE since there isn't a valid SQL resource so
-		// we'll simply return an empty array.
-		if ($this->result_id === FALSE)
-		{
-			return array();
-		}
-
-		$this->num_rows = 0;
-		while ($row = $this->_fetch_object())
-		{
-			$this->result_object[] = $row;
-		}
-
-		return $this->result_object;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result.  "array" version.
-	 *
-	 * @return	array
-	 */
-	public function result_array()
-	{
-		if (count($this->result_array) === $this->num_rows)
-		{
-			return $this->result_array;
-		}
-
-		// Since the object and array are really similar, just case
-		// the result object to an array  if need be
-		if (($c = count($this->result_object)) > 0)
-		{
-			for ($i = 0; $i < $c; $i++)
-			{
-				$this->result_array[$i] = (array) $this->result_object[$i];
-			}
-
-			return $this->result_array;
-		}
-
-		// In the event that query caching is on the result_id variable
-		// will return FALSE since there isn't a valid SQL resource so
-		// we'll simply return an empty array.
-		if ($this->result_id === FALSE)
-		{
-			return array();
-		}
-
-		$this->num_rows = 0;
-		while ($row = $this->_fetch_assoc())
-		{
-			$this->result_array[] = $row;
-		}
-
-		return $this->result_array;
+		return @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS);
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index 5929306..62996aa 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	1.3
  */
 class CI_DB_mssql_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @mssql_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @mssql_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 5b64785..b507f79 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	1.0
  */
 class CI_DB_mysql_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @mysql_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @mysql_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index 9b4d494..bf96ed9 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	1.3
  */
 class CI_DB_mysqli_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return $this->result_id->num_rows;
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = $this->result_id->num_rows;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index f168131..faa295e 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -62,35 +62,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Number of rows in the result set.
-	 *
-	 * Oracle doesn't have a graceful way to return the number of rows
-	 * so we have to use what amounts to a hack.
-	 *
-	 * @return	int
-	 */
-	public function num_rows()
-	{
-		if ( ! is_int($this->num_rows))
-		{
-			if (count($this->result_array) > 0)
-			{
-				return $this->num_rows = count($this->result_array);
-			}
-			elseif (count($this->result_object) > 0)
-			{
-				return $this->num_rows = count($this->result_object);
-			}
-
-			return $this->num_rows = count($this->result_array());
-		}
-
-		return $this->num_rows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Number of fields in the result set
 	 *
 	 * @return	int
@@ -207,444 +178,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Query result. Array version.
-	 *
-	 * @return	array
-	 */
-	public function result_array()
-	{
-		if (count($this->result_array) > 0)
-		{
-			return $this->result_array;
-		}
-		elseif (count($this->result_object) > 0)
-		{
-			for ($i = 0, $c = count($this->result_object); $i < $c; $i++)
-			{
-				$this->result_array[$i] = (array) $this->result_object[$i];
-			}
-
-			return $this->result_array;
-		}
-		elseif (is_array($this->row_data))
-		{
-			if (count($this->row_data) === 0)
-			{
-				return $this->result_array;
-			}
-			else
-			{
-				$row_index = count($this->row_data);
-			}
-		}
-		else
-		{
-			$row_index = 0;
-			$this->row_data = array();
-		}
-
-		$row = NULL;
-		while ($row = $this->_fetch_assoc())
-		{
-			$this->row_data[$row_index++] = $row;
-		}
-
-		return $this->result_array = $this->row_data;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. "object" version.
-	 *
-	 * @return	array
-	 */
-	public function result_object()
-	{
-		if (count($this->result_object) > 0)
-		{
-			return $this->result_object;
-		}
-		elseif (count($this->result_array) > 0)
-		{
-			for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
-			{
-				$this->result_object[] = (object) $this->result_array[$i];
-			}
-
-			return $this->result_object;
-		}
-		elseif (is_array($this->row_data))
-		{
-			if (count($this->row_data) === 0)
-			{
-				return $this->result_object;
-			}
-			else
-			{
-				$row_index = count($this->row_data);
-				for ($i = 0; $i < $row_index; $i++)
-				{
-					$this->result_object[$i] = (object) $this->row_data[$i];
-				}
-			}
-		}
-		else
-		{
-			$row_index = 0;
-			$this->row_data = array();
-		}
-
-		$row = NULL;
-		while ($row = $this->_fetch_object())
-		{
-			$this->row_data[$row_index] = (array) $row;
-			$this->result_object[$row_index++] = $row;
-		}
-
-		return $this->result_object;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. Custom object version.
-	 *
-	 * @param	string	class name used to instantiate rows to
-	 * @return	array
-	 */
-	public function custom_result_object($class_name)
-	{
-		if (isset($this->custom_result_object[$class_name]))
-		{
-			return $this->custom_result_object[$class_name];
-		}
-
-		if ( ! class_exists($class_name) OR $this->result_id === FALSE OR $this->num_rows() === 0)
-		{
-			return array();
-		}
-
-		/* Even if we didn't have result_array or result_object
-		 * set prior to custom_result_object() being called,
-		 * num_rows() has already done so.
-		 * Pass by reference, as we don't know how
-		 * large it might be and we don't want 1000 row
-		 * sets being copied.
-		 */
-		if (count($this->result_array) > 0)
-		{
-			$data = &$this->result_array;
-		}
-		elseif (count($this->result_object) > 0)
-		{
-			$data = &$this->result_object;
-		}
-
-		$this->custom_result_object[$class_name] = array();
-		for ($i = 0, $c = count($data); $i < $c; $i++)
-		{
-			$this->custom_result_object[$class_name][$i] = new $class_name();
-			foreach ($data[$i] as $key => $value)
-			{
-				$this->custom_result_object[$class_name][$i]->$key = $value;
-			}
-		}
-
-		return $this->custom_result_object[$class_name];
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result.
-	 *
-	 * Acts as a wrapper for row_object(), row_array()
-	 * and custom_row_object(). Also used by first_row(), next_row()
-	 * and previous_row().
-	 *
-	 * @param	int	row index
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function row($n = 0, $type = 'object')
-	{
-		if ($type === 'object')
-		{
-			return $this->row_object($n);
-		}
-		elseif ($type === 'array')
-		{
-			return $this->row_array($n);
-		}
-
-		return $this->custom_row_object($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Array version.
-	 *
-	 * @param	int	row index
-	 * @return	array
-	 */
-	public function row_array($n = 0)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-
-		/* If row_data is initialized, it means that we've already tried
-		 * (at least) to fetch some data, so ... check if we already have
-		 * this row.
-		*/
-		if (is_array($this->row_data))
-		{
-			/* If we already have row_data[$n] - return it.
-			 *
-			 * If we enter the elseif, there's a number of reasons to
-			 * return an empty array:
-			 *
-			 *	- count($this->row_data) === 0 means there are no results
-			 *	- num_rows being set, result_array and/or result_object
-			 *	  having count() > 0 means that we've already fetched all
-			 *	  data and $n is greater than our highest row index available
-			 *	- $n < $this->current_row means that if such row existed,
-			 *	  we would've already returned it, therefore $n is an
-			 *	  invalid index
-			 */
-			if (isset($this->row_data[$n])) // We already have this row
-			{
-				$this->current_row = $n;
-				return $this->row_data[$n];
-			}
-			elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
-				OR count($this->result_array) > 0 OR count($this->result_object) > 0
-				OR $n < $this->current_row)
-			{
-				// No such row exists
-				return NULL;
-			}
-
-			// Get the next row index that would actually need to be fetched
-			$current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
-		}
-		else
-		{
-			$current_row = $this->current_row = 0;
-			$this->row_data = array();
-		}
-
-		/* Fetch more data, if available
-		 *
-		 * NOTE: Operator precedence is important here, if you change
-		 *	 'AND' with '&&' - it WILL BREAK the results, as
-		 *	 $row will be assigned the scalar value of both
-		 *	 expressions!
-		 */
-		while ($row = $this->_fetch_assoc() AND $current_row <= $n)
-		{
-			$this->row_data[$current_row++] = $row;
-		}
-
-		// This would mean that there's no (more) data to fetch
-		if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
-		{
-			// Cache what we already have
-			if (is_array($this->row_data))
-			{
-				$this->num_rows = count($this->row_data);
-				/* Usually, row_data could have less elements than result_array,
-				 * but at this point - they should be exactly the same.
-				 */
-				$this->result_array = $this->row_data;
-			}
-			else
-			{
-				$this->num_rows = 0;
-			}
-
-			return NULL;
-		}
-
-		$this->current_row = $n;
-		return $this->row_data[$n];
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Object version.
-	 *
-	 * @param	int	row index
-	 * @return	mixed	object if row found; empty array if not
-	 */
-	public function row_object($n = 0)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-		/* Logic here is exactly the same as in row_array,
-		 * except we have to cast row_data[$n] to an object.
-		 *
-		 * If we already have result_object though - we can
-		 * directly return from it.
-		 */
-		if (isset($this->result_object[$n]))
-		{
-			$this->current_row = $n;
-			// Set this, if not already done.
-			if ( ! is_int($this->num_rows))
-			{
-				$this->num_rows = count($this->result_object);
-			}
-
-			return $this->result_object[$n];
-		}
-
-		$row = $this->row_array($n);
-		// Cast only if the row exists
-		if (count($row) > 0)
-		{
-			$this->current_row = $n;
-			return (object) $row;
-		}
-
-		return NULL;
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Custom object version.
-	 *
-	 * @param	int	row index
-	 * @param	string	custom class name
-	 * @return	mixed	custom object if row found; empty array otherwise
-	 */
-	public function custom_row_object($n = 0, $class_name)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-
-		if (array_key_exists($class_name, $this->custom_result_object))
-		{
-			/* We already have a the whole result set with this class_name,
-			 * return the specified row if it exists, and an empty array if
-			 * it doesn't.
-			 */
-			if (isset($this->custom_result_object[$class_name][$n]))
-			{
-				$this->current_row = $n;
-				return $this->custom_result_object[$class_name][$n];
-			}
-			else
-			{
-				return NULL;
-			}
-		}
-		elseif ( ! class_exists($class_name)) // No such class exists
-		{
-			return NULL;
-		}
-
-		$row = $this->row_array($n);
-		// A non-array would mean that the row doesn't exist
-		if ( ! is_array($row))
-		{
-			return NULL;
-		}
-
-		// Convert to the desired class and return
-		$row_object = new $class_name();
-		foreach ($row as $key => $value)
-		{
-			$row_object->$key = $value;
-		}
-
-		$this->current_row = $n;
-		return $row_object;
-	}
-
-	// --------------------------------------------------------------------
-
-	/* First row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function first_row($type = 'object')
-	{
-		return $this->row(0, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Last row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function last_row($type = 'object')
-	{
-		$result = &$this->result($type);
-		if ( ! isset($this->num_rows))
-		{
-			$this->num_rows = count($result);
-		}
-		$this->current_row = $this->num_rows - 1;
-		return $result[$this->current_row];
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Next row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function next_row($type = 'object')
-	{
-		if (is_array($this->row_data))
-		{
-			$count = count($this->row_data);
-			if ($this->current_row > $count OR ($this->current_row === 0 && $count === 0))
-			{
-				$n = $count;
-			}
-			else
-			{
-				$n = $this->current_row + 1;
-			}
-		}
-		else
-		{
-			$n = 0;
-		}
-
-		return $this->row($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Previous row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function previous_row($type = 'object')
-	{
-		$n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
-		return $this->row($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Data Seek
 	 *
 	 * Moves the internal pointer to the desired offset. We call
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index 0085ef6..1d998be 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -48,14 +48,22 @@
 		{
 			return $this->num_rows;
 		}
-
-		// Work-around for ODBC subdrivers that don't support num_rows()
-		if (($this->num_rows = @odbc_num_rows($this->result_id)) === -1)
+		elseif (($this->num_rows = @odbc_num_rows($this->result_id)) !== -1)
 		{
-			$this->num_rows = count($this->result_array());
+			return $this->num_rows;
 		}
 
-		return $this->num_rows;
+		// Work-around for ODBC subdrivers that don't support num_rows()
+		if (count($this->result_array) > 0)
+		{
+			return $this->num_rows = count($this->result_array);
+		}
+		elseif (count($this->result_object) > 0)
+		{
+			return $this->num_rows = count($this->result_object);
+		}
+
+		return $this->num_rows = count($this->result_array());
 	}
 
 	// --------------------------------------------------------------------
@@ -164,76 +172,6 @@
 		return odbc_fetch_object($this->result_id);
 	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. Array version.
-	 *
-	 * @return	array
-	 */
-	public function result_array()
-	{
-		if (count($this->result_array) > 0)
-		{
-			return $this->result_array;
-		}
-		elseif (($c = count($this->result_object)) > 0)
-		{
-			for ($i = 0; $i < $c; $i++)
-			{
-				$this->result_array[$i] = (array) $this->result_object[$i];
-			}
-		}
-		elseif ($this->result_id === FALSE)
-		{
-			return array();
-		}
-		else
-		{
-			while ($row = $this->_fetch_assoc())
-			{
-				$this->result_array[] = $row;
-			}
-		}
-
-		return $this->result_array;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. Object version.
-	 *
-	 * @return	array
-	 */
-	public function result_object()
-	{
-		if (count($this->result_object) > 0)
-		{
-			return $this->result_object;
-		}
-		elseif (($c = count($this->result_array)) > 0)
-		{
-			for ($i = 0; $i < $c; $i++)
-			{
-				$this->result_object[$i] = (object) $this->result_array[$i];
-			}
-		}
-		elseif ($this->result_id === FALSE)
-		{
-			return array();
-		}
-		else
-		{
-			while ($row = $this->_fetch_object())
-			{
-				$this->result_object[] = $row;
-			}
-		}
-
-		return $this->result_object;
-	}
-
 }
 
 // --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php
index 8671056..8dc16b1 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 2.1.0
+ * @since		Version 1.0
  * @filesource
  */
 
@@ -33,72 +33,35 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	2.1
  */
 class CI_DB_pdo_result extends CI_DB_result {
 
 	/**
-	 * @var bool  Hold the flag whether a result handler already fetched before
-	 */
-	protected $is_fetched = FALSE;
-
-	/**
-	 * @var mixed Hold the fetched assoc array of a result handler
-	 */
-	protected $result_assoc;
-
-	/**
 	 * Number of rows in the result set
 	 *
 	 * @return	int
 	 */
 	public function num_rows()
 	{
-		if (empty($this->result_id) OR ! is_object($this->result_id))
+		if (is_int($this->num_rows))
 		{
-			// invalid result handler
-			return 0;
+			return $this->num_rows;
 		}
-		elseif (($num_rows = $this->result_id->rowCount()) && $num_rows > 0)
+		elseif (count($this->result_array) > 0)
 		{
-			// If rowCount return something, we're done.
-			return $num_rows;
+			return $this->num_rows = count($this->result_array);
+		}
+		elseif (count($this->result_object) > 0)
+		{
+			return $this->num_rows = count($this->result_object);
+		}
+		elseif (($this->num_rows = $this->restul_id->rowCount()) > 0)
+		{
+			return $this->num_rows;
 		}
 
-		// Fetch the result, instead perform another extra query
-		return ($this->is_fetched && is_array($this->result_assoc)) ? count($this->result_assoc) : count($this->result_assoc());
-	}
-
-	/**
-	 * Fetch the result handler
-	 *
-	 * @return	mixed
-	 */
-	public function result_assoc()
-	{
-		// If the result already fetched before, use that one
-		if (count($this->result_array) > 0 OR $this->is_fetched)
-		{
-			return $this->result_array();
-		}
-
-		// Define the output
-		$output = array('assoc', 'object');
-
-		// Initial value
-		$this->result_assoc = array() and $this->result_object = array();
-
-		// Fetch the result
-		while ($row = $this->_fetch_assoc())
-		{
-			$this->result_assoc[] = $row;
-			$this->result_object[] = (object) $row;
-		}
-
-		// Save this as buffer and marked the fetch flag
-		$this->result_array = $this->result_assoc;
-		$this->is_fetched = TRUE;
-
-		return $this->result_assoc;
+		return $this->num_rows = count($this->result_array());
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index f913bc9..515acd2 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	1.3
  */
 class CI_DB_postgre_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @pg_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @pg_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
index 741dc9d..307dec5 100644
--- a/system/database/drivers/sqlite/sqlite_result.php
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	1.3
  */
 class CI_DB_sqlite_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @sqlite_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @sqlite_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php
index b91e76f..4d59bb0 100644
--- a/system/database/drivers/sqlite3/sqlite3_result.php
+++ b/system/database/drivers/sqlite3/sqlite3_result.php
@@ -41,23 +41,6 @@
 	protected $_num_fields;
 
 	/**
-	 * Number of rows in the result set
-	 *
-	 * @return	int
-	 */
-	public function num_rows()
-	{
-		/* The SQLite3 driver doesn't have a graceful way to do this,
-		 * so we'll have to do it on our own.
-		 */
-		return is_int($this->num_rows)
-			? $this->num_rows
-			: $this->num_rows = count($this->result_array());
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Number of fields in the result set
 	 *
 	 * @return	int
@@ -163,436 +146,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Query result. "array" version.
-	 *
-	 * return	array
-	 */
-	public function result_array()
-	{
-		if (count($this->result_array) > 0)
-		{
-			return $this->result_array;
-		}
-		elseif (is_array($this->row_data))
-		{
-			if (count($this->row_data) === 0)
-			{
-				return $this->result_array;
-			}
-			else
-			{
-				$row_index = count($this->row_data);
-			}
-		}
-		else
-		{
-			$row_index = 0;
-			$this->row_data = array();
-		}
-
-		$row = NULL;
-		while ($row = $this->_fetch_assoc())
-		{
-			$this->row_data[$row_index++] = $row;
-		}
-
-		return $this->result_array = $this->row_data;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. "object" version.
-	 *
-	 * @return	array
-	 */
-	public function result_object()
-	{
-		if (count($this->result_object) > 0)
-		{
-			return $this->result_object;
-		}
-		elseif (count($this->result_array) > 0)
-		{
-			for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
-			{
-				$this->result_object[] = (object) $this->result_array[$i];
-			}
-
-			return $this->result_object;
-		}
-		elseif (is_array($this->row_data))
-		{
-			if (count($this->row_data) === 0)
-			{
-				return $this->result_object;
-			}
-			else
-			{
-				$row_index = count($this->row_data);
-				for ($i = 0; $i < $row_index; $i++)
-				{
-					$this->result_object[$i] = (object) $this->row_data[$i];
-				}
-			}
-		}
-		else
-		{
-			$row_index = 0;
-			$this->row_data = array();
-		}
-
-		$row = NULL;
-		while ($row = $this->_fetch_assoc())
-		{
-			$this->row_data[$row_index] = $row;
-			$this->result_object[$row_index++] = (object) $row;
-		}
-
-		$this->result_array = $this->row_data;
-
-		/* As described for the num_rows() method - there's no easy
-		 * way to get the number of rows selected. Our work-around
-		 * solution (as in here as well) first checks if result_array
-		 * exists and returns its count. It doesn't however check for
-		 * custom_object_result, so - do it here.
-		 */
-		if ( ! is_int($this->num_rows))
-		{
-			$this->num_rows = count($this->result_object);
-		}
-
-		return $this->result_object;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Query result. Custom object version.
-	 *
-	 * @param	string	class name used to instantiate rows to
-	 * @return	array
-	 */
-	public function custom_result_object($class_name)
-	{
-		if (array_key_exists($class_name, $this->custom_result_object))
-		{
-			return $this->custom_result_object[$class_name];
-		}
-
-		if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
-		{
-			return array();
-		}
-
-		/* Even if result_array hasn't been set prior to custom_result_object being called,
-		 * num_rows() has done it.
-		*/
-		$data = &$this->result_array;
-
-		$result_object = array();
-		for ($i = 0, $c = count($data); $i < $c; $i++)
-		{
-			$result_object[$i] = new $class_name();
-			foreach ($data[$i] as $key => $value)
-			{
-				$result_object[$i]->$key = $value;
-			}
-		}
-
-		/* As described for the num_rows() method - there's no easy
-		 * way to get the number of rows selected. Our work-around
-		 * solution (as in here as well) first checks if result_array
-		 * exists and returns its count. It doesn't however check for
-		 * custom_object_result, so - do it here.
-		 */
-		if ( ! is_int($this->num_rows))
-		{
-			$this->num_rows = count($result_object);
-		}
-
-		// Cache and return the array
-		return $this->custom_result_object[$class_name] = $result_object;
-        }
-
-	// --------------------------------------------------------------------
-
-	/* Single row result.
-	 *
-	 * Acts as a wrapper for row_object(), row_array()
-	 * and custom_row_object(). Also used by first_row(), next_row()
-	 * and previous_row().
-	 *
-	 * @param	int	row index
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function row($n = 0, $type = 'object')
-	{
-		if ($type === 'object')
-		{
-			return $this->row_object($n);
-		}
-		elseif ($type === 'array')
-		{
-			return $this->row_array($n);
-		}
-
-		return $this->custom_row_object($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Array version.
-	 *
-	 * @param	int	row index
-	 * @return	array
-	 */
-	public function row_array($n = 0)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-
-		/* If row_data is initialized, it means that we've already tried
-		 * (at least) to fetch some data, so ... check if we already have
-		 * this row.
-		*/
-		if (is_array($this->row_data))
-		{
-			/* If we already have row_data[$n] - return it.
-			 *
-			 * If we enter the elseif, there's a number of reasons to
-			 * return an empty array:
-			 *
-			 *	- count($this->row_data) === 0 means there are no results
-			 *	- num_rows being set or result_array having count() > 0 means
-			 *	  that we've already fetched all data and $n is greater than
-			 *	  our highest row index available
-			 *	- $n < $this->current_row means that if such row existed,
-			 *	  we would've already returned it, therefore $n is an
-			 *	  invalid index
-			 */
-			if (isset($this->row_data[$n])) // We already have this row
-			{
-				$this->current_row = $n;
-				return $this->row_data[$n];
-			}
-			elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
-				OR count($this->result_array) > 0 OR $n < $this->current_row)
-			{
-				// No such row exists
-				return NULL;
-			}
-
-			// Get the next row index that would actually need to be fetched
-			$current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
-		}
-		else
-		{
-			$current_row = $this->current_row = 0;
-			$this->row_data = array();
-		}
-
-		/* Fetch more data, if available
-		 *
-		 * NOTE: Operator precedence is important here, if you change
-		 *	 'AND' with '&&' - it WILL BREAK the results, as
-		 *	 $row will be assigned the scalar value of both
-		 *	 expressions!
-		 */
-		while ($row = $this->_fetch_assoc() AND $current_row <= $n)
-		{
-			$this->row_data[$current_row++] = $row;
-		}
-
-		// This would mean that there's no (more) data to fetch
-		if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
-		{
-			// Cache what we already have
-			if (is_array($this->row_data))
-			{
-				$this->num_rows = count($this->row_data);
-				/* Usually, row_data could have less elements than result_array,
-				 * but at this point - they should be exactly the same.
-				 */
-				$this->result_array = $this->row_data;
-			}
-			else
-			{
-				$this->num_rows = 0;
-			}
-
-			return NULL;
-		}
-
-		$this->current_row = $n;
-		return $this->row_data[$n];
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Object version.
-	 *
-	 * @param	int	row index
-	 * @return	mixed	object if row found; empty array if not
-	 */
-	public function row_object($n = 0)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-
-		/* Logic here is exactly the same as in row_array,
-		 * except we have to cast row_data[$n] to an object.
-		 *
-		 * If we already have result_object though - we can
-		 * directly return from it.
-		 */
-		if (isset($this->result_object[$n]))
-		{
-			$this->current_row = $n;
-			return $this->result_object[$n];
-		}
-
-		$row = $this->row_array($n);
-		// Cast only if the row exists
-		if (count($row) > 0)
-		{
-			$this->current_row = $n;
-			return (object) $row;
-		}
-
-		return NULL;
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Single row result. Custom object version.
-	 *
-	 * @param	int	row index
-	 * @param	string	custom class name
-	 * @return	mixed	custom object if row found; empty array otherwise
-	 */
-	public function custom_row_object($n = 0, $class_name)
-	{
-		// Make sure $n is not a string
-		if ( ! is_int($n))
-		{
-			$n = (int) $n;
-		}
-
-		if (array_key_exists($class_name, $this->custom_result_object))
-		{
-			/* We already have a the whole result set with this class_name,
-			 * return the specified row if it exists, and an empty array if
-			 * it doesn't.
-			 */
-			if (isset($this->custom_result_object[$class_name][$n]))
-			{
-				$this->current_row = $n;
-				return $this->custom_result_object[$class_name][$n];
-			}
-			else
-			{
-				return NULL;
-			}
-		}
-		elseif ( ! class_exists($class_name)) // No such class exists
-		{
-			return NULL;
-		}
-
-		$row = $this->row_array($n);
-		// A non-array would mean that the row doesn't exist
-		if ( ! is_array($row))
-		{
-			return NULL;
-		}
-
-		// Convert to the desired class and return
-		$row_object = new $class_name();
-		foreach ($row as $key => $value)
-		{
-			$row_object->$key = $value;
-		}
-
-		$this->current_row = $n;
-		return $row_object;
-	}
-
-	// --------------------------------------------------------------------
-
-	/* First row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function first_row($type = 'object')
-	{
-		return $this->row(0, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Last row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function last_row($type = 'object')
-	{
-		$result = &$this->result($type);
-		if ( ! isset($this->num_rows))
-		{
-			$this->num_rows = count($result);
-		}
-		$this->current_row = $this->num_rows - 1;
-		return $result[$this->current_row];
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Next row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function next_row($type = 'object')
-	{
-		if (is_array($this->row_data))
-		{
-			$count = count($this->row_data);
-			$n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
-		}
-		else
-		{
-			$n = 0;
-		}
-
-		return $this->row($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/* Previous row result.
-	 *
-	 * @param	string	('object', 'array' or a custom class name)
-	 * @return	mixed	whatever was passed to the second parameter
-	 */
-	public function previous_row($type = 'object')
-	{
-		$n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
-		return $this->row($n, $type);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Data Seek
 	 *
 	 * Moves the internal pointer to the desired offset. We call
diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index f9d5a0d..d469ff4 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 2.0.3
+ * @since		Version 1.0
  * @filesource
  */
 
@@ -33,6 +33,7 @@
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
+ * @since	2.0.3
  */
 class CI_DB_sqlsrv_result extends CI_DB_result {
 
@@ -43,7 +44,9 @@
 	 */
 	public function num_rows()
 	{
-		return @sqlsrv_num_rows($this->result_id);
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = @sqlsrv_num_rows($this->result_id);
 	}
 
 	// --------------------------------------------------------------------