Drizzled Public API Documentation

quick_index_merge_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/records.h>
23 #include <drizzled/util/functors.h>
24 #include <drizzled/optimizer/quick_range_select.h>
25 #include <drizzled/optimizer/quick_index_merge_select.h>
26 #include <drizzled/internal/m_string.h>
27 #include <drizzled/unique.h>
28 #include <drizzled/key.h>
29 #include <drizzled/table.h>
30 #include <drizzled/system_variables.h>
31 
32 #include <vector>
33 
34 using namespace std;
35 
36 namespace drizzled {
37 
38 static int refpos_order_cmp(void *arg, const void *a, const void *b)
39 {
40  Cursor *cursor= (Cursor*)arg;
41  return cursor->cmp_ref((const unsigned char *) a, (const unsigned char *) b);
42 }
43 
44 optimizer::QuickIndexMergeSelect::QuickIndexMergeSelect(Session *session_param,
45  Table *table)
46  :
47  pk_quick_select(NULL),
48  session(session_param)
49 {
50  index= MAX_KEY;
51  head= table;
52  memset(&read_record, 0, sizeof(read_record));
53  alloc.init(session->variables.range_alloc_block_size);
54 }
55 
57 {
58  return 0;
59 }
60 
62 {
63  return (read_keys_and_merge());
64 }
65 
66 void optimizer::QuickIndexMergeSelect::push_quick_back(optimizer::QuickRangeSelect *quick_sel_range)
67 {
68  /*
69  Save quick_select that does scan on clustered primary key as it will be
70  processed separately.
71  */
72  if (head->cursor->primary_key_is_clustered() &&
73  quick_sel_range->index == head->getShare()->getPrimaryKey())
74  {
75  pk_quick_select= quick_sel_range;
76  }
77  else
78  {
79  quick_selects.push_back(quick_sel_range);
80  }
81 }
82 
83 optimizer::QuickIndexMergeSelect::~QuickIndexMergeSelect()
84 {
85  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
86  it->cursor= NULL;
87  for_each(quick_selects.begin(), quick_selects.end(), DeletePtr());
88  quick_selects.clear();
89  delete pk_quick_select;
90  alloc.free_root(MYF(0));
91 }
92 
93 
94 int optimizer::QuickIndexMergeSelect::read_keys_and_merge()
95 {
96  vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
97  optimizer::QuickRangeSelect *cur_quick= NULL;
98  int result;
99  Unique *unique= NULL;
100  Cursor *cursor= head->cursor;
101 
102  cursor->extra(HA_EXTRA_KEYREAD);
103  head->prepare_for_position();
104 
105  cur_quick= *it;
106  ++it;
107  assert(cur_quick != 0);
108 
109  /*
110  We reuse the same instance of Cursor so we need to call both init and
111  reset here.
112  */
113  if (cur_quick->init() || cur_quick->reset())
114  return 0;
115 
116  unique= new Unique(refpos_order_cmp,
117  (void *) cursor,
118  cursor->ref_length,
119  session->variables.sortbuff_size);
120  if (! unique)
121  return 0;
122  for (;;)
123  {
124  while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
125  {
126  cur_quick->range_end();
127  if (it == quick_selects.end())
128  {
129  break;
130  }
131  cur_quick= *it;
132  ++it;
133  if (! cur_quick)
134  break;
135 
136  if (cur_quick->cursor->inited != Cursor::NONE)
137  cur_quick->cursor->endIndexScan();
138  if (cur_quick->init() || cur_quick->reset())
139  return 0;
140  }
141 
142  if (result)
143  {
144  if (result != HA_ERR_END_OF_FILE)
145  {
146  cur_quick->range_end();
147  return result;
148  }
149  break;
150  }
151 
152  if (session->getKilled())
153  return 0;
154 
155  /* skip row if it will be retrieved by clustered PK scan */
156  if (pk_quick_select && pk_quick_select->row_in_ranges())
157  continue;
158 
159  cur_quick->cursor->position(cur_quick->record);
160  result= unique->unique_add((char*) cur_quick->cursor->ref);
161  if (result)
162  return 0;
163 
164  }
165 
166  /* ok, all row ids are in Unique */
167  result= unique->get(head);
168  delete unique;
169  doing_pk_scan= false;
170  /* index_merge currently doesn't support "using index" at all */
171  cursor->extra(HA_EXTRA_NO_KEYREAD);
172  /* start table scan */
173  if ((result= read_record.init_read_record(session, head, (optimizer::SqlSelect*) 0, 1, 1)))
174  {
175  head->print_error(result, MYF(0));
176  return 0;
177  }
178  return result;
179 }
180 
181 
183 {
184  int result;
185 
186  if (doing_pk_scan)
187  return(pk_quick_select->get_next());
188 
189  if ((result= read_record.read_record(&read_record)) == -1)
190  {
191  result= HA_ERR_END_OF_FILE;
192  read_record.end_read_record();
193  /* All rows from Unique have been retrieved, do a clustered PK scan */
194  if (pk_quick_select)
195  {
196  doing_pk_scan= true;
197  if ((result= pk_quick_select->init()) ||
198  (result= pk_quick_select->reset()))
199  return result;
200  return(pk_quick_select->get_next());
201  }
202  }
203 
204  return result;
205 }
206 
207 bool optimizer::QuickIndexMergeSelect::is_keys_used(const boost::dynamic_bitset<>& fields)
208 {
209  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
210  {
211  if (is_key_used(head, it->index, fields))
212  return 1;
213  }
214  return 0;
215 }
216 
217 
219 {
220  bool first= true;
221  str->append("sort_union(");
222  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
223  {
224  if (! first)
225  str->append(",");
226  else
227  first= false;
228  it->add_info_string(str);
229  }
230  if (pk_quick_select)
231  {
232  str->append(",");
233  pk_quick_select->add_info_string(str);
234  }
235  str->append(")");
236 }
237 
238 
240  string *used_lengths)
241 {
242  char buf[64];
243  uint32_t length= 0;
244  bool first= true;
245 
246  BOOST_FOREACH(QuickRangeSelect* it, quick_selects)
247  {
248  if (first)
249  first= false;
250  else
251  {
252  key_names->append(",");
253  used_lengths->append(",");
254  }
255 
256  KeyInfo *key_info= head->key_info + it->index;
257  key_names->append(key_info->name);
258  length= internal::int64_t2str(it->max_used_key_length, buf, 10) - buf;
259  used_lengths->append(buf, length);
260  }
261  if (pk_quick_select)
262  {
263  KeyInfo *key_info= head->key_info + pk_quick_select->index;
264  key_names->append(",");
265  key_names->append(key_info->name);
266  length= internal::int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf;
267  used_lengths->append(",");
268  used_lengths->append(buf, length);
269  }
270 }
271 
272 
273 } /* namespace drizzled */