Drizzled Public API Documentation

quick_ror_intersect_select.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008-2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 #include <drizzled/session.h>
22 #include <drizzled/util/functors.h>
23 #include <drizzled/optimizer/range.h>
24 #include <drizzled/optimizer/quick_range_select.h>
25 #include <drizzled/optimizer/quick_ror_intersect_select.h>
26 #include <drizzled/internal/m_string.h>
27 #include <drizzled/key.h>
28 #include <drizzled/table.h>
29 #include <drizzled/system_variables.h>
30 
31 #include <vector>
32 
33 using namespace std;
34 
35 namespace drizzled {
36 
37 optimizer::QuickRorIntersectSelect::QuickRorIntersectSelect(Session *session_param,
38  Table *table,
39  bool retrieve_full_rows,
40  memory::Root *parent_alloc)
41  :
42  cpk_quick(NULL),
43  session(session_param),
44  need_to_fetch_row(retrieve_full_rows),
45  scans_inited(false)
46 {
47  index= MAX_KEY;
48  head= table;
49  record= head->record[0];
50  if (! parent_alloc)
51  {
52  alloc.init(session->variables.range_alloc_block_size);
53  }
54  else
55  {
56  memset(&alloc, 0, sizeof(memory::Root));
57  }
58 
59  last_rowid= parent_alloc
60  ? parent_alloc->alloc(head->cursor->ref_length)
61  : alloc.alloc(head->cursor->ref_length);
62 }
63 
64 
65 optimizer::QuickRorIntersectSelect::~QuickRorIntersectSelect()
66 {
67  for_each(quick_selects.begin(),
68  quick_selects.end(),
69  DeletePtr());
70  quick_selects.clear();
71  delete cpk_quick;
72  alloc.free_root(MYF(0));
73  if (need_to_fetch_row && head->cursor->inited != Cursor::NONE)
74  {
75  head->cursor->endTableScan();
76  }
77  return;
78 }
79 
80 
82 {
83  /* Check if last_rowid was successfully allocated in ctor */
84  return (! last_rowid);
85 }
86 
87 
89 {
90  vector<optimizer::QuickRangeSelect*>::iterator it= quick_selects.begin();
91 
92  /* Initialize all merged "children" quick selects */
93  assert(! need_to_fetch_row || reuse_handler);
94  if (not need_to_fetch_row && reuse_handler)
95  {
96  optimizer::QuickRangeSelect *quick= *it;
97  ++it;
98  /*
99  There is no use of this->cursor. Use it for the first of merged range
100  selects.
101  */
102  if (quick->init_ror_merged_scan(true))
103  return 0;
104  quick->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
105  }
106  while (it != quick_selects.end())
107  {
108  if ((*it)->init_ror_merged_scan(false))
109  {
110  return 0;
111  }
112  (*it)->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
113  /* All merged scans share the same record buffer in intersection. */
114  (*it)->record= head->record[0];
115  ++it;
116  }
117 
118  if (need_to_fetch_row && head->cursor->startTableScan(1))
119  {
120  return 0;
121  }
122  return 0;
123 }
124 
125 
127 {
128  if (! scans_inited && init_ror_merged_scan(true))
129  return 0;
130  scans_inited= true;
131  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
132  it->reset();
133  return 0;
134 }
135 
136 
138 {
139  quick_selects.push_back(quick);
140 }
141 
142 
143 bool optimizer::QuickRorIntersectSelect::is_keys_used(const boost::dynamic_bitset<>& fields)
144 {
145  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
146  {
147  if (is_key_used(head, it->index, fields))
148  return 1;
149  }
150  return 0;
151 }
152 
153 
155 {
156  optimizer::QuickRangeSelect *quick= NULL;
157  vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
158  int error;
159  int cmp;
160  uint32_t last_rowid_count= 0;
161 
162  do
163  {
164  /* Get a rowid for first quick and save it as a 'candidate' */
165  quick= *it;
166  ++it;
167  error= quick->get_next();
168  if (cpk_quick)
169  {
170  while (! error && ! cpk_quick->row_in_ranges())
171  error= quick->get_next();
172  }
173  if (error)
174  return error;
175 
176  quick->cursor->position(quick->record);
177  memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
178  last_rowid_count= 1;
179 
180  while (last_rowid_count < quick_selects.size())
181  {
183  if (it != quick_selects.end())
184  {
185  quick= *it;
186  ++it;
187  }
188  else
189  {
190  it= quick_selects.begin();
191  quick= *it;
192  ++it;
193  }
194 
195  do
196  {
197  if ((error= quick->get_next()))
198  return error;
199  quick->cursor->position(quick->record);
200  cmp= head->cursor->cmp_ref(quick->cursor->ref, last_rowid);
201  } while (cmp < 0);
202 
203  /* Ok, current select 'caught up' and returned ref >= cur_ref */
204  if (cmp > 0)
205  {
206  /* Found a row with ref > cur_ref. Make it a new 'candidate' */
207  if (cpk_quick)
208  {
209  while (! cpk_quick->row_in_ranges())
210  {
211  if ((error= quick->get_next()))
212  return error;
213  }
214  }
215  memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
216  last_rowid_count= 1;
217  }
218  else
219  {
220  /* current 'candidate' row confirmed by this select */
221  last_rowid_count++;
222  }
223  }
224 
225  /* We get here if we got the same row ref in all scans. */
226  if (need_to_fetch_row)
227  error= head->cursor->rnd_pos(head->record[0], last_rowid);
228  } while (error == HA_ERR_RECORD_DELETED);
229  return error;
230 }
231 
232 
234 {
235  bool first= true;
236  str->append("intersect(");
237  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
238  {
239  KeyInfo *key_info= head->key_info + it->index;
240  if (! first)
241  str->append(",");
242  else
243  first= false;
244  str->append(key_info->name);
245  }
246  if (cpk_quick)
247  {
248  KeyInfo *key_info= head->key_info + cpk_quick->index;
249  str->append(",");
250  str->append(key_info->name);
251  }
252  str->append(")");
253 }
254 
255 
257  string *used_lengths)
258 {
259  char buf[64];
260  uint32_t length;
261  bool first= true;
262  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
263  {
264  KeyInfo *key_info= head->key_info + it->index;
265  if (first)
266  {
267  first= false;
268  }
269  else
270  {
271  key_names->append(",");
272  used_lengths->append(",");
273  }
274  key_names->append(key_info->name);
275  length= internal::int64_t2str(it->max_used_key_length, buf, 10) - buf;
276  used_lengths->append(buf, length);
277  }
278 
279  if (cpk_quick)
280  {
281  KeyInfo *key_info= head->key_info + cpk_quick->index;
282  key_names->append(",");
283  key_names->append(key_info->name);
284  length= internal::int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf;
285  used_lengths->append(",");
286  used_lengths->append(buf, length);
287  }
288 }
289 
290 } /* namespace drizzled */
unsigned char * alloc(size_t Size)
Allocate a chunk of memory from the Root structure provided, obtaining more memory from the heap if n...
Definition: root.cc:140
void push_quick_back(QuickRangeSelect *quick_sel_range)
unsigned char * record[2]
Definition: table.h:139
void init(size_t block_size=ROOT_MIN_BLOCK_SIZE)
Initialize memory root.
Definition: root.cc:57
bool is_keys_used(const boost::dynamic_bitset<> &fields)
Cursor * cursor
Definition: table.h:68
int init_ror_merged_scan(bool reuse_handler)
uint32_t ref_length
Definition: cursor.h:159
drizzle_system_variables & variables
Definition: session.h:199
void add_keys_and_lengths(std::string *key_names, std::string *used_lengths)