~drizzle-trunk/drizzle/development

1054.1.7 by Brian Aker
Refactor TableList methods.
1
/* Copyright (C) 2009 Sun Microsystems
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
1122.2.13 by Monty Taylor
Header cleanup.
16
#include "drizzled/server_includes.h"
1054.1.7 by Brian Aker
Refactor TableList methods.
17
18
#include <string>
19
1122.2.13 by Monty Taylor
Header cleanup.
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
1054.1.7 by Brian Aker
Refactor TableList methods.
28
using namespace std;
29
30
class Item;
31
class Item_field;
32
33
uint32_t TableList::create_table_def_key(char *key)
34
{
1089.1.4 by Brian Aker
Optimization for createKey(). Removes the need to initialize some
35
  return TableShare::createKey(key, db, table_name);
1054.1.7 by Brian Aker
Refactor TableList methods.
36
}
37
38
bool TableList::set_insert_values(MEM_ROOT *mem_root)
39
{
40
  if (table)
41
  {
42
    if (!table->insert_values &&
43
        !(table->insert_values= (unsigned char *)alloc_root(mem_root,
44
                                                   table->s->rec_buff_length)))
45
      return true;
46
  }
47
48
  return false;
49
}
50
51
bool TableList::is_leaf_for_name_resolution()
52
{
53
  return (is_natural_join || is_join_columns_complete || !nested_join);
54
}
55
56
TableList *TableList::find_underlying_table(Table *table_to_find)
57
{
58
  /* is this real table and table which we are looking for? */
59
  if (table == table_to_find)
60
    return this;
61
62
  return NULL;
63
}
64
65
bool TableList::placeholder()
66
{
67
  return derived || schema_table || (create && !table->getDBStat()) || !table;
68
}
69
70
/*
1188.1.2 by Jay Pipes
Style and doxygen cleanup ONLY. Moves method documentation from source into header files. Removes TAB characters and cleans up indentation.
71
 * The right-most child of a nested table reference is the first
72
 * element in the list of children because the children are inserted
73
 * in reverse order.
74
 */
1054.1.7 by Brian Aker
Refactor TableList methods.
75
TableList *TableList::last_leaf_for_name_resolution()
76
{
77
  TableList *cur_table_ref= this;
78
  nested_join_st *cur_nested_join;
79
80
  if (is_leaf_for_name_resolution())
81
    return this;
82
  assert(nested_join);
83
84
  for (cur_nested_join= nested_join;
85
       cur_nested_join;
86
       cur_nested_join= cur_table_ref->nested_join)
87
  {
88
    cur_table_ref= cur_nested_join->join_list.head();
89
    /*
90
      If the current nested is a RIGHT JOIN, the operands in
91
      'join_list' are in reverse order, thus the last operand is in the
92
      end of the list.
93
    */
94
    if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
95
    {
96
      List_iterator_fast<TableList> it(cur_nested_join->join_list);
97
      TableList *next;
98
      cur_table_ref= it++;
99
      while ((next= it++))
100
        cur_table_ref= next;
101
    }
102
    if (cur_table_ref->is_leaf_for_name_resolution())
103
      break;
104
  }
105
  return cur_table_ref;
106
}
107
108
/*
1188.1.2 by Jay Pipes
Style and doxygen cleanup ONLY. Moves method documentation from source into header files. Removes TAB characters and cleans up indentation.
109
 * The left-most child of a nested table reference is the last element
110
 * in the list of children because the children are inserted in
111
 * reverse order.
112
 */
