diff --git a/.bzrignore b/.bzrignore
index d6d84003198dde64fef4bed3e6120f1384072870..21383779fa73682e78c527aa10a2c56cb8f70ffc 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -934,6 +934,7 @@ scripts/mysql_install_db
 scripts/mysql_secure_installation
 scripts/mysql_setpermission
 scripts/mysql_tableinfo
+scripts/mysql_upgrade
 scripts/mysql_zap
 scripts/mysqlaccess
 scripts/mysqlbug
@@ -1613,4 +1614,3 @@ vio/viotest-sslconnect.cpp
 vio/viotest.cpp
 zlib/*.ds?
 zlib/*.vcproj
-scripts/mysql_upgrade
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 806ccf9653784400ced19d3cae8c68dbd9ca7ea5..f862ee29986c4ec1e8efa7e3e8fb62edfb8b4fc9 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1023,3 +1023,10 @@ select format(d, 2) from t1;
 format(d, 2)
 NULL
 drop table t1;
+create table t1 (c varchar(40));
+insert into t1 values ('y,abc'),('y,abc');
+select c, substring_index(lcase(c), @q:=',', -1) as res from t1;
+c	res
+y,abc	abc
+y,abc	abc
+drop table t1;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 85976c211c5881632f44d6b765c61bc5b0afe203..6094d23b0d070f05bd63cbcb02371a0e4fceb48a 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -215,9 +215,9 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from
 a
 select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
 b	(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)
-8	7.5
-8	4.5
-9	7.5
+8	7.5000
+8	4.5000
+9	7.5000
 explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t4	ALL	NULL	NULL	NULL	NULL	3	
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index b9f1e36349c2c2c6e4b82f0b39ac0fc904df1ef0..0d4a0737bb91cb1744542986327012f3078bf400 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -42,7 +42,6 @@ rpl_row_basic_3innodb   : Bug #17385
 rpl_sp                  : Bug#16456
 rpl_until               : Unstable test case, bug#15886
 sp-goto                 : GOTO is currently is disabled - will be fixed in the future
-subselect               : Bug#15706 (ps mode) [PATCH PENDING]
 rpl_ndb_blob            : Bug #17505
 rpl_ndb_blob2           : Bug #17505
 rpl_ndb_log             : results are not deterministic
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index ac2bf8202572759d1f0305fc48d6a4d05fdb37a3..ef20d766bcecc4b6882a6ad24f2b1b8540f05a95 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -676,4 +676,12 @@ insert into t1 values (null);
 select format(d, 2) from t1;
 drop table t1;
 
+#
+# Bug #14676: substring_index() returns incorrect results
+#
+create table t1 (c varchar(40));
+insert into t1 values ('y,abc'),('y,abc');
+select c, substring_index(lcase(c), @q:=',', -1) as res from t1;
+drop table t1;
+
 # End of 5.0 tests
diff --git a/sql/item.cc b/sql/item.cc
index a3bfd71c010112cdabfa8a41e52016c0f09ea4ff..9f09a8fa02c7572eb534ec3fd8273c26d8ba688d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3211,6 +3211,252 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
 }
 
 
+/*
+  Resolve the name of an outer select column reference.
+
+  SYNOPSIS
+    Item_field::fix_outer_field()
+    thd        [in]      current thread
+    from_field [in/out]  found field reference or (Field*)not_found_field
+    reference  [in/out]  view column if this item was resolved to a view column
+
+  DESCRIPTION
+    The method resolves the column reference represented by 'this' as a column
+    present in outer selects that contain current select.
+
+  NOTES
+    This is the inner loop of Item_field::fix_fields:
+
+      for each outer query Q_k beginning from the inner-most one
+      {
+        search for a column or derived column named col_ref_i
+        [in table T_j] in the FROM clause of Q_k;
+
+        if such a column is not found
+          Search for a column or derived column named col_ref_i
+          [in table T_j] in the SELECT and GROUP clauses of Q_k.
+      }
+
+  IMPLEMENTATION
+    In prepared statements, because of cache, find_field_in_tables()
+    can resolve fields even if they don't belong to current context.
+    In this case this method only finds appropriate context and marks
+    current select as dependent. The found reference of field should be
+    provided in 'from_field'.
+
+  RETURN
+     1 - column succefully resolved and fix_fields() should continue.
+     0 - column fully fixed and fix_fields() should return FALSE
+    -1 - error occured
+*/
+int
+Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
+{
+  enum_parsing_place place= NO_MATTER;
+  bool field_found= (*from_field != not_found_field);
+  bool upward_lookup= FALSE;
+
+  /*
+    If there are outer contexts (outer selects, but current select is
+    not derived table or view) try to resolve this reference in the
+    outer contexts.
+
+    We treat each subselect as a separate namespace, so that different
+    subselects may contain columns with the same names. The subselects
+    are searched starting from the innermost.
+  */
+  Name_resolution_context *last_checked_context= context;
+  Item **ref= (Item **) not_found_item;
+  Name_resolution_context *outer_context= context->outer_context;
+  for (;
+       outer_context;
+       outer_context= outer_context->outer_context)
+  {
+    SELECT_LEX *select= outer_context->select_lex;
+    Item_subselect *prev_subselect_item=
+      last_checked_context->select_lex->master_unit()->item;
+    last_checked_context= outer_context;
+    upward_lookup= TRUE;
+
+    place= prev_subselect_item->parsing_place;
+    /*
+      If outer_field is set, field was already found by first call
+      to find_field_in_tables(). Only need to find appropriate context.
+    */
+    if (field_found && outer_context->select_lex !=
+        cached_table->select_lex)
+      continue;
+    /*
+      In case of a view, find_field_in_tables() writes the pointer to
+      the found view field into '*reference', in other words, it
+      substitutes this Item_field with the found expression.
+    */
+    if (field_found || (*from_field= find_field_in_tables(thd, this,
+                                          outer_context->
+                                            first_name_resolution_table,
+                                          outer_context->
+                                            last_name_resolution_table,
+                                          reference,
+                                          IGNORE_EXCEPT_NON_UNIQUE,
+                                          TRUE, TRUE)) !=
+        not_found_field)
+    {
+      if (*from_field)
+      {
+        if (*from_field != view_ref_found)
+        {
+          prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
+          prev_subselect_item->const_item_cache= 0;
+          if (thd->lex->in_sum_func &&
+              thd->lex->in_sum_func->nest_level == 
+              thd->lex->current_select->nest_level)
+          {
+            Item::Type type= (*reference)->type();
+            set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+                          select->nest_level);
+            set_field(*from_field);
+            fixed= 1;
+            mark_as_dependent(thd, last_checked_context->select_lex,
+                              context->select_lex, this,
+                              ((type == REF_ITEM || type == FIELD_ITEM) ?
+                               (Item_ident*) (*reference) : 0));
+            return 0;
+          }
+        }
+        else
+        {
+          Item::Type type= (*reference)->type();
+          prev_subselect_item->used_tables_cache|=
+            (*reference)->used_tables();
+          prev_subselect_item->const_item_cache&=
+            (*reference)->const_item();
+          mark_as_dependent(thd, last_checked_context->select_lex,
+                            context->select_lex, this,
+                            ((type == REF_ITEM || type == FIELD_ITEM) ?
+                             (Item_ident*) (*reference) :
+                             0));
+          /*
+            A reference to a view field had been found and we
+            substituted it instead of this Item (find_field_in_tables
+            does it by assigning the new value to *reference), so now
+            we can return from this function.
+          */
+          return 0;
+        }
+      }
+      break;
+    }
+
+    /* Search in SELECT and GROUP lists of the outer select. */
+    if (outer_context->resolve_in_select_list)
+    {
+      if (!(ref= resolve_ref_in_select_and_group(thd, this, select)))
+        return -1; /* Some error occurred (e.g. ambiguous names). */
+      if (ref != not_found_item)
+      {
+        DBUG_ASSERT(*ref && (*ref)->fixed);
+        prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
+        prev_subselect_item->const_item_cache&= (*ref)->const_item();
+        break;
+      }
+    }
+
+    /*
+      Reference is not found in this select => this subquery depend on
+      outer select (or we just trying to find wrong identifier, in this
+      case it does not matter which used tables bits we set)
+    */
+    prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
+    prev_subselect_item->const_item_cache= 0;
+  }
+
+  DBUG_ASSERT(ref != 0);
+  if (!*from_field)
+    return -1;
+  if (ref == not_found_item && *from_field == not_found_field)
+  {
+    if (upward_lookup)
+    {
+      // We can't say exactly what absent table or field
+      my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
+    }
+    else
+    {
+      /* Call find_field_in_tables only to report the error */
+      find_field_in_tables(thd, this,
+                           context->first_name_resolution_table,
+                           context->last_name_resolution_table,
+                           reference, REPORT_ALL_ERRORS,
+                           !any_privileges &&
+                           TRUE, TRUE);
+    }
+    return -1;
+  }
+  else if (ref != not_found_item)
+  {
+    Item *save;
+    Item_ref *rf;
+
+    /* Should have been checked in resolve_ref_in_select_and_group(). */
+    DBUG_ASSERT(*ref && (*ref)->fixed);
+    /*
+      Here, a subset of actions performed by Item_ref::set_properties
+      is not enough. So we pass ptr to NULL into Item_[direct]_ref
+      constructor, so no initialization is performed, and call 
+      fix_fields() below.
+    */
+    save= *ref;
+    *ref= NULL;                             // Don't call set_properties()
+    rf= (place == IN_HAVING ?
+         new Item_ref(context, ref, (char*) table_name,
+                      (char*) field_name) :
+         new Item_direct_ref(context, ref, (char*) table_name,
+                             (char*) field_name));
+    *ref= save;
+    if (!rf)
+      return -1;
+    thd->change_item_tree(reference, rf);
+    /*
+      rf is Item_ref => never substitute other items (in this case)
+      during fix_fields() => we can use rf after fix_fields()
+    */
+    DBUG_ASSERT(!rf->fixed);                // Assured by Item_ref()
+    if (rf->fix_fields(thd, reference) || rf->check_cols(1))
+      return -1;
+
+    mark_as_dependent(thd, last_checked_context->select_lex,
+                      context->select_lex, this,
+                      rf);
+    return 0;
+  }
+  else
+  {
+    mark_as_dependent(thd, last_checked_context->select_lex,
+                      context->select_lex,
+                      this, this);
+    if (last_checked_context->select_lex->having_fix_field)
+    {
+      Item_ref *rf;
+      rf= new Item_ref(context,
+                       (cached_table->db[0] ? cached_table->db : 0),
+                       (char*) cached_table->alias, (char*) field_name);
+      if (!rf)
+        return -1;
+      thd->change_item_tree(reference, rf);
+      /*
+        rf is Item_ref => never substitute other items (in this case)
+        during fix_fields() => we can use rf after fix_fields()
+      */
+      DBUG_ASSERT(!rf->fixed);                // Assured by Item_ref()
+      if (rf->fix_fields(thd, reference) || rf->check_cols(1))
+        return -1;
+      return 0;
+    }
+  }
+  return 1;
+}
+
+
 /*
   Resolve the name of a column reference.
 
@@ -3258,12 +3504,11 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
 
 bool Item_field::fix_fields(THD *thd, Item **reference)
 {
-  enum_parsing_place place= NO_MATTER;
   DBUG_ASSERT(fixed == 0);
   if (!field)					// If field is not checked
   {
-    bool upward_lookup= FALSE;
     Field *from_field= (Field *)not_found_field;
+    bool outer_fixed= false;
     /*
       In case of view, find_field_in_tables() write pointer to view field
       expression to 'reference', i.e. it substitute that expression instead
@@ -3278,7 +3523,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
                                           TRUE)) ==
 	not_found_field)
     {
-
+      int ret;
       /* Look up in current select's item_list to find aliased fields */
       if (thd->lex->current_select->is_item_list_lookup)
       {
@@ -3293,197 +3538,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
           return 0;
         }
       }
