item_subselect.h 14.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* subselect Item */

19
#ifdef USE_PRAGMA_INTERFACE
20 21 22
#pragma interface			/* gcc class implementation */
#endif

unknown's avatar
unknown committed
23 24
class st_select_lex;
class st_select_lex_unit;
25 26
class JOIN;
class select_subselect;
unknown's avatar
unknown committed
27
class subselect_engine;
unknown's avatar
unknown committed
28 29
class Item_bool_func2;

unknown's avatar
unknown committed
30
/* base class for subselects */
31

unknown's avatar
unknown committed
32
class Item_subselect :public Item_result_field
33
{
unknown's avatar
unknown committed
34
  my_bool value_assigned; /* value already assigned to subselect */
35
protected:
36 37
  /* thread handler, will be assigned in fix_fields only */
  THD *thd;
unknown's avatar
unknown committed
38 39
  /* substitution instead of subselect in case of optimization */
  Item *substitution;
unknown's avatar
unknown committed
40 41
  /* unit of subquery */
  st_select_lex_unit *unit;
unknown's avatar
unknown committed
42
  /* engine that perform execution of subselect (single select or union) */
43
  subselect_engine *engine;
unknown's avatar
unknown committed
44 45
  /* old engine if engine was changed */
  subselect_engine *old_engine;
46
  /* cache of used external tables */
47
  table_map used_tables_cache;
unknown's avatar
unknown committed
48
  /* allowed number of columns (1 for single value subqueries) */
unknown's avatar
unknown committed
49
  uint max_columns;
50 51
  /* where subquery is placed */
  enum_parsing_place parsing_place;
52 53
  /* work with 'substitution' */
  bool have_to_be_excluded;
unknown's avatar
unknown committed
54
  /* cache of constant state */
55
  bool const_item_cache;
56 57

public:
58 59
  /* changed engine indicator */
  bool engine_changed;
unknown's avatar
unknown committed
60 61
  /* subquery is transformed */
  bool changed;
62

63 64 65
  /* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */
  bool is_correlated; 

66
  enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
67
  enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
68
		  EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS};
69

70 71
  Item_subselect();

72 73
  virtual subs_type substype() { return UNKNOWN_SUBS; }

74
  /*
75 76 77 78
     We need this method, because some compilers do not allow 'this'
     pointer in constructor initialization list, but we need pass pointer
     to subselect Item class to select_subselect classes constructor.
  */
79
  virtual void init (st_select_lex *select_lex,
unknown's avatar
unknown committed
80
		     select_subselect *result);
81

unknown's avatar
unknown committed
82
  ~Item_subselect();
unknown's avatar
unknown committed
83
  void cleanup();
84
  virtual void reset()
unknown's avatar
unknown committed
85 86 87
  {
    null_value= 1;
  }
unknown's avatar
unknown committed
88
  virtual trans_res select_transformer(JOIN *join);
unknown's avatar
unknown committed
89 90
  bool assigned() { return value_assigned; }
  void assigned(bool a) { value_assigned= a; }
91
  enum Type type() const;
unknown's avatar
unknown committed
92 93
  bool is_null()
  {
94
    update_null_value();
unknown's avatar
unknown committed
95 96
    return null_value;
  }
97
  bool fix_fields(THD *thd, Item **ref);
98
  virtual bool exec(bool full_scan);
99
  virtual void fix_length_and_dec();
unknown's avatar
unknown committed
100
  table_map used_tables() const;
unknown's avatar
unknown committed
101
  table_map not_null_tables() const { return 0; }
102
  bool const_item() const;
103 104
  inline table_map get_used_tables_cache() { return used_tables_cache; }
  inline bool get_const_item_cache() { return const_item_cache; }
unknown's avatar
unknown committed
105
  Item *get_tmp_table_item(THD *thd);
106
  void update_used_tables();
unknown's avatar
unknown committed
107
  void print(String *str);
108 109
  bool change_engine(subselect_engine *eng)
  {
unknown's avatar
unknown committed
110
    old_engine= engine;
111 112 113 114
    engine= eng;
    engine_changed= 1;
    return eng == 0;
  }
