Drizzled Public API Documentation

quick_ror_union_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_union_select.h>
00026 #include <drizzled/table.h>
00027 
00028 #include <vector>
00029 #include <algorithm>
00030 
00031 using namespace std;
00032 
00033 namespace drizzled
00034 {
00035 
00036 optimizer::QuickRorUnionSelect::QuickRorUnionSelect(Session *session_param,
00037                                                     Table *table)
00038   :
00039     session(session_param),
00040     scans_inited(false)
00041 {
00042   index= MAX_KEY;
00043   head= table;
00044   rowid_length= table->cursor->ref_length;
00045   record= head->record[0];
00046   memory::init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0);
00047   session_param->mem_root= &alloc;
00048 }
00049 
00050 /*
00051  * Function object that is used as the comparison function
00052  * for the priority queue in the QuickRorUnionSelect
00053  * class.
00054  */
00055 class optimizer::compare_functor
00056 {
00057   optimizer::QuickRorUnionSelect *self;
00058   public:
00059   compare_functor(optimizer::QuickRorUnionSelect *in_arg)
00060     : self(in_arg) { }
00061   inline bool operator()(const optimizer::QuickSelectInterface *i, const optimizer::QuickSelectInterface *j) const
00062   {
00063     int val= self->head->cursor->cmp_ref(i->last_rowid,
00064                                          j->last_rowid);
00065     return (val >= 0);
00066   }
00067 };
00068 
00069 
00070 int optimizer::QuickRorUnionSelect::init()
00071 {
00072   queue=
00073     new priority_queue<optimizer::QuickSelectInterface *,
00074                        vector<optimizer::QuickSelectInterface *>,
00075                        optimizer::compare_functor >(optimizer::compare_functor(this));
00076   if (! (cur_rowid= (unsigned char*) alloc.alloc_root(2 * head->cursor->ref_length)))
00077   {
00078     return 0;
00079   }
00080   prev_rowid= cur_rowid + head->cursor->ref_length;
00081   return 0;
00082 }
00083 
00084 
00085 int optimizer::QuickRorUnionSelect::reset()
00086 {
00087   int error;
00088   have_prev_rowid= false;
00089   if (! scans_inited)
00090   {
00091     for (vector<optimizer::QuickSelectInterface *>::iterator it= quick_selects.begin();
00092          it != quick_selects.end();
00093          ++it)
00094     {
00095       if ((*it)->init_ror_merged_scan(false))
00096       {
00097         return 0;
00098       }
00099     }
00100     scans_inited= true;
00101   }
00102   while (! queue->empty())
00103   {
00104     queue->pop();
00105   }
00106   /*
00107     Initialize scans for merged quick selects and put all merged quick
00108     selects into the queue.
00109   */
00110   for (vector<optimizer::QuickSelectInterface *>::iterator it= quick_selects.begin();
00111        it != quick_selects.end();
00112        ++it)
00113   {
00114     if ((*it)->reset())
00115     {
00116       return 0;
00117     }
00118     
00119     error= (*it)->get_next();
00120     if (error)
00121     {
00122       if (error == HA_ERR_END_OF_FILE)
00123       {
00124         continue;
00125       }
00126     }
00127     (*it)->save_last_pos();
00128     queue->push(*it);
00129   }
00130 
00131   if (head->cursor->startTableScan(1))
00132   {
00133     return 0;
00134   }
00135 
00136   return 0;
00137 }
00138 
00139 
00140 bool
00141 optimizer::QuickRorUnionSelect::push_quick_back(QuickSelectInterface *quick_sel_range)
00142 {
00143   quick_selects.push_back(quick_sel_range);
00144   return false;
00145 }
00146 
00147 
00148 optimizer::QuickRorUnionSelect::~QuickRorUnionSelect()
00149 {
00150   while (! queue->empty())
00151   {
00152     queue->pop();
00153   }
00154   delete queue;
00155   for_each(quick_selects.begin(),
00156            quick_selects.end(),
00157            DeletePtr());
00158   quick_selects.clear();
00159   if (head->cursor->inited != Cursor::NONE)
00160   {
00161     head->cursor->endTableScan();
00162   }
00163   alloc.free_root(MYF(0));
00164 }
00165 
00166 
00167 bool optimizer::QuickRorUnionSelect::is_keys_used(const boost::dynamic_bitset<>& fields)
00168 {
00169   for (vector<optimizer::QuickSelectInterface *>::iterator it= quick_selects.begin();
00170        it != quick_selects.end();
00171        ++it)
00172   {
00173     if ((*it)->is_keys_used(fields))
00174     {
00175       return true;
00176     }
00177   }
00178   return false;
00179 }
00180 
00181 
00182 int optimizer::QuickRorUnionSelect::get_next()
00183 {
00184   int error;
00185   int dup_row;
00186   optimizer::QuickSelectInterface *quick= NULL;
00187   unsigned char *tmp= NULL;
00188 
00189   do
00190   {
00191     do
00192     {
00193       if (queue->empty())
00194         return HA_ERR_END_OF_FILE;
00195       /* Ok, we have a queue with >= 1 scans */
00196 
00197       quick= queue->top();
00198       memcpy(cur_rowid, quick->last_rowid, rowid_length);
00199 
00200       /* put into queue rowid from the same stream as top element */
00201       if ((error= quick->get_next()))
00202       {
00203         if (error != HA_ERR_END_OF_FILE)
00204           return(error);
00205         queue->pop();
00206       }
00207       else
00208       {
00209         quick->save_last_pos();
00210         queue->pop();
00211         queue->push(quick);
00212       }
00213 
00214       if (!have_prev_rowid)
00215       {
00216         /* No rows have been returned yet */
00217         dup_row= false;
00218         have_prev_rowid= true;
00219       }
00220       else
00221         dup_row= ! head->cursor->cmp_ref(cur_rowid, prev_rowid);
00222     } while (dup_row);
00223 
00224     tmp= cur_rowid;
00225     cur_rowid= prev_rowid;
00226     prev_rowid= tmp;
00227 
00228     error= head->cursor->rnd_pos(quick->record, prev_rowid);
00229   } while (error == HA_ERR_RECORD_DELETED);
00230   return error;
00231 }
00232 
00233 
00234 void optimizer::QuickRorUnionSelect::add_info_string(string *str)
00235 {
00236   bool first= true;
00237   str->append("union(");
00238   for (vector<optimizer::QuickSelectInterface *>::iterator it= quick_selects.begin();
00239        it != quick_selects.end();
00240        ++it)
00241   {
00242     if (! first)
00243       str->append(",");
00244     else
00245       first= false;
00246     (*it)->add_info_string(str);
00247   }
00248   str->append(")");
00249 }
00250 
00251 
00252 void optimizer::QuickRorUnionSelect::add_keys_and_lengths(string *key_names,
00253                                                           string *used_lengths)
00254 {
00255   bool first= true;
00256   for (vector<optimizer::QuickSelectInterface *>::iterator it= quick_selects.begin();
00257        it != quick_selects.end();
00258        ++it)
00259   {
00260     if (first)
00261     {
00262       first= false;
00263     }
00264     else
00265     {
00266       used_lengths->append(",");
00267       key_names->append(",");
00268     }
00269     (*it)->add_keys_and_lengths(key_names, used_lengths);
00270   }
00271 }
00272 
00273 } /* namespace drizzled */