-
-      /*
-        If there are outer contexts (outer selects, but current select is
-        not derived table or view) try to resolve this reference in the
-        outer contexts.
-
-        We treat each subselect as a separate namespace, so that different
-        subselects may contain columns with the same names. The subselects
-        are searched starting from the innermost.
-      */
-      Name_resolution_context *last_checked_context= context;
-      Item **ref= (Item **) not_found_item;
-      Name_resolution_context *outer_context= context->outer_context;
-      for (;
-           outer_context;
-           outer_context= outer_context->outer_context)
-      {
-        SELECT_LEX *select= outer_context->select_lex;
-        Item_subselect *prev_subselect_item=
-          last_checked_context->select_lex->master_unit()->item;
-        last_checked_context= outer_context;
-        upward_lookup= TRUE;
-
-        place= prev_subselect_item->parsing_place;
-        /*
-          In case of a view, find_field_in_tables() writes the pointer to
-          the found view field into '*reference', in other words, it
-          substitutes this Item_field with the found expression.
-        */
-        if ((from_field= find_field_in_tables(thd, this,
-                                              outer_context->
-                                                first_name_resolution_table,
-                                              outer_context->
-                                                last_name_resolution_table,
-                                              reference,
-                                              IGNORE_EXCEPT_NON_UNIQUE,
-                                              TRUE, TRUE)) !=
-            not_found_field)
-        {
-          if (from_field)
-          {
-            if (from_field != view_ref_found)
-            {
-              prev_subselect_item->used_tables_cache|= from_field->table->map;
-              prev_subselect_item->const_item_cache= 0;
-              if (thd->lex->in_sum_func &&
-                  thd->lex->in_sum_func->nest_level == 
-                  thd->lex->current_select->nest_level)
-              {
-                Item::Type type= (*reference)->type();
-                set_if_bigger(thd->lex->in_sum_func->max_arg_level,
-                              select->nest_level);
-                set_field(from_field);
-                fixed= 1;
-                mark_as_dependent(thd, last_checked_context->select_lex,
-                                  context->select_lex, this,
-                                  ((type == REF_ITEM || type == FIELD_ITEM) ?
-                                   (Item_ident*) (*reference) : 0));
-                return FALSE;
-              }
-            }
-            else
-            {
-              Item::Type type= (*reference)->type();
-              prev_subselect_item->used_tables_cache|=
-                (*reference)->used_tables();
-              prev_subselect_item->const_item_cache&=
-                (*reference)->const_item();
-              mark_as_dependent(thd, last_checked_context->select_lex,
-                                context->select_lex, this,
-                                ((type == REF_ITEM || type == FIELD_ITEM) ?
-                                 (Item_ident*) (*reference) :
-                                 0));
-              /*
-                A reference to a view field had been found and we
-                substituted it instead of this Item (find_field_in_tables
-                does it by assigning the new value to *reference), so now
-                we can return from this function.
-              */
-              return FALSE;
-            }
-          }
-          break;
-        }
-
-        /* Search in SELECT and GROUP lists of the outer select. */
-        if (outer_context->resolve_in_select_list)
-        {
-          if (!(ref= resolve_ref_in_select_and_group(thd, this, select)))
-            goto error; /* Some error occurred (e.g. ambiguous names). */
-          if (ref != not_found_item)
-          {
-            DBUG_ASSERT(*ref && (*ref)->fixed);
-            prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
-	    prev_subselect_item->const_item_cache&= (*ref)->const_item();
-            break;
-          }
-        }
-
-        /*
-          Reference is not found in this select => this subquery depend on
-          outer select (or we just trying to find wrong identifier, in this
-          case it does not matter which used tables bits we set)
-        */
-        prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
-        prev_subselect_item->const_item_cache= 0;
-      }
-
-      DBUG_ASSERT(ref != 0);
-      if (!from_field)
-	goto error;
-      if (ref == not_found_item && from_field == not_found_field)
-      {
-	if (upward_lookup)
-	{
-          // We can't say exactly what absent table or field
-	  my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
-	}
-	else
-	{
-          /* Call find_field_in_tables only to report the error */
-	  find_field_in_tables(thd, this,
-                               context->first_name_resolution_table,
-                               context->last_name_resolution_table,
-                               reference, REPORT_ALL_ERRORS,
-                               !any_privileges &&
-                               TRUE, TRUE);
-	}
-	goto error;
-      }
-      else if (ref != not_found_item)
-      {
-        Item *save;
-        Item_ref *rf;
-
-        /* Should have been checked in resolve_ref_in_select_and_group(). */
-        DBUG_ASSERT(*ref && (*ref)->fixed);
-        /*
-          Here, a subset of actions performed by Item_ref::set_properties
-          is not enough. So we pass ptr to NULL into Item_[direct]_ref
-          constructor, so no initialization is performed, and call 
-          fix_fields() below.
-        */
-        save= *ref;
-        *ref= NULL;                             // Don't call set_properties()
-        rf= (place == IN_HAVING ?
-             new Item_ref(context, ref, (char*) table_name,
-                          (char*) field_name) :
-             new Item_direct_ref(context, ref, (char*) table_name,
-                                 (char*) field_name));
-        *ref= save;
-	if (!rf)
-	  goto error;
-        thd->change_item_tree(reference, rf);
-	/*
-	  rf is Item_ref => never substitute other items (in this case)
-	  during fix_fields() => we can use rf after fix_fields()
-	*/
-        DBUG_ASSERT(!rf->fixed);                // Assured by Item_ref()
-        if (rf->fix_fields(thd, reference) || rf->check_cols(1))
-	  goto error;
-
-	mark_as_dependent(thd, last_checked_context->select_lex,
-                          context->select_lex, this,
-                          rf);
-	return FALSE;
-      }
-      else
-      {
-	mark_as_dependent(thd, last_checked_context->select_lex,
-                          context->select_lex,
-                          this, this);
-	if (last_checked_context->select_lex->having_fix_field)
-	{
-	  Item_ref *rf;
-          rf= new Item_ref(context,
-                           (cached_table->db[0] ? cached_table->db : 0),
-                           (char*) cached_table->alias, (char*) field_name);
-	  if (!rf)
-	    goto error;
-          thd->change_item_tree(reference, rf);
-	  /*
-	    rf is Item_ref => never substitute other items (in this case)
-	    during fix_fields() => we can use rf after fix_fields()
-	  */
-          DBUG_ASSERT(!rf->fixed);                // Assured by Item_ref()
-          if (rf->fix_fields(thd, reference) || rf->check_cols(1))
-            goto error;
-          return FALSE;
-	}
-      }
+      if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
+        goto error;
+      else if (!ret)
+        return FALSE;
+      outer_fixed= TRUE;
     }
     else if (!from_field)
       goto error;