115 116 117 118 119
  /*
    True if this subquery has been already evaluated. Implemented only for
    single select and union subqueries only.
  */
  bool is_evaluated() const;
unknown's avatar
unknown committed
120
  bool is_uncacheable() const;
121

122 123 124 125 126
  /*
    Used by max/min subquery to initialize value presence registration
    mechanism. Engine call this method before rexecution query.
  */
  virtual void reset_value_registration() {}
127
  enum_parsing_place place() { return parsing_place; }
128 129

  friend class select_subselect;
unknown's avatar
unknown committed
130
  friend class Item_in_optimizer;
131
  friend bool Item_field::fix_fields(THD *, Item **);
132
  friend int  Item_field::fix_outer_field(THD *, Field **, Item **);
133
  friend bool Item_ref::fix_fields(THD *, Item **);
134 135 136
  friend void mark_select_range_as_dependent(THD*,
                                             st_select_lex*, st_select_lex*,
                                             Field*, Item*, Item_ident*);
137 138
};

unknown's avatar
unknown committed
139 140
/* single value subselect */

141
class Item_cache;
unknown's avatar
unknown committed
142
class Item_singlerow_subselect :public Item_subselect
unknown's avatar
unknown committed
143 144
{
protected:
145
  Item_cache *value, **row;
unknown's avatar
unknown committed
146
public:
147
  Item_singlerow_subselect(st_select_lex *select_lex);
148
  Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
149

unknown's avatar
unknown committed
150
  void cleanup();
151 152
  subs_type substype() { return SINGLEROW_SUBS; }

153
  void reset();
unknown's avatar
unknown committed
154
  trans_res select_transformer(JOIN *join);
155
  void store(uint i, Item* item);
156
  double val_real();
unknown's avatar
unknown committed
157 158
  longlong val_int ();
  String *val_str (String *);
unknown's avatar
unknown committed
159 160
  my_decimal *val_decimal(my_decimal *);
  bool val_bool();
161
  enum Item_result result_type() const;
162
  enum_field_types field_type() const;
163
  void fix_length_and_dec();
unknown's avatar
unknown committed
164

165
  uint cols();
166
  Item* el(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
167 168 169 170 171
  Item** addr(uint i) { return (Item**)row + i; }
  bool check_cols(uint c);
  bool null_inside();
  void bring_value();

unknown's avatar
unknown committed
172
  friend class select_singlerow_subselect;
unknown's avatar
unknown committed
173 174
};

unknown's avatar
unknown committed
175
/* used in static ALL/ANY optimization */
176
class select_max_min_finder_subselect;
177
class Item_maxmin_subselect :public Item_singlerow_subselect
178
{
179
protected:
unknown's avatar
unknown committed
180
  bool max;
unknown's avatar
unknown committed
181
  bool was_values;  // Set if we have found at least one row
182
public:
unknown's avatar
unknown committed
183
  Item_maxmin_subselect(THD *thd, Item_subselect *parent,
184
			st_select_lex *select_lex, bool max);
unknown's avatar
unknown committed
185
  void print(String *str);
186 187 188 189
  void cleanup();
  bool any_value() { return was_values; }
  void register_value() { was_values= TRUE; }
  void reset_value_registration() { was_values= FALSE; }
190 191
};

unknown's avatar
unknown committed
192 193 194 195 196
/* exists subselect */

class Item_exists_subselect :public Item_subselect
{
protected:
unknown's avatar
unknown committed
197
  bool value; /* value of this item (boolean: exists/not-exists) */
unknown's avatar
unknown committed
198 199

public:
200
  Item_exists_subselect(st_select_lex *select_lex);
unknown's avatar
unknown committed
201 202
  Item_exists_subselect(): Item_subselect() {}

203
  subs_type substype() { return EXISTS_SUBS; }
204
  void reset() 
unknown's avatar
unknown committed
205 206 207 208
  {
    value= 0;
  }

unknown's avatar
unknown committed
209 210
  enum Item_result result_type() const { return INT_RESULT;}
  longlong val_int();
211
  double val_real();
unknown's avatar
unknown committed
212
  String *val_str(String*);
unknown's avatar
unknown committed
213 214
  my_decimal *val_decimal(my_decimal *);
  bool val_bool();
215
  void fix_length_and_dec();
unknown's avatar
unknown committed
216
  void print(String *str);
217

unknown's avatar
unknown committed
218
  friend class select_exists_subselect;
219 220
  friend class subselect_uniquesubquery_engine;
  friend class subselect_indexsubquery_engine;
unknown's avatar
unknown committed
221
};
unknown's avatar
unknown committed
222

223 224 225 226 227 228 229 230 231 232 233 234 235 236

/*
  IN subselect: this represents "left_exr IN (SELECT ...)"

  This class has: 
   - (as a descendant of Item_subselect) a "subquery execution engine" which 
      allows it to evaluate subqueries. (and this class participates in
      execution by having was_null variable where part of execution result
      is stored.
   - Transformation methods (todo: more on this).

  This class is not used directly, it is "wrapped" into Item_in_optimizer
  which provides some small bits of subquery evaluation.
*/
unknown's avatar
unknown committed
237 238 239

class Item_in_subselect :public Item_exists_subselect
{
unknown's avatar
unknown committed
240
protected:
241
  Item *left_expr;
242
  /*
unknown's avatar
unknown committed
243
    expr & optimizer used in subselect rewriting to store Item for
244 245 246 247
    all JOIN in UNION
  */
  Item *expr;
  Item_in_optimizer *optimizer;
248
  bool was_null;
249
  bool abort_on_null;
unknown's avatar
unknown committed
250
  bool transformed;
unknown's avatar
unknown committed
251
public:
252 253
  /* Used to trigger on/off conditions that were pushed down to subselect */
  bool enable_pushed_conds;
254
  Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
255

256
  Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
257
  Item_in_subselect()
258
    :Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
259
     enable_pushed_conds(TRUE), upper_item(0)
unknown's avatar
unknown committed
260
  {}
261 262

  subs_type substype() { return IN_SUBS; }
263 264 265 266 267 268
  void reset() 
  {
    value= 0;
    null_value= 0;
    was_null= 0;
  }
unknown's avatar
unknown committed
269
  trans_res select_transformer(JOIN *join);
270 271
  trans_res select_in_like_transformer(JOIN *join, Comp_creator *func);
  trans_res single_value_transformer(JOIN *join, Comp_creator *func);
unknown's avatar
unknown committed
272
  trans_res row_value_transformer(JOIN * join);
273
  longlong val_int();
274
  double val_real();
275
  String *val_str(String*);
unknown's avatar
unknown committed
276 277
  my_decimal *val_decimal(my_decimal *);
  bool val_bool();
278
  void top_level_item() { abort_on_null=1; }
279
  inline bool is_top_level_item() { return abort_on_null; }
280
  bool test_limit(st_select_lex_unit *unit);
unknown's avatar
unknown committed
281
  void print(String *str);
282
  bool fix_fields(THD *thd, Item **ref);
283 284

  friend class Item_ref_null_helper;
285
  friend class Item_is_not_null_test;
286
  friend class subselect_indexsubquery_engine;
unknown's avatar
unknown committed
287 288
};

289

unknown's avatar
unknown committed
290 291 292 293
/* ALL/ANY/SOME subselect */
class Item_allany_subselect :public Item_in_subselect
{
public:
294 295
  chooser_compare_func_creator func_creator;
  Comp_creator *func;
unknown's avatar
unknown committed
296 297
  bool all;

298 299
  Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc,
                        st_select_lex *select_lex, bool all);
300

301
  // only ALL subquery has upper not
302
  subs_type substype() { return all?ALL_SUBS:ANY_SUBS; }
unknown's avatar
unknown committed
303
  trans_res select_transformer(JOIN *join);
unknown's avatar
unknown committed
304
  void print(String *str);
unknown's avatar
unknown committed
305 306
};