1054.1.7 by Brian Aker
Refactor TableList methods.
113
TableList *TableList::first_leaf_for_name_resolution()
114
{
115
  TableList *cur_table_ref= NULL;
116
  nested_join_st *cur_nested_join;
117
118
  if (is_leaf_for_name_resolution())
119
    return this;
120
  assert(nested_join);
121
122
  for (cur_nested_join= nested_join;
123
       cur_nested_join;
124
       cur_nested_join= cur_table_ref->nested_join)
125
  {
126
    List_iterator_fast<TableList> it(cur_nested_join->join_list);
127
    cur_table_ref= it++;
128
    /*
129
      If the current nested join is a RIGHT JOIN, the operands in
130
      'join_list' are in reverse order, thus the first operand is
131
      already at the front of the list. Otherwise the first operand
132
      is in the end of the list of join operands.
133
    */
134
    if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
135
    {
136
      TableList *next;
137
      while ((next= it++))
138
        cur_table_ref= next;
139
    }
140
    if (cur_table_ref->is_leaf_for_name_resolution())
141
      break;
142
  }
143
  return cur_table_ref;
144
}
145
146
Item_subselect *TableList::containing_subselect()
147
{
148
  return (select_lex ? select_lex->master_unit()->item : 0);
149
}
150
151
bool TableList::process_index_hints(Table *tbl)
152
{
153
  /* initialize the result variables */
154
  tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
155
    tbl->keys_in_use_for_order_by= tbl->s->keys_in_use;
156
157
  /* index hint list processing */
158
  if (index_hints)
159
  {
160
    key_map index_join[INDEX_HINT_FORCE + 1];
161
    key_map index_order[INDEX_HINT_FORCE + 1];
162
    key_map index_group[INDEX_HINT_FORCE + 1];
163
    Index_hint *hint;
164
    int type;
165
    bool have_empty_use_join= false, have_empty_use_order= false,
166
         have_empty_use_group= false;
167
    List_iterator <Index_hint> iter(*index_hints);
168
169
    /* initialize temporary variables used to collect hints of each kind */
170
    for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
171
    {
172
      index_join[type].reset();
173
      index_order[type].reset();
174
      index_group[type].reset();
175
    }
176
177
    /* iterate over the hints list */
178
    while ((hint= iter++))
179
    {
180
      uint32_t pos;
181
182
      /* process empty USE INDEX () */
183
      if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
184
      {
185
        if (hint->clause & INDEX_HINT_MASK_JOIN)
186
        {
187
          index_join[hint->type].reset();
188
          have_empty_use_join= true;
189
        }
190
        if (hint->clause & INDEX_HINT_MASK_ORDER)
191
        {
192
          index_order[hint->type].reset();
193
          have_empty_use_order= true;
194
        }
195
        if (hint->clause & INDEX_HINT_MASK_GROUP)
196
        {
197
          index_group[hint->type].reset();
198
          have_empty_use_group= true;
199
        }
200
        continue;
201
      }
202
203
      /*
204
        Check if an index with the given name exists and get his offset in
205
        the keys bitmask for the table
206
      */
207
      if (tbl->s->keynames.type_names == 0 ||
208
          (pos= find_type(&tbl->s->keynames, hint->key_name.str,
209
                          hint->key_name.length, 1)) <= 0)
210
      {
211
        my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
212
        return 1;
213
      }
214
215
      pos--;
216
217
      /* add to the appropriate clause mask */
218
      if (hint->clause & INDEX_HINT_MASK_JOIN)
219
        index_join[hint->type].set(pos);
220
      if (hint->clause & INDEX_HINT_MASK_ORDER)
221
        index_order[hint->type].set(pos);
222
      if (hint->clause & INDEX_HINT_MASK_GROUP)
223
        index_group[hint->type].set(pos);
224
    }
225
226
    /* cannot mix USE INDEX and FORCE INDEX */
227
    if ((index_join[INDEX_HINT_FORCE].any() ||
228
         index_order[INDEX_HINT_FORCE].any() ||
229
         index_group[INDEX_HINT_FORCE].any()) &&
230
        (index_join[INDEX_HINT_USE].any() ||  have_empty_use_join ||
231
         index_order[INDEX_HINT_USE].any() || have_empty_use_order ||
232
         index_group[INDEX_HINT_USE].any() || have_empty_use_group))
233
    {
234
      my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
235
               index_hint_type_name[INDEX_HINT_FORCE]);
236
      return 1;
237
    }
238
239
    /* process FORCE INDEX as USE INDEX with a flag */
240
    if (index_join[INDEX_HINT_FORCE].any() ||
241
        index_order[INDEX_HINT_FORCE].any() ||
242
        index_group[INDEX_HINT_FORCE].any())
243
    {
244
      tbl->force_index= true;
245
      index_join[INDEX_HINT_USE]|= index_join[INDEX_HINT_FORCE];
246
      index_order[INDEX_HINT_USE]|= index_order[INDEX_HINT_FORCE];
247
      index_group[INDEX_HINT_USE]|= index_group[INDEX_HINT_FORCE];
248
    }
249
250
    /* apply USE INDEX */
251
    if (index_join[INDEX_HINT_USE].any() || have_empty_use_join)
252
      tbl->keys_in_use_for_query&= index_join[INDEX_HINT_USE];
253
    if (index_order[INDEX_HINT_USE].any() || have_empty_use_order)
254
      tbl->keys_in_use_for_order_by&= index_order[INDEX_HINT_USE];
255
    if (index_group[INDEX_HINT_USE].any() || have_empty_use_group)
256
      tbl->keys_in_use_for_group_by&= index_group[INDEX_HINT_USE];
257
258
    /* apply IGNORE INDEX */
259
    key_map_subtract(tbl->keys_in_use_for_query, index_join[INDEX_HINT_IGNORE]);
260
    key_map_subtract(tbl->keys_in_use_for_order_by, index_order[INDEX_HINT_IGNORE]);
261
    key_map_subtract(tbl->keys_in_use_for_group_by, index_group[INDEX_HINT_IGNORE]);
262
  }
263
264
  /* make sure covering_keys don't include indexes disabled with a hint */
265
  tbl->covering_keys&= tbl->keys_in_use_for_query;
266
  return 0;
267
}
268
269
void TableList::print(Session *session, String *str, enum_query_type query_type)
270
{
271
  if (nested_join)
272
  {
273
    str->append('(');
274
    print_join(session, str, &nested_join->join_list, query_type);
275
    str->append(')');
276
  }
277
  else
278
  {
279
    const char *cmp_name;                         // Name to compare with alias
280
    if (derived)
281
    {
282
      // A derived table
283
      str->append('(');
284
      derived->print(str, query_type);
285
      str->append(')');
286
      cmp_name= "";                               // Force printing of alias
287
    }
288
    else
289
    {
290
      // A normal table
291
      {
292
        str->append_identifier(db, db_length);
293
        str->append('.');
294
      }
295
      if (schema_table)
296
      {
297
        str->append_identifier(schema_table_name, strlen(schema_table_name));
298
        cmp_name= schema_table_name;
299
      }
300
      else
301
      {
302
        str->append_identifier(table_name, table_name_length);
303
        cmp_name= table_name;
304
      }
305
    }
306
    if (my_strcasecmp(table_alias_charset, cmp_name, alias))
307
    {
308
309
      if (alias && alias[0])
310
      {
311
        str->append(' ');
312
313
        string t_alias(alias);
314
        transform(t_alias.begin(), t_alias.end(),
315
                  t_alias.begin(), ::tolower);
316
317
        str->append_identifier(t_alias.c_str(), t_alias.length());
318
      }
319
320
    }
321
322
    if (index_hints)
323
    {
324
      List_iterator<Index_hint> it(*index_hints);
325
      Index_hint *hint;
326
327
      while ((hint= it++))
328
      {
329
        str->append (STRING_WITH_LEN(" "));
330
        hint->print (session, str);
331
      }
332
    }
333
  }
334
}