=== modified file 'mysql-test/r/innodb_ext_key.result'
--- mysql-test/r/innodb_ext_key.result	2014-03-05 22:20:10 +0000
+++ mysql-test/r/innodb_ext_key.result	2014-07-23 20:41:34 +0000
@@ -1002,7 +1002,7 @@ insert into t2 (b) values (null), (null)
 set optimizer_switch='extended_keys=on';
 explain select a from t1 where b is null order by a desc limit 2;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t1	ref	b	b	9	const	2	Using where; Using filesort
+1	SIMPLE	t1	index	b	PRIMARY	8	NULL	3	Using where
 select a from t1 where b is null order by a desc limit 2;
 a
 3

=== modified file 'sql/opt_range.cc'
--- sql/opt_range.cc	2014-06-05 22:07:27 +0000
+++ sql/opt_range.cc	2014-07-23 20:46:54 +0000
@@ -888,6 +888,8 @@ class PARAM : public RANGE_OPT_PARAM
   /* Number of ranges in the last checked tree->key */
   uint n_ranges;
   uint8 first_null_comp; /* first null component if any, 0 - otherwise */
+
+  key_map keys_to_make_select_from;
 };
 
 
@@ -2939,6 +2941,7 @@ static int fill_used_fields_bitmap(PARAM
 */
 
 int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
+                                  key_map keys_to_make_select_from,
 				  table_map prev_tables,
 				  ha_rows limit, bool force_quick_range, 
                                   bool ordered_output)