307

unknown's avatar
unknown committed
308
class subselect_engine: public Sql_alloc
unknown's avatar
unknown committed
309 310 311 312 313
{
protected:
  select_subselect *result; /* results storage class */
  THD *thd; /* pointer to current THD */
  Item_subselect *item; /* item, that use this engine */
314
  enum Item_result res_type; /* type of results */
315
  enum_field_types res_field_type; /* column type of the results */
unknown's avatar
unknown committed
316
  bool maybe_null; /* may be null (first item in select) */
unknown's avatar
unknown committed
317 318
public:

319 320
  subselect_engine(Item_subselect *si, select_subselect *res)
    :thd(0)
unknown's avatar
unknown committed
321 322 323
  {
    result= res;
    item= si;
324
    res_type= STRING_RESULT;
325
    res_field_type= FIELD_TYPE_VAR_STRING;
unknown's avatar
unknown committed
326
    maybe_null= 0;
unknown's avatar
unknown committed
327
  }
unknown's avatar
unknown committed
328
  virtual ~subselect_engine() {}; // to satisfy compiler
unknown's avatar
unknown committed
329
  virtual void cleanup()= 0;
330

331 332 333 334 335
  /*
    Also sets "thd" for subselect_engine::result.
    Should be called before prepare().
  */
  void set_thd(THD *thd_arg);
336
  THD * get_thd() { return thd; }
unknown's avatar
unknown committed
337
  virtual int prepare()= 0;
338
  virtual void fix_length_and_dec(Item_cache** row)= 0;
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
  /*
    Execute the engine

    SYNOPSIS
      exec()
        full_scan TRUE  - Pushed-down predicates are disabled, the engine
                          must disable made based on those predicates.
                  FALSE - Pushed-down predicates are in effect.
    DESCRIPTION
      Execute the engine. The result of execution is subquery value that is
      either captured by previously set up select_result-based 'sink' or
      stored somewhere by the exec() method itself.

      A required side effect: if full_scan==TRUE, subselect_engine->no_rows()
      should return correct result.

    RETURN
      0 - OK
      1 - Either an execution error, or the engine was be "changed", and
          caller should call exec() again for the new engine.
  */
  virtual int exec(bool full_scan)= 0;
unknown's avatar
unknown committed
361
  virtual uint cols()= 0; /* return number of columns in select */
362
  virtual uint8 uncacheable()= 0; /* query is uncacheable */
363
  enum Item_result type() { return res_type; }
364
  enum_field_types field_type() { return res_field_type; }
unknown's avatar
unknown committed
365
  virtual void exclude()= 0;
unknown's avatar
unknown committed
366
  bool may_be_null() { return maybe_null; };
367 368
  virtual table_map upper_select_const_tables()= 0;
  static table_map calc_const_tables(TABLE_LIST *);
unknown's avatar
unknown committed
369
  virtual void print(String *str)= 0;
unknown's avatar
unknown committed
370
  virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
371
  virtual bool no_tables()= 0;
372
  virtual bool is_executed() const { return FALSE; }
373 374
  /* Check if subquery produced any rows during last query execution */
  virtual bool no_rows() = 0;
375 376 377

protected:
  void set_row(List<Item> &item_list, Item_cache **row);
unknown's avatar
unknown committed
378 379
};

