diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index acf69fdd09840e5603a81d83d687ff47b8a53001..e67a9881bba372bed32b1029748923a0ec836655 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -725,7 +725,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
   key_part_info= head->key_info[index].key_part;
   my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16);
 
-  /* 'thd' is not accessible in QUICK_RANGE_SELECT::get_next_init(). */
+  /* 'thd' is not accessible in QUICK_RANGE_SELECT::reset(). */
   multi_range_bufsiz= thd->variables.read_rnd_buff_size;
   multi_range_count= thd->variables.multi_range_count;
   multi_range_length= 0;
@@ -749,9 +749,6 @@ int QUICK_RANGE_SELECT::init()
 {
   DBUG_ENTER("QUICK_RANGE_SELECT::init");
 
-  if ((error= get_next_init()))
-    DBUG_RETURN(error);
-
   if (file->inited == handler::NONE)
     DBUG_RETURN(error= file->ha_index_init(index));
   error= 0;
@@ -5655,9 +5652,8 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
     We reuse the same instance of handler so we need to call both init and 
     reset here.
   */
-  if (cur_quick->init())
+  if (cur_quick->init() || cur_quick->reset())
     DBUG_RETURN(1);
-  cur_quick->reset();
 
   unique= new Unique(refpos_order_cmp, (void *)head->file,
                      head->file->ref_length,
@@ -5675,10 +5671,8 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
 
       if (cur_quick->file->inited != handler::NONE) 
         cur_quick->file->ha_index_end();
-      if (cur_quick->init())
+      if (cur_quick->init() || cur_quick->reset())
         DBUG_RETURN(1);
-      /* QUICK_RANGE_SELECT::reset never fails */
-      cur_quick->reset();
     }
 
     if (result)
@@ -5745,9 +5739,8 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
     if (pk_quick_select)
     {
       doing_pk_scan= TRUE;
-      if ((result= pk_quick_select->init()))
+      if ((result= pk_quick_select->init()) || (result= pk_quick_select->reset()))
         DBUG_RETURN(result);
-      pk_quick_select->reset();
       DBUG_RETURN(pk_quick_select->get_next());
     }
   }
@@ -5908,28 +5901,15 @@ int QUICK_ROR_UNION_SELECT::get_next()
   DBUG_RETURN(error);
 }
 
-
-/*
-  Initialize data structures needed by get_next().
-
-  SYNOPSIS
-    QUICK_RANGE_SELECT::get_next_init()
-
-  DESCRIPTION
-    This is called from get_next() at its first call for an object.
-    It allocates memory buffers and sets size variables.
-
-  RETURN
-    0           OK.
-    != 0        Error.
-*/
-
-int QUICK_RANGE_SELECT::get_next_init(void)
+int QUICK_RANGE_SELECT::reset()
 {
   uint  mrange_bufsiz;
   byte  *mrange_buff;
-  DBUG_ENTER("QUICK_RANGE_SELECT::get_next_init");
-
+  DBUG_ENTER("QUICK_RANGE_SELECT::reset");
+  next=0;
+  range= NULL;
+  cur_range= (QUICK_RANGE**) ranges.buffer;
+  
   /* Do not allocate the buffers twice. */
   if (multi_range_length)
   {
@@ -5937,15 +5917,8 @@ int QUICK_RANGE_SELECT::get_next_init(void)
     DBUG_RETURN(0);
   }
 
-  /* If the ranges are not yet initialized, wait for the next call. */
-  if (! ranges.elements)
-  {
-    DBUG_RETURN(0);
-  }
-
-  /*
-    Allocate the ranges array.
-  */
+  /* Allocate the ranges array. */
+  DBUG_ASSERT(ranges.elements);
   multi_range_length= min(multi_range_count, ranges.elements);
   DBUG_ASSERT(multi_range_length > 0);
   while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*)
@@ -5962,9 +5935,7 @@ int QUICK_RANGE_SELECT::get_next_init(void)
     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
   }
 
-  /*
-    Allocate the handler buffer if necessary.
-  */
+  /* Allocate the handler buffer if necessary.  */
   if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
   {
     mrange_bufsiz= min(multi_range_bufsiz,
@@ -5992,9 +5963,6 @@ int QUICK_RANGE_SELECT::get_next_init(void)
     multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz;
     multi_range_buff->end_of_used_area= mrange_buff;
   }
-
-  /* Initialize the current QUICK_RANGE pointer. */
-  cur_range= (QUICK_RANGE**) ranges.buffer;
   DBUG_RETURN(0);
 }
 
@@ -7948,10 +7916,10 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
   file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
   result= file->ha_index_init(index);
   result= file->index_last(record);
