Drizzled Public API Documentation

table_list.cc
1 /* Copyright (C) 2009 Sun Microsystems, Inc.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <config.h>
17 
18 #include <string>
19 
20 #include <drizzled/error.h>
21 #include <drizzled/table_list.h>
22 #include <drizzled/item.h>
23 #include <drizzled/item/field.h>
24 #include <drizzled/nested_join.h>
25 #include <drizzled/sql_lex.h>
26 #include <drizzled/sql_select.h>
27 
28 using namespace std;
29 
30 namespace drizzled {
31 
32 void TableList::set_insert_values()
33 {
34  if (table)
35  {
36  table->insert_values.resize(table->getShare()->rec_buff_length);
37  }
38 }
39 
40 bool TableList::is_leaf_for_name_resolution() const
41 {
42  return is_natural_join || is_join_columns_complete || not nested_join;
43 }
44 
45 TableList *TableList::find_underlying_table(Table *table_to_find)
46 {
47  /* is this real table and table which we are looking for? */
48  if (table == table_to_find)
49  return this;
50 
51  return NULL;
52 }
53 
54 bool TableList::isCartesian() const
55 {
56  return false;
57 }
58 
59 bool TableList::placeholder()
60 {
61  return derived || (create && !table->getDBStat()) || !table;
62 }
63 
64 /*
65  * The right-most child of a nested table reference is the first
66  * element in the list of children because the children are inserted
67  * in reverse order.
68  */
69 TableList *TableList::last_leaf_for_name_resolution()
70 {
71  TableList *cur_table_ref= this;
72  NestedJoin *cur_nested_join;
73 
74  if (is_leaf_for_name_resolution())
75  return this;
76  assert(nested_join);
77 
78  for (cur_nested_join= nested_join;
79  cur_nested_join;
80  cur_nested_join= cur_table_ref->nested_join)
81  {
82  cur_table_ref= &cur_nested_join->join_list.front();
83  /*
84  If the current nested is a RIGHT JOIN, the operands in
85  'join_list' are in reverse order, thus the last operand is in the
86  end of the list.
87  */
88  if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
89  {
90  List<TableList>::iterator it(cur_nested_join->join_list.begin());
91  TableList *next;
92  cur_table_ref= it++;
93  while ((next= it++))
94  cur_table_ref= next;
95  }
96  if (cur_table_ref->is_leaf_for_name_resolution())
97  break;
98  }
99  return cur_table_ref;
100 }
101 
102 /*
103  * The left-most child of a nested table reference is the last element
104  * in the list of children because the children are inserted in
105  * reverse order.
106  */
107 TableList *TableList::first_leaf_for_name_resolution()
108 {
109  TableList *cur_table_ref= NULL;
110  NestedJoin *cur_nested_join;
111 
112  if (is_leaf_for_name_resolution())
113  return this;
114  assert(nested_join);
115 
116  for (cur_nested_join= nested_join;
117  cur_nested_join;
118  cur_nested_join= cur_table_ref->nested_join)
119  {
120  List<TableList>::iterator it(cur_nested_join->join_list.begin());
121  cur_table_ref= it++;
122  /*
123  If the current nested join is a RIGHT JOIN, the operands in
124  'join_list' are in reverse order, thus the first operand is
125  already at the front of the list. Otherwise the first operand
126  is in the end of the list of join operands.
127  */
128  if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
129  {
130  TableList *next;
131  while ((next= it++))
132  cur_table_ref= next;
133  }
134  if (cur_table_ref->is_leaf_for_name_resolution())
135  break;
136  }
137  return cur_table_ref;
138 }
139 
140 Item_subselect *TableList::containing_subselect()
141 {
142  return (select_lex ? select_lex->master_unit()->item : 0);
143 }
144 
145 bool TableList::process_index_hints(Table *tbl)
146 {
147  /* initialize the result variables */
148  tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
149  tbl->keys_in_use_for_order_by= tbl->getShare()->keys_in_use;
150 
151  /* index hint list processing */
152  if (index_hints)
153  {
154  key_map index_join[INDEX_HINT_FORCE + 1];
155  key_map index_order[INDEX_HINT_FORCE + 1];
156  key_map index_group[INDEX_HINT_FORCE + 1];
157  bool have_empty_use_join= false, have_empty_use_order= false,
158  have_empty_use_group= false;
159  List_iterator <Index_hint> iter(index_hints->begin());
160 
161  /* initialize temporary variables used to collect hints of each kind */
162  for (int type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
163  {
164  index_join[type].reset();
165  index_order[type].reset();
166  index_group[type].reset();
167  }
168 
169  /* iterate over the hints list */
170  while (Index_hint* hint= iter++)
171  {
172  /* process empty USE INDEX () */
173  if (hint->type == INDEX_HINT_USE && !hint->key_name)
174  {
175  if (hint->clause & INDEX_HINT_MASK_JOIN)
176  {
177  index_join[hint->type].reset();
178  have_empty_use_join= true;
179  }
180  if (hint->clause & INDEX_HINT_MASK_ORDER)
181  {
182  index_order[hint->type].reset();
183  have_empty_use_order= true;
184  }
185  if (hint->clause & INDEX_HINT_MASK_GROUP)
186  {
187  index_group[hint->type].reset();
188  have_empty_use_group= true;
189  }
190  continue;
191  }
192 
193  /*
194  Check if an index with the given name exists and get his offset in
195  the keys bitmask for the table
196  */
197  uint32_t pos= tbl->getShare()->doesKeyNameExist(hint->key_name);
198  if (pos == UINT32_MAX)
199  {
200  my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name, alias);
201  return 1;
202  }
203  /* add to the appropriate clause mask */
204  if (hint->clause & INDEX_HINT_MASK_JOIN)
205  index_join[hint->type].set(pos);
206  if (hint->clause & INDEX_HINT_MASK_ORDER)
207  index_order[hint->type].set(pos);
208  if (hint->clause & INDEX_HINT_MASK_GROUP)
209  index_group[hint->type].set(pos);
210  }
211 
212  /* cannot mix USE INDEX and FORCE INDEX */
213  if ((index_join[INDEX_HINT_FORCE].any() ||
214  index_order[INDEX_HINT_FORCE].any() ||
215  index_group[INDEX_HINT_FORCE].any()) &&
216  (index_join[INDEX_HINT_USE].any() || have_empty_use_join ||
217  index_order[INDEX_HINT_USE].any() || have_empty_use_order ||
218  index_group[INDEX_HINT_USE].any() || have_empty_use_group))
219  {
220  my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE], index_hint_type_name[INDEX_HINT_FORCE]);
221  return 1;
222  }
223 
224  /* process FORCE INDEX as USE INDEX with a flag */
225  if (index_join[INDEX_HINT_FORCE].any() ||
226  index_order[INDEX_HINT_FORCE].any() ||
227  index_group[INDEX_HINT_FORCE].any())
228  {
229  tbl->force_index= true;
230  index_join[INDEX_HINT_USE]|= index_join[INDEX_HINT_FORCE];
231  index_order[INDEX_HINT_USE]|= index_order[INDEX_HINT_FORCE];
232  index_group[INDEX_HINT_USE]|= index_group[INDEX_HINT_FORCE];
233  }
234 
235  /* apply USE INDEX */
236  if (index_join[INDEX_HINT_USE].any() || have_empty_use_join)
237  tbl->keys_in_use_for_query&= index_join[INDEX_HINT_USE];
238  if (index_order[INDEX_HINT_USE].any() || have_empty_use_order)
239  tbl->keys_in_use_for_order_by&= index_order[INDEX_HINT_USE];
240  if (index_group[INDEX_HINT_USE].any() || have_empty_use_group)
241  tbl->keys_in_use_for_group_by&= index_group[INDEX_HINT_USE];
242 
243  /* apply IGNORE INDEX */
244  key_map_subtract(tbl->keys_in_use_for_query, index_join[INDEX_HINT_IGNORE]);
245  key_map_subtract(tbl->keys_in_use_for_order_by, index_order[INDEX_HINT_IGNORE]);
246  key_map_subtract(tbl->keys_in_use_for_group_by, index_group[INDEX_HINT_IGNORE]);
247  }
248 
249  /* make sure covering_keys don't include indexes disabled with a hint */
250  tbl->covering_keys&= tbl->keys_in_use_for_query;
251  return 0;
252 }
253 
254 void TableList::print(Session *session, String *str)
255 {
256  if (nested_join)
257  {
258  str->append('(');
259  print_join(session, str, &nested_join->join_list);
260  str->append(')');
261  }
262  else
263  {
264  const char *cmp_name; // Name to compare with alias
265  if (derived)
266  {
267  // A derived table
268  str->append('(');
269  derived->print(str);
270  str->append(')');
271  cmp_name= ""; // Force printing of alias
272  }
273  else
274  {
275  // A normal table
276  str->append_identifier(str_ref(schema));
277  str->append('.');
278  str->append_identifier(str_ref(table_name));
279  cmp_name= table_name;
280  }
281  if (table_alias_charset->strcasecmp(cmp_name, alias) && alias && alias[0])
282  {
283  str->append(' ');
284  str->append_identifier(boost::to_lower_copy(string(alias)));
285  }
286 
287  if (index_hints)
288  {
289  List<Index_hint>::iterator it(index_hints->begin());
290  while (Index_hint* hint= it++)
291  {
292  str->append(STRING_WITH_LEN(" "));
293  hint->print(*str);
294  }
295  }
296  }
297 }
298 
299 } /* namespace drizzled */