@@ -3503,6 +3562,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
     if (from_field == view_ref_found)
       return FALSE;
 
+    if (!outer_fixed && cached_table && cached_table->select_lex &&
+          context->select_lex &&
+          cached_table->select_lex != context->select_lex)
+    {
+      int ret;
+      if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
+        goto error;
+      else if (!ret)
+        return FALSE;
+    }
+
     set_field(from_field);
     if (thd->lex->in_sum_func &&
         thd->lex->in_sum_func->nest_level == 
@@ -4655,6 +4725,25 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
           }
           if (from_field != not_found_field)
           {
+            if (cached_table && cached_table->select_lex &&
+                outer_context->select_lex &&
+                cached_table->select_lex != outer_context->select_lex)
+            {
+              /*
+                Due to cache, find_field_in_tables() can return field which
+                doesn't belong to provided outer_context. In this case we have
+                to find proper field context in order to fix field correcly.
+              */
+              do
+              {
+                outer_context= outer_context->outer_context;
+                select= outer_context->select_lex;
+                prev_subselect_item=
+                  last_checked_context->select_lex->master_unit()->item;
+                last_checked_context= outer_context;
+              } while (outer_context && outer_context->select_lex &&
+                       cached_table->select_lex != outer_context->select_lex);
+            }
             prev_subselect_item->used_tables_cache|= from_field->table->map;
             prev_subselect_item->const_item_cache= 0;
             break;
diff --git a/sql/item.h b/sql/item.h
index 030b2c40b4a0e7432a2670c460a83c3b7e8b4460..ae6aaeb82f09beea2d51a2efda0d7d13786dd69c 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1205,6 +1205,7 @@ public:
   inline uint32 max_disp_length() { return field->max_length(); }
   Item_field *filed_for_view_update() { return this; }
   Item *safe_charset_converter(CHARSET_INFO *tocs);
+  int fix_outer_field(THD *thd, Field **field, Item **reference);
   friend class Item_default_value;
   friend class Item_insert_value;
   friend class st_select_lex_unit;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fe02e7c5b49121f50e54398ccece79365c613f49..a3e47154bc3f037691e0884e05ed161ee4abd3bc 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1128,9 +1128,9 @@ void Item_func_substr_index::fix_length_and_dec()
 String *Item_func_substr_index::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
-  String *res =args[0]->val_str(str);
-  String *delimeter =args[1]->val_str(&tmp_value);
-  int32 count = (int32) args[2]->val_int();
+  String *res= args[0]->val_str(str);
+  String *delimiter= args[1]->val_str(&tmp_value);
+  int32 count= (int32) args[2]->val_int();
   uint offset;
 
   if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
@@ -1139,8 +1139,8 @@ String *Item_func_substr_index::val_str(String *str)
     return 0;
   }
   null_value=0;