380

unknown's avatar
unknown committed
381 382
class subselect_single_select_engine: public subselect_engine
{
unknown's avatar
unknown committed
383
  my_bool prepared; /* simple subselect is prepared */
unknown's avatar
unknown committed
384
  my_bool optimized; /* simple subselect is optimized */
unknown's avatar
unknown committed
385
  my_bool executed; /* simple subselect is executed */
unknown's avatar
unknown committed
386 387 388
  st_select_lex *select_lex; /* corresponding select_lex */
  JOIN * join; /* corresponding JOIN structure */
public:
389
  subselect_single_select_engine(st_select_lex *select,
unknown's avatar
unknown committed
390 391
				 select_subselect *result,
				 Item_subselect *item);
unknown's avatar
unknown committed
392
  void cleanup();
unknown's avatar
unknown committed
393
  int prepare();
394
  void fix_length_and_dec(Item_cache** row);
395
  int exec(bool full_scan);
unknown's avatar
unknown committed
396
  uint cols();
397
  uint8 uncacheable();
unknown's avatar
unknown committed
398
  void exclude();
399
  table_map upper_select_const_tables();
unknown's avatar
unknown committed
400
  void print (String *str);
unknown's avatar
unknown committed
401
  bool change_result(Item_subselect *si, select_subselect *result);
402
  bool no_tables();
403
  bool is_executed() const { return executed; }
404
  bool no_rows();
unknown's avatar
unknown committed
405 406
};

