Merge branch 'develop' into feature/minify
diff --git a/.travis.yml b/.travis.yml
index ab0aa56..fa9d5e5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,7 @@
 php:
   - 5.3
   - 5.4
+  - 5.5
   
 env:
   - DB=mysql
diff --git a/readme.rst b/readme.rst
index 5857558..619c7ae 100644
--- a/readme.rst
+++ b/readme.rst
@@ -49,9 +49,9 @@
 Resources
 *********
 
--  `User Guide <http://codeigniter.com/user_guide/>`_
--  `Community Forums <http://codeigniter.com/forums/>`_
--  `Community Wiki <http://codeigniter.com/wiki/>`_
+-  `User Guide <http://ellislab.com/codeigniter/user_guide/>`_
+-  `Community Forums <http://ellislab.com/codeigniter/forums/>`_
+-  `Community Wiki <http://ellislab.com/codeigniter/wiki/>`_
 -  `Community IRC <http://ellislab.com/codeigniter/irc>`_
 
 ***************
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index d52029e..92806d3 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -740,6 +740,18 @@
 					'_literal'		=> FALSE
 			);
 
+			if ($create_table === FALSE)
+			{
+				if (isset($attributes['AFTER']))
+				{
+					$field['after'] = $attributes['AFTER'];
+				}
+				elseif (isset($attributes['FIRST']))
+				{
+					$field['first'] = (bool) $attributes['FIRST'];
+				}
+			}
+
 			$this->_attr_default($attributes, $field);
 
 			if (isset($attributes['NULL']))
@@ -748,11 +760,15 @@
 				{
 					$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
 				}
-				elseif ($create_table === TRUE)
+				else
 				{
 					$field['null'] = ' NOT NULL';
 				}
 			}
+			elseif ($create_table === TRUE)
+			{
+				$field['null'] = ' NOT NULL';
+			}
 
 			$this->_attr_auto_increment($attributes, $field);
 			$this->_attr_unique($attributes, $field);
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index ebc9855..a734603 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -2291,7 +2291,12 @@
 		{
 			for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
 			{
-				if ($this->{$qb_key}[$i]['escape'] === FALSE)
+				// Is this condition already compiled?
+				if (is_string($this->{$qb_key}[$i]))
+				{
+					continue;
+				}
+				elseif ($this->{$qb_key}[$i]['escape'] === FALSE)
 				{
 					$this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
 					continue;
@@ -2361,6 +2366,12 @@
 		{
 			for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
 			{
+				// Is it already compiled?
+				if (is_string($this->qb_groupby))
+				{
+					continue;
+				}
+
 				$this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field']))
 					? $this->qb_groupby[$i]['field']
 					: $this->protect_identifiers($this->qb_groupby[$i]['field']);
diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php
index 40823fc..f13e447 100644
--- a/system/libraries/Cache/drivers/Cache_redis.php
+++ b/system/libraries/Cache/drivers/Cache_redis.php
@@ -44,6 +44,7 @@
 	 * @var	array
 	 */
 	protected static $_default_config = array(
+		'socket_type' => 'tcp',
 		'host' => '127.0.0.1',
 		'password' => NULL,
 		'port' => 6379,
@@ -163,8 +164,7 @@
 	{
 		if (extension_loaded('redis'))
 		{
-			$this->_setup_redis();
-			return TRUE;
+			return $this->_setup_redis();
 		}
 		else
 		{
@@ -200,17 +200,33 @@
 
 		try
 		{
-			$this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+			if ($config['socket_type'] === 'unix')
+			{
+				$success = $this->_redis->connect($config['socket']);
+			}
+			else // tcp socket
+			{
+				$success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+			}
+			
+			if ( ! $success)
+			{
+				log_message('debug', 'Cache: Redis connection refused. Check the config.');
+				return FALSE;
+			}
 		}
 		catch (RedisException $e)
 		{
-			show_error('Redis connection refused. ' . $e->getMessage());
+			log_message('debug', 'Cache: Redis connection refused ('.$e->getMessage().')');
+			return FALSE;
 		}
 
 		if (isset($config['password']))
 		{
 			$this->_redis->auth($config['password']);
 		}
+		
+		return TRUE;
 	}
 
 	// ------------------------------------------------------------------------
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index c191432..1c1100b 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -623,6 +623,7 @@
 -  Fixed a bug (#2681) - ``CI_Security::entity_decode()`` used the `PREG_REPLACE_EVAL` flag, which is deprecated since PHP 5.5.
 -  Fixed a bug (#2691) - nested transactions could end in a deadlock when an error is encountered with *db_debug* set to TRUE.
 -  Fixed a bug (#2515) - ``_exception_handler()`` used to send the 200 "OK" HTTP status code and didn't stop script exection even on fatal errors.
+-  Fixed a bug - Redis :doc:`Caching <libraries/caching>` driver didn't handle connection failures properly.
 
 Version 2.1.4
 =============
diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst
index 8d7b4c4..3f7dc2d 100644
--- a/user_guide_src/source/libraries/caching.rst
+++ b/user_guide_src/source/libraries/caching.rst
@@ -239,17 +239,28 @@
 Redis Caching
 =============
 
+Redis is an in-memory key-value store which can operate in LRU cache mode. 
+To use it, you need Redis server and phpredis PHP extension 
+`https://github.com/nicolasff/phpredis <https://github.com/nicolasff/phpredis>`_.
+
+Config options to connect to redis server must be stored in the application/config/redis.php file.
+Available options are::
+	
+	$config['socket_type'] = 'tcp'; //`tcp` or `unix`
+	$config['socket'] = '/var/run/redis.sock'; // in case of `unix` socket type
+	$config['host'] = '127.0.0.1';
+	$config['password'] = NULL;
+	$config['port'] = 6379;
+	$config['timeout'] = 0;
+
 All of the methods listed above can be accessed without passing a
 specific adapter to the driver loader as follows::
 
 	$this->load->driver('cache');
 	$this->cache->redis->save('foo', 'bar', 10);
 
-.. important:: Redis may require one or more of the following options:
-	**host**, **post**, **timeout**, **password**.
-
-The Redis PHP extension repository is located at
-`https://github.com/nicolasff/phpredis <https://github.com/nicolasff/phpredis>`_.
+For more information on Redis, please see
+`http://redis.io <http://redis.io>`_.
 
 Dummy Cache
 ===========
diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst
index 36c7c1d..2f8bea0 100644
--- a/user_guide_src/source/libraries/sessions.rst
+++ b/user_guide_src/source/libraries/sessions.rst
@@ -252,7 +252,7 @@
 ===================
 
 You'll find the following Session related preferences in your
-application/config/config.php file:
+*application/config/config.php* file:
 
 =========================== =============== =========================== ==========================================================================
 Preference                  Default         Options                     Description
@@ -271,7 +271,8 @@
                                                                         table before enabling this option (Cookie driver only).
 **sess_table_name**         ci_sessions     Any valid SQL table name    The name of the session database table (Cookie driver only).
 **sess_time_to_update**     300             Time in seconds             This options controls how often the session class will regenerate itself
-                                                                        and create a new session id.
+                                                                        and create a new session ID. Setting it to 0 will disable session
+                                                                        ID regeneartion.
 **sess_match_ip**           FALSE           TRUE/FALSE (boolean)        Whether to match the user's IP address when reading the session data.
                                                                         Note that some ISPs dynamically changes the IP, so if you want a
                                                                         non-expiring session you will likely set this to FALSE.