Added 'is_unique' which is a brilliant feature I came up with all by myself. Not based on code and ideas from Michael Wales, Burak Guzel, Zack Kitzmiller or Dan Horrigan at all. If they say any differently they are lying.
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index d8bcbd6..c71c8b5 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -26,16 +26,15 @@
  */
 class CI_Form_validation {
 
-	var $CI;
-	var $_field_data			= array();
-	var $_config_rules			= array();
-	var $_error_array			= array();
-	var $_error_messages		= array();
-	var $_error_prefix			= '<p>';
-	var $_error_suffix			= '</p>';
-	var $error_string			= '';
-	var $_safe_form_data		= FALSE;
-
+	protected $CI;
+	protected $_field_data			= array();
+	protected $_config_rules		= array();
+	protected $_error_array			= array();
+	protected $_error_messages		= array();
+	protected $_error_prefix		= '<p>';
+	protected $_error_suffix		= '</p>';
+	protected $error_string			= '';
+	protected $_safe_form_data		= FALSE;
 
 	/**
 	 * Constructor
@@ -72,7 +71,7 @@
 	 * @param	string
 	 * @return	void
 	 */
-	function set_rules($field, $label = '', $rules = '')
+	public function set_rules($field, $label = '', $rules = '')
 	{
 		// No reason to set rules if we have no POST data
 		if (count($_POST) == 0)
@@ -163,7 +162,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function set_message($lang, $val = '')
+	public function set_message($lang, $val = '')
 	{
 		if ( ! is_array($lang))
 		{
@@ -187,7 +186,7 @@
 	 * @param	string
 	 * @return	void
 	 */
-	function set_error_delimiters($prefix = '<p>', $suffix = '</p>')
+	public function set_error_delimiters($prefix = '<p>', $suffix = '</p>')
 	{
 		$this->_error_prefix = $prefix;
 		$this->_error_suffix = $suffix;
@@ -206,7 +205,7 @@
 	 * @param	string	the field name
 	 * @return	void
 	 */
-	function error($field = '', $prefix = '', $suffix = '')
+	public function error($field = '', $prefix = '', $suffix = '')
 	{
 		if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == '')
 		{
@@ -238,7 +237,7 @@
 	 * @param	string
 	 * @return	str
 	 */
-	function error_string($prefix = '', $suffix = '')
+	public function error_string($prefix = '', $suffix = '')
 	{
 		// No errrors, validation passes!
 		if (count($this->_error_array) === 0)
@@ -279,7 +278,7 @@
 	 * @access	public
 	 * @return	bool
 	 */
-	function run($group = '')
+	public function run($group = '')
 	{
 		// Do we even have any data to process? Mm?
 		if (count($_POST) == 0)
@@ -374,7 +373,7 @@
 	 * @param	integer
 	 * @return	mixed
 	 */
-	function _reduce_array($array, $keys, $i = 0)
+	protected function _reduce_array($array, $keys, $i = 0)
 	{
 		if (is_array($array))
 		{
@@ -406,7 +405,7 @@
 	 * @access	private
 	 * @return	null
 	 */
-	function _reset_post_array()
+	protected function _reset_post_array()
 	{
 		foreach ($this->_field_data as $field => $row)
 		{
@@ -468,7 +467,7 @@
 	 * @param	integer
 	 * @return	mixed
 	 */
-	function _execute($row, $rules, $postdata = NULL, $cycles = 0)
+	protected function _execute($row, $rules, $postdata = NULL, $cycles = 0)
 	{
 		// If the $_POST data is an array we will run a recursive call
 		if (is_array($postdata))
@@ -695,7 +694,7 @@
 	 * @param	string	the field name
 	 * @return	string
 	 */
-	function _translate_fieldname($fieldname)
+	protected function _translate_fieldname($fieldname)
 	{
 		// Do we need to translate the field name?
 		// We look for the prefix lang: to determine this
@@ -727,7 +726,7 @@
 	 * @param	string
 	 * @return	void
 	 */
-	function set_value($field = '', $default = '')
+	public function set_value($field = '', $default = '')
 	{
 		if ( ! isset($this->_field_data[$field]))
 		{
@@ -757,7 +756,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function set_select($field = '', $value = '', $default = FALSE)
+	public function set_select($field = '', $value = '', $default = FALSE)
 	{
 		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
 		{
@@ -801,7 +800,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function set_radio($field = '', $value = '', $default = FALSE)
+	public function set_radio($field = '', $value = '', $default = FALSE)
 	{
 		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
 		{
@@ -845,7 +844,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function set_checkbox($field = '', $value = '', $default = FALSE)
+	public function set_checkbox($field = '', $value = '', $default = FALSE)
 	{
 		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
 		{
@@ -885,7 +884,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function required($str)
+	public function required($str)
 	{
 		if ( ! is_array($str))
 		{
@@ -907,7 +906,7 @@
 	 * @param	regex
 	 * @return	bool
 	 */
-	function regex_match($str, $regex)
+	public function regex_match($str, $regex)
 	{
 		if ( ! preg_match($regex, $str))
 		{
@@ -927,7 +926,7 @@
 	 * @param	field
 	 * @return	bool
 	 */
-	function matches($str, $field)
+	public function matches($str, $field)
 	{
 		if ( ! isset($_POST[$field]))
 		{
@@ -938,6 +937,24 @@
 
 		return ($str !== $field) ? FALSE : TRUE;
 	}
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Match one field to another
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	field
+	 * @return	bool
+	 */
+	public function is_unique($str, $field)
+	{
+		list($table, $field)=explode('.', $field);
+		$query = $this->CI->db->limit(1)->get_where($table, array($field => $str));
+		
+		return $query->num_rows() === 0;
+    }
 
 	// --------------------------------------------------------------------
 
@@ -949,7 +966,7 @@
 	 * @param	value
 	 * @return	bool
 	 */
-	function min_length($str, $val)
+	public function min_length($str, $val)
 	{
 		if (preg_match("/[^0-9]/", $val))
 		{
@@ -974,7 +991,7 @@
 	 * @param	value
 	 * @return	bool
 	 */
-	function max_length($str, $val)
+	public function max_length($str, $val)
 	{
 		if (preg_match("/[^0-9]/", $val))
 		{
@@ -999,7 +1016,7 @@
 	 * @param	value
 	 * @return	bool
 	 */
-	function exact_length($str, $val)
+	public function exact_length($str, $val)
 	{
 		if (preg_match("/[^0-9]/", $val))
 		{
@@ -1023,7 +1040,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function valid_email($str)
+	public function valid_email($str)
 	{
 		return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE;
 	}
@@ -1037,7 +1054,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function valid_emails($str)
+	public function valid_emails($str)
 	{
 		if (strpos($str, ',') === FALSE)
 		{
@@ -1064,7 +1081,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function valid_ip($ip)
+	public function valid_ip($ip)
 	{
 		return $this->CI->input->valid_ip($ip);
 	}
@@ -1078,7 +1095,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function alpha($str)
+	public function alpha($str)
 	{
 		return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE;
 	}
@@ -1092,7 +1109,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function alpha_numeric($str)
+	public function alpha_numeric($str)
 	{
 		return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE;
 	}
@@ -1106,7 +1123,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function alpha_dash($str)
+	public function alpha_dash($str)
 	{
 		return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE;
 	}
@@ -1120,7 +1137,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function numeric($str)
+	public function numeric($str)
 	{
 		return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str);
 
@@ -1135,7 +1152,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function is_numeric($str)
+	public function is_numeric($str)
 	{
 		return ( ! is_numeric($str)) ? FALSE : TRUE;
 	}
@@ -1149,7 +1166,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function integer($str)
+	public function integer($str)
 	{
 		return (bool) preg_match('/^[\-+]?[0-9]+$/', $str);
 	}
@@ -1163,7 +1180,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function decimal($str)
+	public function decimal($str)
 	{
 		return (bool) preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str);
 	}
@@ -1177,7 +1194,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function greater_than($str, $min)
+	public function greater_than($str, $min)
 	{
 		if ( ! is_numeric($str))
 		{
@@ -1195,7 +1212,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function less_than($str, $max)
+	public function less_than($str, $max)
 	{
 		if ( ! is_numeric($str))
 		{
@@ -1213,7 +1230,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function is_natural($str)
+	public function is_natural($str)
 	{
 		return (bool) preg_match( '/^[0-9]+$/', $str);
 	}
@@ -1227,7 +1244,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function is_natural_no_zero($str)
+	public function is_natural_no_zero($str)
 	{
 		if ( ! preg_match( '/^[0-9]+$/', $str))
 		{
@@ -1254,7 +1271,7 @@
 	 * @param	string
 	 * @return	bool
 	 */
-	function valid_base64($str)
+	public function valid_base64($str)
 	{
 		return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str);
 	}
@@ -1271,7 +1288,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function prep_for_form($data = '')
+	public function prep_for_form($data = '')
 	{
 		if (is_array($data))
 		{
@@ -1300,7 +1317,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function prep_url($str = '')
+	public function prep_url($str = '')
 	{
 		if ($str == 'http://' OR $str == '')
 		{
@@ -1324,7 +1341,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function strip_image_tags($str)
+	public function strip_image_tags($str)
 	{
 		return $this->CI->input->strip_image_tags($str);
 	}
@@ -1338,7 +1355,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function xss_clean($str)
+	public function xss_clean($str)
 	{
 		return $this->CI->security->xss_clean($str);
 	}
@@ -1352,7 +1369,7 @@
 	 * @param	string
 	 * @return	string
 	 */
-	function encode_php_tags($str)
+	public function encode_php_tags($str)
 	{
 		return str_replace(array('<?php', '<?PHP', '<?', '?>'), array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
 	}
@@ -1361,4 +1378,4 @@
 // END Form Validation Class
 
 /* End of file Form_validation.php */
-/* Location: ./system/libraries/Form_validation.php */
+/* Location: ./system/libraries/Form_validation.php */
\ No newline at end of file