-  if (quick_prefix_select)
-    quick_prefix_select->reset();
   if (result)
     DBUG_RETURN(result);
+  if (quick_prefix_select && quick_prefix_select->reset())
+    DBUG_RETURN(1);
   /* Save the prefix of the last group. */
   key_copy(last_prefix, record, index_info, group_prefix_len);
 
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 71981dfb5c741ba9363e2e903bb3f811ae92c9ca..97d646cedbe2d95350b6dae59c2713c6dc16451a 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -59,6 +59,44 @@ class QUICK_RANGE :public Sql_alloc {
 /*
   Quick select interface.
   This class is a parent for all QUICK_*_SELECT and FT_SELECT classes.
+  
+  The usage scenario is as follows:
+  1. Create quick select
+    quick= new QUICK_XXX_SELECT(...);
+    
+  2. Perform lightweight initialization. This can be done in 2 ways:
+  2.a: Regular initialization
+    if (quick->init())
+    {
+      //the only valid action after failed init() call is delete
+      delete quick;
+    }
+  2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT
+    if (quick->init_ror_merged_scan())
+      delete quick;
+        
+  3. Perform zero, one, or more scans.
+    while (...)
+    {
+      // initialize quick select for scan. This may allocate
+      // buffers and/or prefetch rows. 
+      if (quick->reset())
+      {
+        //the only valid action after failed reset() call is delete
+        delete quick;
+        //abort query
+      }
+      
+      // perform the scan
+      do
+      {
+        res= quick->get_next();
+      } while (res && ...)
+    }
+    
+  4. Delete the select:
+    delete quick;
+  
 */
 
 class QUICK_SELECT_I
@@ -117,27 +155,16 @@ public:
     reset() should be called when it is certain that row retrieval will be
     necessary. This call may do heavyweight initialization like buffering first
     N records etc. If reset() call fails get_next() must not be called.
-    Note that reset() may be called several times if this quick select 
-    executes in a subselect.
+    Note that reset() may be called several times if 
+     * the quick select is executed in a subselect
+     * a JOIN buffer is used
+    
     RETURN
       0      OK
       other  Error code
   */
   virtual int  reset(void) = 0;
 
-  /*
-    Initialize get_next() for row retrieval.
-    SYNOPSIS
-      get_next_init()
-
-    get_next_init() must be called before the first get_next().
-    If get_next_init() call fails get_next() must not be called.
-
-    RETURN
-      0      OK
-      other  Error code
-  */
-  virtual int  get_next_init() { return false; }
   virtual int  get_next() = 0;   /* get next record to retrieve */
 
   /* Range end should be called when we have looped over the whole index */
@@ -284,18 +311,7 @@ public:
   ~QUICK_RANGE_SELECT();
 
   int init();
-  int reset(void)
-  {
-    next=0;
-    range= NULL;
-    cur_range= (QUICK_RANGE**) ranges.buffer;
-    /*
-      Note: in opt_range.cc there are places where it is assumed that this
-      function always succeeds 
-    */
-    return 0;
-  }
-  int get_next_init(void);
+  int reset(void);
   int get_next();
   void range_end();
   int get_next_prefix(uint prefix_length, byte *cur_prefix);
@@ -310,6 +326,8 @@ public:
 #ifndef DBUG_OFF
   void dbug_dump(int indent, bool verbose);
 #endif
+private:
+  /* Used only by QUICK_SELECT_DESC */
   QUICK_RANGE_SELECT(const QUICK_RANGE_SELECT& org) : QUICK_SELECT_I()
   {
     bcopy(&org, this, sizeof(*this));
@@ -685,6 +703,7 @@ public:
       QUICK_RANGE_SELECT (thd, table, key, 1) { init(); }
   ~FT_SELECT() { file->ft_end(); }
   int init() { return error=file->ft_init(); }
+  int reset() { return 0; }
   int get_next() { return error=file->ft_read(record); }
   int get_type() { return QS_TYPE_FULLTEXT; }
 };
diff --git a/sql/records.cc b/sql/records.cc
index 9a506cadf0c9115f222606eda8333b9deec0ccf5..00da1ac1adc74ef7b6daf91d311097596fc5dc3c 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -100,19 +100,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
   }
   else if (select && select->quick)
   {
-    int error;
     DBUG_PRINT("info",("using rr_quick"));
-
-    if (!table->file->inited)
-      table->file->ha_index_init(select->quick->index);
     info->read_record=rr_quick;
-
-    if ((error= select->quick->get_next_init()))
-    {
-      /* Cannot return error code here. Instead print to error log. */
-      table->file->print_error(error,MYF(ME_NOREFRESH));
-      thd->fatal_error();
-    }
   }
   else if (table->sort.record_pointers)
   {