1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
21
classes to use when handling where clause
24
#ifdef USE_PRAGMA_INTERFACE
25
#pragma interface /* gcc class implementation */
28
#include "procedure.h"
31
typedef struct keyuse_t {
33
Item *val; /**< or value if no field */
34
table_map used_tables;
35
uint key, keypart, optimize;
36
key_part_map keypart_map;
37
ha_rows ref_table_rows;
39
If true, the comparison this value was created from will not be
40
satisfied if val has NULL 'value'.
44
!NULL - This KEYUSE was created from an equality that was wrapped into
45
an Item_func_trig_cond. This means the equality (and validity of
46
this KEYUSE element) can be turned on and off. The on/off state
47
is indicted by the pointed value:
48
*cond_guard == TRUE <=> equality condition is on
49
*cond_guard == FALSE <=> equality condition is off
51
NULL - Otherwise (the source equality can't be turned off)
58
typedef struct st_table_ref
61
/** True if something was read into buffer in join_read_key. */
63
uint key_parts; ///< num of ...
64
uint key_length; ///< length of key_buff
66
uchar *key_buff; ///< value to look for with key
67
uchar *key_buff2; ///< key_buff+key_length
68
store_key **key_copy; //
69
Item **items; ///< val()'s for each keypart
71
Array of pointers to trigger variables. Some/all of the pointers may be
72
NULL. The ref access can be used iff
74
for each used key part i, (!cond_guards[i] || *cond_guards[i])
76
This array is used by subquery code. The subquery code may inject
77
triggered conditions, i.e. conditions that can be 'switched off'. A ref
78
access created from such condition is not valid when at least one of the
79
underlying conditions is switched off (see subquery code for more details)
83
(null_rejecting & (1<<i)) means the condition is '=' and no matching
84
rows will be produced if items[i] IS NULL (see add_not_null_conds())
86
key_part_map null_rejecting;
87
table_map depend_map; ///< Table depends on these tables.
88
/* null byte position in the key_buf. Used for REF_OR_NULL optimization */
91
The number of times the record associated with this key was used
99
#define CACHE_BLOB 1 /* blob field */
100
#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */
103
CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
107
typedef struct st_cache_field {
109
uint length, blob_length;
111
uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */
115
typedef struct st_join_cache {
116
uchar *buff,*pos,*end;
117
uint records,record_nr,ptr_record,fields,length,blobs;
118
CACHE_FIELD *field,**blob_ptr;
124
The structs which holds the join connections and join states
126
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
127
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
128
JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE};
132
enum enum_nested_loop_state
134
NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1,
135
NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1,
136
NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
140
/* Values for JOIN_TAB::packed_info */
141
#define TAB_INFO_HAVE_VALUE 1
142
#define TAB_INFO_USING_INDEX 2
143
#define TAB_INFO_USING_WHERE 4
144
#define TAB_INFO_FULL_SCAN_ON_NULL 8
146
typedef enum_nested_loop_state
147
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
148
typedef int (*Read_record_func)(struct st_join_table *tab);
149
Next_select_func setup_end_select_func(JOIN *join);
152
typedef struct st_join_table {
153
st_join_table() {} /* Remove gcc warning */
155
KEYUSE *keyuse; /**< pointer to first used key */
158
QUICK_SELECT_I *quick;
159
Item **on_expr_ref; /**< pointer to the associated on expression */
160
COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */
161
st_join_table *first_inner; /**< first inner table for including outerjoin */
162
bool found; /**< true after all matches or null complement */
163
bool not_null_compl;/**< true before null complement is added */
164
st_join_table *last_inner; /**< last table table for embedding outer join */
165
st_join_table *first_upper; /**< first inner table for embedding outer join */
166
st_join_table *first_unmatched; /**< used for optimization purposes only */
168
/* Special content for EXPLAIN 'Extra' column or NULL if none */
171
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
172
column, or 0 if there is no info.
176
Read_record_func read_first_record;
177
Next_select_func next_select;
178
READ_RECORD read_record;
180
Currently the following two fields are used only for a [NOT] IN subquery
181
if it is executed by an alternative full table scan when the left operand of
182
the subquery predicate is evaluated to NULL.
184
Read_record_func save_read_first_record;/* to save read_first_record */
185
int (*save_read_record) (READ_RECORD *);/* to save read_record.read_record */
187
key_map const_keys; /**< Keys with constant part */
188
key_map checked_keys; /**< Keys checked in find_best */
190
key_map keys; /**< all keys with can be used */
192
/* Either #rows in the table or 1 for const table. */
195
Number of records that will be scanned (yes scanned, not returned) by the
196
best 'independent' access method, i.e. table scan or QUICK_*_SELECT)
198
ha_rows found_records;
200
Cost of accessing the table using "ALL" or range/index_merge access
201
method (but not 'index' for some reason), i.e. this matches method which
202
E(#records) is in found_records.
206
table_map dependent,key_dependent;
207
uint use_quick,index;
208
uint status; ///< Save status for cache
209
uint used_fields,used_fieldlength,used_blobs;
211
bool cached_eq_ref_table,eq_ref_table,not_used_in_distinct;
214
If it's not 0 the number stored this field indicates that the index
215
scan has been chosen to access the table data and we expect to scan
216
this number of rows for the table.
222
/** Bitmap of nested joins this table is part of */
223
nested_join_map embedding_map;
226
inline bool is_using_loose_index_scan()
228
return (select && select->quick &&
229
(select->quick->get_type() ==
230
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
234
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
236
enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool
240
Information about a position of table within a join order. Used in join
243
typedef struct st_position
246
The "fanout": number of output rows that will be produced (after
247
pushed down selection condition is applied) per each row combination of
253
Cost accessing the table in course of the entire complete join execution,
254
i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times
255
number the access method will be invoked.
261
NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used.
262
Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr}
266
/* If ref-based access is used: bitmap of tables this table depends on */
267
table_map ref_depend_map;
271
typedef struct st_rollup
273
enum State { STATE_NONE, STATE_INITED, STATE_READY };
275
Item_null_result **null_items;
276
Item ***ref_pointer_arrays;
281
class JOIN :public Sql_alloc
283
JOIN(const JOIN &rhs); /**< not implemented */
284
JOIN& operator=(const JOIN &rhs); /**< not implemented */
286
JOIN_TAB *join_tab,**best_ref;
287
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
288
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
289
TABLE **table,**all_tables,*sort_by_table;
290
uint tables,const_tables;
291
uint send_group_parts;
293
Indicates that grouping will be performed on the result set during
294
query execution. This field belongs to query execution.
296
@see make_group_fields, alloc_group_fields, JOIN::exec
299
bool first_record,full_join,group, no_field_update;
302
TRUE when we want to resume nested loop iterations when
303
fetching data from a cursor
305
bool resume_nested_loop;
306
table_map const_table_map,found_const_table_map;
308
Bitmap of all inner tables from outer joins
310
table_map outer_join;
311
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
313
Used to fetch no more than given amount of rows per one
314
fetch operation of server side cursor.
315
The value is checked in end_send and end_send_group in fashion, similar
317
- fetch_limit= HA_POS_ERROR if there is no cursor.
318
- when we open a cursor, we set fetch_limit to 0,
319
- on each fetch iteration we add num_rows to fetch to fetch_limit
322
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
325
Bitmap of nested joins embedding the position at the end of the current
326
partial join (valid only during join optimizer run).
328
nested_join_map cur_embedding_map;
332
List<Cached_item> group_fields, group_fields_cache;
334
/// used to store 2 possible tmp table of SELECT
335
TABLE *exec_tmp_table1, *exec_tmp_table2;
337
Item_sum **sum_funcs, ***sum_funcs_end;
338
/** second copy of sumfuncs (for queries with 2 temporary tables */
339
Item_sum **sum_funcs2, ***sum_funcs_end2;
340
Procedure *procedure;
342
Item *tmp_having; ///< To store having when processed temporary table
343
Item *having_history; ///< Store having for explain
344
ulonglong select_options;
345
select_result *result;
346
TMP_TABLE_PARAM tmp_table_param;
348
/// unit structure (with global parameters) for this select
349
SELECT_LEX_UNIT *unit;
350
/// select that processed
351
SELECT_LEX *select_lex;
353
TRUE <=> optimizer must not mark any table as a constant table.
354
This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..):
355
when we optimize the select that reads the results of the union from a
356
temporary table, we must not mark the temp. table as constant because
357
the number of rows in it may vary from one subquery execution to another.
359
bool no_const_tables;
362
Copy of this JOIN to be used with temporary tables.
364
tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery
365
that gets re-executed several times) and we know will use temporary tables
366
for materialization. The materialization to a temporary table overwrites the
367
JOIN structure to point to the temporary table after the materialization is
368
done. This is where tmp_join is used : it's a copy of the JOIN before the
369
materialization and is used in restoring before re-execution by overwriting
370
the current JOIN structure with the saved copy.
371
Because of this we should pay extra care of not freeing up helper structures
372
that are referenced by the original contents of the JOIN. We can check for
373
this by making sure the "current" join is not the temporary copy, e.g.
374
!tmp_join || tmp_join != join
376
We should free these sub-structures at JOIN::destroy() if the "current" join
377
has a copy is not that copy.
380
ROLLUP rollup; ///< Used with rollup
382
bool select_distinct; ///< Set if SELECT DISTINCT
384
If we have the GROUP BY statement in the query,
385
but the group_list was emptied by optimizer, this
387
It happens when fields in the GROUP BY are from
390
bool group_optimized_away;
393
simple_xxxxx is set if ORDER/GROUP BY doesn't include any references
394
to other tables than the first non-constant table in the JOIN.
395
It's also set if ORDER/GROUP BY is empty.
396
Used for deciding for or against using a temporary table to compute
399
bool simple_order, simple_group;
401
Is set only in case if we have a GROUP BY clause
402
and no ORDER BY after constant elimination of 'order'.
405
/** Is set if we have a GROUP BY and we have ORDER BY on a constant. */
406
bool skip_sort_order;
408
bool need_tmp, hidden_group_fields;
409
DYNAMIC_ARRAY keyuse;
410
Item::cond_result cond_value, having_value;
411
List<Item> all_fields; ///< to store all fields that used in query
412
///Above list changed to use temporary table
413
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
414
///Part, shared with list above, emulate following list
415
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
416
List<Item> &fields_list; ///< hold field list passed to mysql_select
417
List<Item> procedure_fields_list;
420
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
421
COND *conds; // ---"---
422
Item *conds_history; // store WHERE for explain
423
TABLE_LIST *tables_list; ///<hold 'tables' parameter of mysql_select
424
List<TABLE_LIST> *join_list; ///< list of joined tables in reverse order
425
COND_EQUAL *cond_equal;
426
SQL_SELECT *select; ///<created in optimisation phase
427
JOIN_TAB *return_tab; ///<used only for outer joins
428
Item **ref_pointer_array; ///<used pointer reference for this select
429
// Copy of above to be used with different lists
430
Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
431
uint ref_pointer_array_size; ///< size of above in bytes
432
const char *zero_result_cause; ///< not 0 if exec must return zero result
434
bool union_part; ///< this subselect is part of union
435
bool optimized; ///< flag to avoid double optimization in EXPLAIN
438
storage for caching buffers allocated during query execution.
439
These buffers allocations need to be cached as the thread memory pool is
440
cleared only at the end of the execution of the whole query and not caching
441
allocations that occur in repetition at execution time will result in
442
excessive memory usage.
443
Note: make_simple_join always creates an execution plan that accesses
444
a single table, thus it is sufficient to have a one-element array for
447
SORT_FIELD *sortorder; // make_unireg_sortorder()
448
TABLE *table_reexec[1]; // make_simple_join()
449
JOIN_TAB *join_tab_reexec; // make_simple_join()
450
/* end of allocation caching storage */
452
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
453
select_result *result_arg)
454
:fields_list(fields_arg)
456
init(thd_arg, fields_arg, select_options_arg, result_arg);
459
void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
460
select_result *result_arg)
462
join_tab= join_tab_save= 0;
467
implicit_grouping= FALSE;
471
resume_nested_loop= FALSE;
474
fetch_limit= HA_POS_ERROR;
482
sum_funcs= sum_funcs2= 0;
484
having= tmp_having= having_history= 0;
485
select_options= select_options_arg;
488
select_lex= 0; //for safety
490
select_distinct= test(select_options & SELECT_DISTINCT);
496
hidden_group_fields= 0; /*safety*/
500
ref_pointer_array= items0= items1= items2= items3= 0;
501
ref_pointer_array_size= 0;
502
zero_result_cause= 0;
505
group_optimized_away= 0;
507
all_fields= fields_arg;
508
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
509
fields_list= fields_arg;
510
bzero((char*) &keyuse,sizeof(keyuse));
511
tmp_table_param.init();
512
tmp_table_param.end_write_records= HA_POS_ERROR;
513
rollup.state= ROLLUP::STATE_NONE;
515
no_const_tables= FALSE;
518
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
519
COND *conds, uint og_num, ORDER *order, ORDER *group,
520
Item *having, ORDER *proc_param, SELECT_LEX *select,
521
SELECT_LEX_UNIT *unit);
527
bool alloc_func_list();
528
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
529
bool before_group_by, bool recompute= FALSE);
531
inline void set_items_ref_array(Item **ptr)
533
memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
534
current_ref_pointer_array= ptr;
536
inline void init_items_ref_array()
538
items0= ref_pointer_array + all_fields.elements;
539
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
540
current_ref_pointer_array= items0;
544
bool rollup_process_const_fields();
545
bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
547
int rollup_send_data(uint idx);
548
int rollup_write_data(uint idx, TABLE *table);
549
void remove_subq_pushed_predicates(Item **where);
551
Release memory and, if possible, the open tables held by this execution
552
plan (and nested plans). It's used to release some tables before
553
the end of execution in order to increase concurrency and reduce
557
/** Cleanup this JOIN, possibly for reuse */
558
void cleanup(bool full);
560
bool save_join_tab();
561
bool init_save_join_tab();
562
bool send_row_on_empty_set()
564
return (do_send_rows && tmp_table_param.sum_func_count != 0 &&
565
!group_list && having_value != Item::COND_FALSE);
567
bool change_result(select_result *result);
568
bool is_top_level_join() const
570
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
571
select_lex == unit->fake_select_lex));
575
TRUE if the query contains an aggregate function but has no GROUP
578
bool implicit_grouping;
579
bool make_simple_join(JOIN *join, TABLE *tmp_table);
583
typedef struct st_select_check {
584
uint const_ref,reg_ref;
587
extern const char *join_type_str[];
588
void TEST_join(JOIN *join);
590
/* Extern functions in sql_select.cc */
591
bool store_val_in_field(Field *field, Item *val, enum_check_fields check_flag);
592
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
593
ORDER *group, bool distinct, bool save_sum_fields,
594
ulonglong select_options, ha_rows rows_limit,
596
void free_tmp_table(THD *thd, TABLE *entry);
597
void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
598
List<Item> &fields, bool reset_with_sum_func);
599
bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
600
Item **ref_pointer_array,
601
List<Item> &new_list1, List<Item> &new_list2,
602
uint elements, List<Item> &fields);
603
void copy_fields(TMP_TABLE_PARAM *param);
604
void copy_funcs(Item **func_ptr);
605
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
606
int error, bool ignore_last_dupp_error);
607
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
608
Field* create_tmp_field_from_field(THD *thd, Field* org_field,
609
const char *name, TABLE *table,
610
Item_field *item, uint convert_blob_length);
612
/* functions from opt_sum.cc */
613
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
614
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
616
/* from sql_delete.cc, used by opt_range.cc */
617
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
619
/** class to copying an field/item to a key struct */
621
class store_key :public Sql_alloc
624
bool null_key; /* TRUE <=> the value of the key has a null part */
625
enum store_key_result { STORE_KEY_OK, STORE_KEY_FATAL, STORE_KEY_CONV };
626
store_key(THD *thd, Field *field_arg, uchar *ptr, uchar *null, uint length)
627
:null_key(0), null_ptr(null), err(0)
629
if (field_arg->type() == MYSQL_TYPE_BLOB
630
|| field_arg->type() == MYSQL_TYPE_GEOMETRY)
633
Key segments are always packed with a 2 byte length prefix.
634
See mi_rkey for details.
636
to_field= new Field_varstring(ptr, length, 2, null, 1,
637
Field::NONE, field_arg->field_name,
638
field_arg->table->s, field_arg->charset());
639
to_field->init(field_arg->table);
642
to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
645
virtual ~store_key() {} /** Not actually needed */
646
virtual const char *name() const=0;
649
@brief sets ignore truncation warnings mode and calls the real copy method
651
@details this function makes sure truncation warnings when preparing the
652
key buffers don't end up as errors (because of an enclosing INSERT/UPDATE).
654
enum store_key_result copy()
656
enum store_key_result result;
657
THD *thd= to_field->table->in_use;
658
enum_check_fields saved_count_cuted_fields= thd->count_cuted_fields;
659
ulong sql_mode= thd->variables.sql_mode;
660
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
662
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
664
result= copy_inner();
666
thd->count_cuted_fields= saved_count_cuted_fields;
667
thd->variables.sql_mode= sql_mode;
673
Field *to_field; // Store data here
677
virtual enum store_key_result copy_inner()=0;
681
class store_key_field: public store_key
683
Copy_field copy_field;
684
const char *field_name;
686
store_key_field(THD *thd, Field *to_field_arg, uchar *ptr,
688
uint length, Field *from_field, const char *name_arg)
689
:store_key(thd, to_field_arg,ptr,
690
null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
691
: (uchar*) 0, length), field_name(name_arg)
695
copy_field.set(to_field,from_field,0);
698
const char *name() const { return field_name; }
701
enum store_key_result copy_inner()
703
TABLE *table= copy_field.to_field->table;
704
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
706
copy_field.do_copy(©_field);
707
dbug_tmp_restore_column_map(table->write_set, old_map);
708
null_key= to_field->is_null();
709
return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK;
714
class store_key_item :public store_key
719
store_key_item(THD *thd, Field *to_field_arg, uchar *ptr,
720
uchar *null_ptr_arg, uint length, Item *item_arg)
721
:store_key(thd, to_field_arg, ptr,
722
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
723
&err : (uchar*) 0, length), item(item_arg)
725
const char *name() const { return "func"; }
728
enum store_key_result copy_inner()
730
TABLE *table= to_field->table;
731
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
733
int res= item->save_in_field(to_field, 1);
735
Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
736
we need to check for errors executing it and react accordingly
738
if (!res && table->in_use->is_error())
739
res= 1; /* STORE_KEY_FATAL */
740
dbug_tmp_restore_column_map(table->write_set, old_map);
741
null_key= to_field->is_null() || item->null_value;
742
return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL :
743
(store_key_result) res);
748
class store_key_const_item :public store_key_item
752
store_key_const_item(THD *thd, Field *to_field_arg, uchar *ptr,
753
uchar *null_ptr_arg, uint length,
755
:store_key_item(thd, to_field_arg,ptr,
756
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
757
&err : (uchar*) 0, length, item_arg), inited(0)
760
const char *name() const { return "const"; }
763
enum store_key_result copy_inner()
769
if ((res= item->save_in_field(to_field, 1)))
772
err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */
775
Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
776
we need to check for errors executing it and react accordingly
778
if (!err && to_field->table->in_use->is_error())
779
err= 1; /* STORE_KEY_FATAL */
781
null_key= to_field->is_null() || item->null_value;
782
return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
786
bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
787
bool error_if_full_join(JOIN *join);
788
int report_error(TABLE *table, int error);
789
int safe_index_read(JOIN_TAB *tab);
790
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
792
inline bool optimizer_flag(THD *thd, uint flag)
794
return (thd->variables.optimizer_switch & flag);