-  uint delimeter_length=delimeter->length();
-  if (!res->length() || !delimeter_length || !count)
+  uint delimiter_length= delimiter->length();
+  if (!res->length() || !delimiter_length || !count)
     return &my_empty_string;		// Wrong parameters
 
   res->set_charset(collation.collation);
@@ -1148,11 +1148,11 @@ String *Item_func_substr_index::val_str(String *str)
 #ifdef USE_MB
   if (use_mb(res->charset()))
   {
-    const char *ptr=res->ptr();
-    const char *strend = ptr+res->length();
-    const char *end=strend-delimeter_length+1;
-    const char *search=delimeter->ptr();
-    const char *search_end=search+delimeter_length;
+    const char *ptr= res->ptr();
+    const char *strend= ptr+res->length();
+    const char *end= strend-delimiter_length+1;
+    const char *search= delimiter->ptr();
+    const char *search_end= search+delimiter_length;
     int32 n=0,c=count,pass;
     register uint32 l;
     for (pass=(count>0);pass<2;++pass)
@@ -1167,7 +1167,7 @@ String *Item_func_substr_index::val_str(String *str)
 	    if (*i++ != *j++) goto skip;
 	  if (pass==0) ++n;
 	  else if (!--c) break;
-	  ptr+=delimeter_length;
+	  ptr+= delimiter_length;
 	  continue;
 	}
     skip:
@@ -1189,7 +1189,7 @@ String *Item_func_substr_index::val_str(String *str)
         }
         else /* return right part */
         {
-	  ptr+=delimeter_length;
+	  ptr+= delimiter_length;
 	  tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr));
         }
       }
@@ -1200,9 +1200,9 @@ String *Item_func_substr_index::val_str(String *str)
   {
     if (count > 0)
     {					// start counting from the beginning
-      for (offset=0 ;; offset+=delimeter_length)
+      for (offset=0; ; offset+= delimiter_length)
       {
-	if ((int) (offset=res->strstr(*delimeter,offset)) < 0)
+	if ((int) (offset= res->strstr(*delimiter, offset)) < 0)
 	  return res;			// Didn't find, return org string
 	if (!--count)
 	{
@@ -1223,7 +1223,7 @@ String *Item_func_substr_index::val_str(String *str)
           address space less than where the found substring is located
           in res
         */
-	if ((int) (offset=res->strrstr(*delimeter,offset)) < 0)
+	if ((int) (offset= res->strrstr(*delimiter, offset)) < 0)
 	  return res;			// Didn't find, return org string
         /*
           At this point, we've searched for the substring
@@ -1231,13 +1231,19 @@ String *Item_func_substr_index::val_str(String *str)
         */
 	if (!++count)
 	{
-	  offset+=delimeter_length;
+	  offset+= delimiter_length;
 	  tmp_value.set(*res,offset,res->length()- offset);
 	  break;
 	}
       }
     }
   }
+  /*
+    We always mark tmp_value as const so that if val_str() is called again
+    on this object, we don't disrupt the contents of tmp_value when it was
+    derived from another String.
+  */
+  tmp_value.mark_as_const();
   return (&tmp_value);
 }
 
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index f1c99f744985d2bee67a427e503be0d60b7d312c..a4dac5bda876e74d5dde581c248e91c1ab75347f 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -125,6 +125,7 @@ public:
   friend class select_subselect;
   friend class Item_in_optimizer;
   friend bool Item_field::fix_fields(THD *, Item **);
+  friend int  Item_field::fix_outer_field(THD *, Field **, Item **);
   friend bool Item_ref::fix_fields(THD *, Item **);
   friend void mark_select_range_as_dependent(THD*,
                                              st_select_lex*, st_select_lex*,