Drizzled Public API Documentation

quick_index_merge_select.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 #include <drizzled/session.h>
00022 #include <drizzled/records.h>
00023 #include <drizzled/util/functors.h>
00024 #include <drizzled/optimizer/quick_range_select.h>
00025 #include <drizzled/optimizer/quick_index_merge_select.h>
00026 #include <drizzled/internal/m_string.h>
00027 #include <drizzled/unique.h>
00028 #include <drizzled/key.h>
00029 #include <drizzled/table.h>
00030 #include <drizzled/system_variables.h>
00031 
00032 #include <vector>
00033 
00034 using namespace std;
00035 
00036 namespace drizzled {
00037 
00038 static int refpos_order_cmp(void *arg, const void *a, const void *b)
00039 {
00040   Cursor *cursor= (Cursor*)arg;
00041   return cursor->cmp_ref((const unsigned char *) a, (const unsigned char *) b);
00042 }
00043 
00044 optimizer::QuickIndexMergeSelect::QuickIndexMergeSelect(Session *session_param,
00045                                                         Table *table)
00046   :
00047     pk_quick_select(NULL),
00048     session(session_param)
00049 {
00050   index= MAX_KEY;
00051   head= table;
00052   memset(&read_record, 0, sizeof(read_record));
00053   alloc.init(session->variables.range_alloc_block_size);
00054 }
00055 
00056 int optimizer::QuickIndexMergeSelect::init()
00057 {
00058   return 0;
00059 }
00060 
00061 int optimizer::QuickIndexMergeSelect::reset()
00062 {
00063   return (read_keys_and_merge());
00064 }
00065 
00066 void optimizer::QuickIndexMergeSelect::push_quick_back(optimizer::QuickRangeSelect *quick_sel_range)
00067 {
00068   /*
00069     Save quick_select that does scan on clustered primary key as it will be
00070     processed separately.
00071   */
00072   if (head->cursor->primary_key_is_clustered() &&
00073       quick_sel_range->index == head->getShare()->getPrimaryKey())
00074   {
00075     pk_quick_select= quick_sel_range;
00076   }
00077   else
00078   {
00079     quick_selects.push_back(quick_sel_range);
00080   }
00081 }
00082 
00083 optimizer::QuickIndexMergeSelect::~QuickIndexMergeSelect()
00084 {
00085   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00086     it->cursor= NULL;
00087   for_each(quick_selects.begin(), quick_selects.end(), DeletePtr());
00088   quick_selects.clear();
00089   delete pk_quick_select;
00090   alloc.free_root(MYF(0));
00091 }
00092 
00093 
00094 int optimizer::QuickIndexMergeSelect::read_keys_and_merge()
00095 {
00096   vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
00097   optimizer::QuickRangeSelect *cur_quick= NULL;
00098   int result;
00099   Unique *unique= NULL;
00100   Cursor *cursor= head->cursor;
00101 
00102   cursor->extra(HA_EXTRA_KEYREAD);
00103   head->prepare_for_position();
00104 
00105   cur_quick= *it;
00106   ++it;
00107   assert(cur_quick != 0);
00108 
00109   /*
00110     We reuse the same instance of Cursor so we need to call both init and
00111     reset here.
00112   */
00113   if (cur_quick->init() || cur_quick->reset())
00114     return 0;
00115 
00116   unique= new Unique(refpos_order_cmp,
00117                      (void *) cursor,
00118                      cursor->ref_length,
00119                      session->variables.sortbuff_size);
00120   if (! unique)
00121     return 0;
00122   for (;;)
00123   {
00124     while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
00125     {
00126       cur_quick->range_end();
00127       if (it == quick_selects.end())
00128       {
00129         break;
00130       }
00131       cur_quick= *it;
00132       ++it;
00133       if (! cur_quick)
00134         break;
00135 
00136       if (cur_quick->cursor->inited != Cursor::NONE)
00137         cur_quick->cursor->endIndexScan();
00138       if (cur_quick->init() || cur_quick->reset())
00139         return 0;
00140     }
00141 
00142     if (result)
00143     {
00144       if (result != HA_ERR_END_OF_FILE)
00145       {
00146         cur_quick->range_end();
00147         return result;
00148       }
00149       break;
00150     }
00151 
00152     if (session->getKilled())
00153       return 0;
00154 
00155     /* skip row if it will be retrieved by clustered PK scan */
00156     if (pk_quick_select && pk_quick_select->row_in_ranges())
00157       continue;
00158 
00159     cur_quick->cursor->position(cur_quick->record);
00160     result= unique->unique_add((char*) cur_quick->cursor->ref);
00161     if (result)
00162       return 0;
00163 
00164   }
00165 
00166   /* ok, all row ids are in Unique */
00167   result= unique->get(head);
00168   delete unique;
00169   doing_pk_scan= false;
00170   /* index_merge currently doesn't support "using index" at all */
00171   cursor->extra(HA_EXTRA_NO_KEYREAD);
00172   /* start table scan */
00173   if ((result= read_record.init_read_record(session, head, (optimizer::SqlSelect*) 0, 1, 1)))
00174   {
00175     head->print_error(result, MYF(0));
00176     return 0;
00177   }
00178   return result;
00179 }
00180 
00181 
00182 int optimizer::QuickIndexMergeSelect::get_next()
00183 {
00184   int result;
00185 
00186   if (doing_pk_scan)
00187     return(pk_quick_select->get_next());
00188 
00189   if ((result= read_record.read_record(&read_record)) == -1)
00190   {
00191     result= HA_ERR_END_OF_FILE;
00192     read_record.end_read_record();
00193     /* All rows from Unique have been retrieved, do a clustered PK scan */
00194     if (pk_quick_select)
00195     {
00196       doing_pk_scan= true;
00197       if ((result= pk_quick_select->init()) ||
00198           (result= pk_quick_select->reset()))
00199         return result;
00200       return(pk_quick_select->get_next());
00201     }
00202   }
00203 
00204   return result;
00205 }
00206 
00207 bool optimizer::QuickIndexMergeSelect::is_keys_used(const boost::dynamic_bitset<>& fields)
00208 {
00209   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00210   {
00211     if (is_key_used(head, it->index, fields))
00212       return 1;
00213   }
00214   return 0;
00215 }
00216 
00217 
00218 void optimizer::QuickIndexMergeSelect::add_info_string(string *str)
00219 {
00220   bool first= true;
00221   str->append("sort_union(");
00222   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00223   {
00224     if (! first)
00225       str->append(",");
00226     else
00227       first= false;
00228     it->add_info_string(str);
00229   }
00230   if (pk_quick_select)
00231   {
00232     str->append(",");
00233     pk_quick_select->add_info_string(str);
00234   }
00235   str->append(")");
00236 }
00237 
00238 
00239 void optimizer::QuickIndexMergeSelect::add_keys_and_lengths(string *key_names,
00240                                                             string *used_lengths)
00241 {
00242   char buf[64];
00243   uint32_t length= 0;
00244   bool first= true;
00245 
00246   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00247   {
00248     if (first)
00249       first= false;
00250     else
00251     {
00252       key_names->append(",");
00253       used_lengths->append(",");
00254     }
00255 
00256     KeyInfo *key_info= head->key_info + it->index;
00257     key_names->append(key_info->name);
00258     length= internal::int64_t2str(it->max_used_key_length, buf, 10) - buf;
00259     used_lengths->append(buf, length);
00260   }
00261   if (pk_quick_select)
00262   {
00263     KeyInfo *key_info= head->key_info + pk_quick_select->index;
00264     key_names->append(",");
00265     key_names->append(key_info->name);
00266     length= internal::int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf;
00267     used_lengths->append(",");
00268     used_lengths->append(buf, length);
00269   }
00270 }
00271 
00272 
00273 } /* namespace drizzled */