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