Drizzled Public API Documentation

quick_ror_intersect_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/util/functors.h>
00023 #include <drizzled/optimizer/range.h>
00024 #include <drizzled/optimizer/quick_range_select.h>
00025 #include <drizzled/optimizer/quick_ror_intersect_select.h>
00026 #include <drizzled/internal/m_string.h>
00027 #include <drizzled/key.h>
00028 #include <drizzled/table.h>
00029 #include <drizzled/system_variables.h>
00030 
00031 #include <vector>
00032 
00033 using namespace std;
00034 
00035 namespace drizzled {
00036 
00037 optimizer::QuickRorIntersectSelect::QuickRorIntersectSelect(Session *session_param,
00038                                                             Table *table,
00039                                                             bool retrieve_full_rows,
00040                                                             memory::Root *parent_alloc)
00041   :
00042     cpk_quick(NULL),
00043     session(session_param),
00044     need_to_fetch_row(retrieve_full_rows),
00045     scans_inited(false)
00046 {
00047   index= MAX_KEY;
00048   head= table;
00049   record= head->record[0];
00050   if (! parent_alloc)
00051   {
00052     alloc.init(session->variables.range_alloc_block_size);
00053   }
00054   else
00055   {
00056     memset(&alloc, 0, sizeof(memory::Root));
00057   }
00058 
00059   last_rowid= parent_alloc
00060     ? parent_alloc->alloc(head->cursor->ref_length)
00061     : alloc.alloc(head->cursor->ref_length);
00062 }
00063 
00064 
00065 optimizer::QuickRorIntersectSelect::~QuickRorIntersectSelect()
00066 {
00067   for_each(quick_selects.begin(),
00068            quick_selects.end(),
00069            DeletePtr());
00070   quick_selects.clear();
00071   delete cpk_quick;
00072   alloc.free_root(MYF(0));
00073   if (need_to_fetch_row && head->cursor->inited != Cursor::NONE)
00074   {
00075     head->cursor->endTableScan();
00076   }
00077   return;
00078 }
00079 
00080 
00081 int optimizer::QuickRorIntersectSelect::init()
00082 {
00083  /* Check if last_rowid was successfully allocated in ctor */
00084   return (! last_rowid);
00085 }
00086 
00087 
00088 int optimizer::QuickRorIntersectSelect::init_ror_merged_scan(bool reuse_handler)
00089 {
00090   vector<optimizer::QuickRangeSelect*>::iterator it= quick_selects.begin();
00091 
00092   /* Initialize all merged "children" quick selects */
00093   assert(! need_to_fetch_row || reuse_handler);
00094   if (not need_to_fetch_row && reuse_handler)
00095   {
00096     optimizer::QuickRangeSelect *quick= *it;
00097     ++it;
00098     /*
00099       There is no use of this->cursor. Use it for the first of merged range
00100       selects.
00101     */
00102     if (quick->init_ror_merged_scan(true))
00103       return 0;
00104     quick->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
00105   }
00106   while (it != quick_selects.end())
00107   {
00108     if ((*it)->init_ror_merged_scan(false))
00109     {
00110       return 0;
00111     }
00112     (*it)->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
00113     /* All merged scans share the same record buffer in intersection. */
00114     (*it)->record= head->record[0];
00115     ++it;
00116   }
00117 
00118   if (need_to_fetch_row && head->cursor->startTableScan(1))
00119   {
00120     return 0;
00121   }
00122   return 0;
00123 }
00124 
00125 
00126 int optimizer::QuickRorIntersectSelect::reset()
00127 {
00128   if (! scans_inited && init_ror_merged_scan(true))
00129     return 0;
00130   scans_inited= true;
00131   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00132     it->reset();
00133   return 0;
00134 }
00135 
00136 
00137 void optimizer::QuickRorIntersectSelect::push_quick_back(optimizer::QuickRangeSelect *quick)
00138 {
00139   quick_selects.push_back(quick);
00140 }
00141 
00142 
00143 bool optimizer::QuickRorIntersectSelect::is_keys_used(const boost::dynamic_bitset<>& fields)
00144 {
00145   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00146   {
00147     if (is_key_used(head, it->index, fields))
00148       return 1;
00149   }
00150   return 0;
00151 }
00152 
00153 
00154 int optimizer::QuickRorIntersectSelect::get_next()
00155 {
00156   optimizer::QuickRangeSelect *quick= NULL;
00157   vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
00158   int error;
00159   int cmp;
00160   uint32_t last_rowid_count= 0;
00161 
00162   do
00163   {
00164     /* Get a rowid for first quick and save it as a 'candidate' */
00165     quick= *it;
00166     ++it;
00167     error= quick->get_next();
00168     if (cpk_quick)
00169     {
00170       while (! error && ! cpk_quick->row_in_ranges())
00171         error= quick->get_next();
00172     }
00173     if (error)
00174       return error;
00175 
00176     quick->cursor->position(quick->record);
00177     memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
00178     last_rowid_count= 1;
00179 
00180     while (last_rowid_count < quick_selects.size())
00181     {
00183       if (it != quick_selects.end())
00184       {
00185         quick= *it;
00186         ++it;
00187       }
00188       else
00189       {
00190         it= quick_selects.begin();
00191         quick= *it;
00192         ++it;
00193       }
00194 
00195       do
00196       {
00197         if ((error= quick->get_next()))
00198           return error;
00199         quick->cursor->position(quick->record);
00200         cmp= head->cursor->cmp_ref(quick->cursor->ref, last_rowid);
00201       } while (cmp < 0);
00202 
00203       /* Ok, current select 'caught up' and returned ref >= cur_ref */
00204       if (cmp > 0)
00205       {
00206         /* Found a row with ref > cur_ref. Make it a new 'candidate' */
00207         if (cpk_quick)
00208         {
00209           while (! cpk_quick->row_in_ranges())
00210           {
00211             if ((error= quick->get_next()))
00212               return error;
00213           }
00214         }
00215         memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
00216         last_rowid_count= 1;
00217       }
00218       else
00219       {
00220         /* current 'candidate' row confirmed by this select */
00221         last_rowid_count++;
00222       }
00223     }
00224 
00225     /* We get here if we got the same row ref in all scans. */
00226     if (need_to_fetch_row)
00227       error= head->cursor->rnd_pos(head->record[0], last_rowid);
00228   } while (error == HA_ERR_RECORD_DELETED);
00229   return error;
00230 }
00231 
00232 
00233 void optimizer::QuickRorIntersectSelect::add_info_string(string *str)
00234 {
00235   bool first= true;
00236   str->append("intersect(");
00237   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00238   {
00239     KeyInfo *key_info= head->key_info + it->index;
00240     if (! first)
00241       str->append(",");
00242     else
00243       first= false;
00244     str->append(key_info->name);
00245   }
00246   if (cpk_quick)
00247   {
00248     KeyInfo *key_info= head->key_info + cpk_quick->index;
00249     str->append(",");
00250     str->append(key_info->name);
00251   }
00252   str->append(")");
00253 }
00254 
00255 
00256 void optimizer::QuickRorIntersectSelect::add_keys_and_lengths(string *key_names,
00257                                                               string *used_lengths)
00258 {
00259   char buf[64];
00260   uint32_t length;
00261   bool first= true;
00262   BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
00263   {
00264     KeyInfo *key_info= head->key_info + it->index;
00265     if (first)
00266     {
00267       first= false;
00268     }
00269     else
00270     {
00271       key_names->append(",");
00272       used_lengths->append(",");
00273     }
00274     key_names->append(key_info->name);
00275     length= internal::int64_t2str(it->max_used_key_length, buf, 10) - buf;
00276     used_lengths->append(buf, length);
00277   }
00278 
00279   if (cpk_quick)
00280   {
00281     KeyInfo *key_info= head->key_info + cpk_quick->index;
00282     key_names->append(",");
00283     key_names->append(key_info->name);
00284     length= internal::int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf;
00285     used_lengths->append(",");
00286     used_lengths->append(buf, length);
00287   }
00288 }
00289 
00290 } /* namespace drizzled */