407

unknown's avatar
unknown committed
408 409 410 411
class subselect_union_engine: public subselect_engine
{
  st_select_lex_unit *unit;  /* corresponding unit structure */
public:
412
  subselect_union_engine(st_select_lex_unit *u,
unknown's avatar
unknown committed
413 414
			 select_subselect *result,
			 Item_subselect *item);
unknown's avatar
unknown committed
415
  void cleanup();
unknown's avatar
unknown committed
416
  int prepare();
417
  void fix_length_and_dec(Item_cache** row);
418
  int exec(bool full_scan);
unknown's avatar
unknown committed
419
  uint cols();
420
  uint8 uncacheable();
unknown's avatar
unknown committed
421
  void exclude();
422
  table_map upper_select_const_tables();
unknown's avatar
unknown committed
423
  void print (String *str);
unknown's avatar
unknown committed
424
  bool change_result(Item_subselect *si, select_subselect *result);
425
  bool no_tables();
426
  bool is_executed() const;
427
  bool no_rows();
unknown's avatar
unknown committed
428
};
429

430

431
struct st_join_table;
432
class subselect_uniquesubquery_engine: public subselect_engine
433
{
434
protected:
435 436
  st_join_table *tab;
  Item *cond;
437 438 439 440 441 442
  /* 
    TRUE<=> last execution produced empty set. Valid only when left
    expression is NULL.
  */
  bool empty_result_set;
  bool null_keypart; /* TRUE <=> constructed search tuple has a NULL */
443 444
public:

445
  // constructor can assign THD because it will be called after JOIN::prepare
446
  subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg,
447
				  Item_subselect *subs, Item *where)
448 449
    :subselect_engine(subs, 0), tab(tab_arg), cond(where)
  {
450
    set_thd(thd_arg);
451
  }
452
  ~subselect_uniquesubquery_engine();
unknown's avatar
unknown committed
453
  void cleanup();
454 455
  int prepare();
  void fix_length_and_dec(Item_cache** row);
456
  int exec(bool full_scan);
457
  uint cols() { return 1; }
458
  uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
459
  void exclude();
460
  table_map upper_select_const_tables() { return 0; }
unknown's avatar
unknown committed
461
  void print (String *str);
unknown's avatar
unknown committed
462
  bool change_result(Item_subselect *si, select_subselect *result);
463
  bool no_tables();
464 465 466
  int scan_table();
  bool copy_ref_key();
  bool no_rows() { return empty_result_set; }
467 468
};

469

470
class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
471
{
472
  /* FALSE for 'ref', TRUE for 'ref-or-null'. */
473
  bool check_null;
474
public:
475 476

  // constructor can assign THD because it will be called after JOIN::prepare
477 478 479 480
  subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
				 Item_subselect *subs, Item *where,
				 bool chk_null)
    :subselect_uniquesubquery_engine(thd, tab_arg, subs, where),
481
     check_null(chk_null)
482
  {}
483
  int exec(bool full_scan);
unknown's avatar
unknown committed
484
  void print (String *str);
485
};
486 487 488 489 490 491 492


inline bool Item_subselect::is_evaluated() const
{
  return engine->is_executed();
}

unknown's avatar
unknown committed
493 494 495 496 497 498
inline bool Item_subselect::is_uncacheable() const
{
  return engine->uncacheable();
}