@@ -2974,6 +2977,8 @@ int SQL_SELECT::test_quick_select(THD *t
   DBUG_PRINT("info",("Time to scan table: %g", read_time));
 
   keys_to_use.intersect(head->keys_in_use_for_query);
+  keys_to_make_select_from.intersect(head->keys_in_use_for_query);
+
   if (!keys_to_use.is_clear_all())
   {
     uchar buff[STACK_BUFF_ALLOC];
@@ -3002,6 +3007,7 @@ int SQL_SELECT::test_quick_select(THD *t
     param.remove_jump_scans= TRUE;
     param.force_default_mrr= ordered_output;
     param.possible_keys.clear_all();
+    param.keys_to_make_select_from= keys_to_make_select_from;
 
     thd->no_errors=1;				// Don't warn about NULL
     init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0,
@@ -3120,7 +3126,8 @@ int SQL_SELECT::test_quick_select(THD *t
       remove_nonrange_trees(&param, tree);
 
       /* Get best 'range' plan and prepare data for making other plans */
-      if ((range_trp= get_key_scans_params(&param, tree, FALSE, TRUE,
+      if ((range_trp= get_key_scans_params(&param, tree,
+                                           FALSE, TRUE,
                                            best_read_time)))
       {
         best_trp= range_trp;
@@ -7233,6 +7240,8 @@ static TRP_RANGE *get_key_scans_params(P
       if ((*key)->type == SEL_ARG::MAYBE_KEY ||
           (*key)->maybe_flag)
         param->needed_reg->set_bit(keynr);
+      if (!param->keys_to_make_select_from.is_set(keynr))
+        continue;
 
       bool read_index_only= index_read_must_be_used ? TRUE :
                             (bool) param->table->covering_keys.is_set(keynr);
@@ -10610,6 +10619,7 @@ ha_rows check_quick_select(PARAM *param,
       param->table->quick_condition_rows=
         MY_MIN(param->table->quick_condition_rows, rows);
       param->table->quick_rows[keynr]= rows;
+      param->table->quick_costs[keynr]= cost->total_cost();
     }
   }
   /* Figure out if the key scan is ROR (returns rows in ROWID order) or not */

=== modified file 'sql/opt_range.h'
--- sql/opt_range.h	2014-02-19 10:05:15 +0000
+++ sql/opt_range.h	2014-07-23 20:46:22 +0000
@@ -994,7 +994,7 @@ class SQL_SELECT :public Sql_alloc {
   {
     key_map tmp;
     tmp.set_all();
-    return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0;
+    return test_quick_select(thd, tmp, tmp, 0, limit, force_quick_range, FALSE) < 0;
   }
   /* 
     RETURN
@@ -1009,7 +1009,9 @@ class SQL_SELECT :public Sql_alloc {
       rc= -1;
     return rc;
   }
-  int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
+  int test_quick_select(THD *thd, key_map keys, 
+                        key_map keys_to_make_select_from,
+                        table_map prev_tables,
 			ha_rows limit, bool force_quick_range, 
                         bool ordered_output);
 };

=== modified file 'sql/sql_select.cc'
--- sql/sql_select.cc	2014-06-09 18:18:53 +0000
+++ sql/sql_select.cc	2014-07-24 11:25:53 +0000
@@ -66,6 +66,7 @@ const char *join_type_str[]={ "UNKNOWN",
                               "hash_index", "hash_index_merge" };
 
 struct st_sargable_param;
+FILE *out1;
 
 static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
 static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves, 
@@ -3337,7 +3338,7 @@ static ha_rows get_quick_record_count(TH
   {
     select->head=table;
     table->reginfo.impossible_range=0;
-    if ((error= select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,
+    if ((error= select->test_quick_select(thd, *(key_map *)keys,*(key_map *)keys,(table_map) 0,
                                           limit, 0, FALSE)) == 1)
       DBUG_RETURN(select->quick->records);
     if (error == -1)
@@ -9620,7 +9621,7 @@ make_join_select(JOIN *join,SQL_SELECT *
 	    if (sel->cond && !sel->cond->fixed)
 	      sel->cond->quick_fix_field();
 
-	    if (sel->test_quick_select(thd, tab->keys,
+	    if (sel->test_quick_select(thd, tab->keys, tab->keys,
 				       ((used_tables & ~ current_map) |
                                         OUTER_REF_TABLE_BIT),
 				       (join->select_options &
@@ -9635,7 +9636,7 @@ make_join_select(JOIN *join,SQL_SELECT *
 	      */
               sel->cond=orig_cond;
               if (!*tab->on_expr_ref ||
-                  sel->test_quick_select(thd, tab->keys,
+                  sel->test_quick_select(thd, tab->keys, tab->keys,
                                          used_tables & ~ current_map,
                                          (join->select_options &
                                           OPTION_FOUND_ROWS ?
@@ -18458,7 +18459,7 @@ test_if_quick_select(JOIN_TAB *tab)
 
   delete tab->select->quick;
   tab->select->quick=0;
-  return tab->select->test_quick_select(tab->join->thd, tab->keys,
+  return tab->select->test_quick_select(tab->join->thd, tab->keys, tab->keys,
 					(table_map) 0, HA_POS_ERROR, 0,
                                         FALSE);
 }
@@ -20128,7 +20129,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
           save_cond= select->cond;
           if (select->pre_idx_push_select_cond)
             select->cond= select->pre_idx_push_select_cond;
-          res= select->test_quick_select(tab->join->thd, new_ref_key_map, 0,
+          key_map keys_for_analysis;
+          if (tab)
+            keys_for_analysis= tab->const_keys;
+          else
+            keys_for_analysis= table->quick_keys; //TODO where are the original
+          res= select->test_quick_select(tab->join->thd, 
+                                         keys_for_analysis, new_ref_key_map, 0,
                                          (tab->join->select_options &
                                           OPTION_FOUND_ROWS) ?
                                          HA_POS_ERROR :
@@ -20180,14 +20187,21 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
          !(table->file->index_flags(best_key, 0, 1) & HA_CLUSTERED_INDEX)))
       goto use_filesort;
 
-    if (select &&
+    if (select && // psergey:  why doesn't this use a quick?
         table->quick_keys.is_set(best_key) && best_key != ref_key)
     {
       key_map map;
       map.clear_all();       // Force the creation of quick select
       map.set_bit(best_key); // only best_key.
       select->quick= 0;
-      select->test_quick_select(join->thd, map, 0,
+      key_map keys_for_analysis;
+      if (tab)
+        keys_for_analysis= tab->const_keys;
+      else
+        keys_for_analysis= table->quick_keys; //TODO where are the original
+      keys_for_analysis.set_bit(best_key);
+
+      select->test_quick_select(join->thd, keys_for_analysis, map, 0,
                                 join->select_options & OPTION_FOUND_ROWS ?
                                 HA_POS_ERROR :
                                 join->unit->select_limit_cnt,
@@ -24522,14 +24536,11 @@ JOIN::reoptimize(Item *added_where, tabl
   if (sort_and_filter_keyuse(thd, &keyuse, true))
     return REOPT_ERROR;
   optimize_keyuse(this, &keyuse);
-
   if (optimize_semijoin_nests(this, join_tables))
     return REOPT_ERROR;
-
   /* Re-run the join optimizer to compute a new query plan. */
   if (choose_plan(this, join_tables))
     return REOPT_ERROR;
-
   return REOPT_NEW_PLAN;
 }
 
@@ -24570,6 +24581,109 @@ void JOIN::cache_const_exprs()
 }
 
 
+/*
+  Get a cost of reading rows_limit rows through index keynr.
+
+  @detail
+   - If there is a quick select, we try to use it.
+   - if there is a ref(const) access, we try to use it, too.
+   - quick and ref(const) use different cost formulas, so if both are possible
+      we should make a cost-based choice.
+
+  @return 
+    true   There was a possible quick or ref access, its cost is in the OUT
+           parameters.
+    false  No quick or ref(const) possible (and so, the caller will attempt 
+           to use a full index scan on this index).
+*/
+
+static bool get_range_limit_read_cost(const JOIN_TAB *tab, 
+                                      const TABLE *table, 
+                                      uint keynr, 
+                                      ha_rows rows_limit,
+                                      double *read_time)
+{
+  bool res= false;
+  /* 
+    We need to adjust the estimates if we had a quick select (or ref(const)) on
+    index keynr.
+  */
+  if (table->quick_keys.is_set(keynr))
+  {
+    /*
+      Start from quick select's rows and cost. These are always cheaper than
+      full index scan/cost.
+    */
+    double best_rows= table->quick_rows[keynr];
+    double best_cost= table->quick_costs[keynr];
+    
+    /*
+      Check if ref(const) access was possible on this index. 
+    */
+    if (tab)
+    {
+      key_part_map const_parts= 0;
+      key_part_map map= 1;
+      uint kp;
+      /* Find how many key parts would be used by ref(const) */
+      for (kp=0; kp < MAX_REF_PARTS; map=map << 1, kp++)
+      {
+        if (!(table->const_key_parts[keynr] & map))
+          break;
+        const_parts |= map;
+      }
+      
+      if (kp > 0)
+      {
+        ha_rows ref_rows;
+        /*
+          Two possible cases:
+          1. ref(const) uses the same #key parts as range access. 
+          2. ref(const) uses fewer key parts, becasue there is a
+            range_cond(key_part+1).
+        */
+        if (kp == table->quick_key_parts[keynr])
+          ref_rows= table->quick_rows[keynr];
+        else
+          ref_rows= table->key_info[keynr].actual_rec_per_key(kp-1);
+
+        if (ref_rows > 0)
+        {
+          double tmp= ref_rows;
+          /* Reuse the cost formula from best_access_path: */
+          set_if_smaller(tmp, (double) tab->join->thd->variables.max_seeks_for_key);
+          if (table->covering_keys.is_set(keynr))
+            tmp= table->file->keyread_time(keynr, 1, (ha_rows) tmp);
+          else
+            tmp= table->file->read_time(keynr, 1,
+                                        (ha_rows) MY_MIN(tmp,tab->worst_seeks));
+          if (tmp < best_cost)
+          {
+            best_cost= tmp;
+            best_rows= ref_rows;
+          }
+        }
+      }
+    }
+ 
+    if (best_rows > rows_limit)
+    {
+      /*
+        LIMIT clause specifies that we will need to read fewer records than
+        quick select will return. Assume that quick select's cost is
+        proportional to the number of records we need to return (e.g. if we 
+        only need 1/3rd of records, it will cost us 1/3rd of quick select's
+        read time)
+      */
+      best_cost *= rows_limit / best_rows;
+    }
+    *read_time= best_cost;
+    res= true;
+  }
+  return res;
+}
+
+
 /**
   Find a cheaper access key than a given @a key
 
@@ -24662,6 +24776,11 @@ test_if_cheaper_ordering(const JOIN_TAB
   }
   else
     read_time= table->file->scan_time();
+  
+  /*
+    TODO: add cost of sorting here.
+  */
+  read_time += COST_EPS;
 
   /*
     Calculate the selectivity of the ref_key for REF_ACCESS. For
@@ -24821,6 +24940,14 @@ test_if_cheaper_ordering(const JOIN_TAB
         */
         index_scan_time= select_limit/rec_per_key *
                          MY_MIN(rec_per_key, table->file->scan_time());
+        double range_scan_time;
+        if (get_range_limit_read_cost(tab, table, nr, select_limit, 
+                                       &range_scan_time))
+        {
+          if (range_scan_time < index_scan_time)
+            index_scan_time= range_scan_time;
+        }
+
         if ((ref_key < 0 && (group || table->force_index || is_covering)) ||
             index_scan_time < read_time)
         {

=== modified file 'sql/table.h'
--- sql/table.h	2014-06-05 22:07:27 +0000
+++ sql/table.h	2014-07-23 20:41:34 +0000
@@ -1113,6 +1113,7 @@ struct TABLE
     and max #key parts that range access would use.
   */
   ha_rows	quick_rows[MAX_KEY];
+  double 	quick_costs[MAX_KEY];
 
   /* 
     Bitmaps of key parts that =const for the duration of join execution. If

