Drizzled Public API Documentation

subselect.h
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #pragma once
00021 
00022 #include <drizzled/comp_creator.h>
00023 #include <drizzled/item/ref.h>
00024 #include <drizzled/item/field.h>
00025 #include <drizzled/item/bin_string.h>
00026 #include <drizzled/util/test.h>
00027 
00028 namespace drizzled {
00029 
00030 class Item_subselect : public Item_result_field
00031 {
00032   bool value_assigned; /* value already assigned to subselect */
00033 public:
00034   /* thread handler, will be assigned in fix_fields only */
00035   Session *session;
00036   /* substitution instead of subselect in case of optimization */
00037   Item *substitution;
00038   /* unit of subquery */
00039   Select_Lex_Unit *unit;
00040 protected:
00041   /* engine that perform execution of subselect (single select or union) */
00042   subselect_engine *engine;
00043   /* old engine if engine was changed */
00044   subselect_engine *old_engine;
00045   /* cache of used external tables */
00046   table_map used_tables_cache;
00047   /* allowed number of columns (1 for single value subqueries) */
00048   uint32_t max_columns;
00049   /* where subquery is placed */
00050   enum_parsing_place parsing_place;
00051   /* work with 'substitution' */
00052   bool have_to_be_excluded;
00053   /* cache of constant state */
00054   bool const_item_cache;
00055 
00056 public:
00057   /* changed engine indicator */
00058   bool engine_changed;
00059   /* subquery is transformed */
00060   bool changed;
00061 
00062   /* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */
00063   bool is_correlated;
00064 
00065   enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
00066   enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
00067       EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS};
00068 
00069   Item_subselect();
00070 
00071   virtual subs_type substype() { return UNKNOWN_SUBS; }
00072 
00073   /*
00074     We need this method, because some compilers do not allow 'this'
00075     pointer in constructor initialization list, but we need to pass a pointer
00076     to subselect Item class to select_result_interceptor's constructor.
00077   */
00078   virtual void init (Select_Lex *select_lex,
00079          select_result_interceptor *result);
00080 
00081   ~Item_subselect();
00082   void cleanup();
00083   virtual void reset()
00084   {
00085     null_value= 1;
00086   }
00087   virtual trans_res select_transformer(Join *join);
00088   bool assigned() { return value_assigned; }
00089   void assigned(bool a) { value_assigned= a; }
00090   enum Type type() const;
00091   bool is_null()
00092   {
00093     update_null_value();
00094     return null_value;
00095   }
00096   bool fix_fields(Session *session, Item **ref);
00097   virtual bool exec();
00098   virtual void fix_length_and_dec();
00099   table_map used_tables() const;
00100   table_map not_null_tables() const { return 0; }
00101   bool const_item() const;
00102   inline table_map get_used_tables_cache() { return used_tables_cache; }
00103   inline bool get_const_item_cache() { return const_item_cache; }
00104   Item *get_tmp_table_item(Session *session);
00105   void update_used_tables();
00106   virtual void print(String *str);
00107   virtual bool have_guarded_conds() { return false; }
00108   bool change_engine(subselect_engine *eng)
00109   {
00110     old_engine= engine;
00111     engine= eng;
00112     engine_changed= 1;
00113     return eng == 0;
00114   }
00115   /*
00116     True if this subquery has been already evaluated. Implemented only for
00117     single select and union subqueries only.
00118   */
00119   bool is_evaluated() const;
00120   bool is_uncacheable() const;
00121 
00122   /*
00123     Used by max/min subquery to initialize value presence registration
00124     mechanism. Engine call this method before rexecution query.
00125   */
00126   virtual void reset_value_registration() {}
00127   enum_parsing_place place() { return parsing_place; }
00128   bool walk(Item_processor processor, bool walk_subquery, unsigned char *arg);
00129 
00134   Select_Lex* get_select_lex();
00135 
00136   friend class select_result_interceptor;
00137   friend class Item_in_optimizer;
00138   friend bool Item_field::fix_fields(Session *, Item **);
00139   friend int  Item_field::fix_outer_field(Session *, Field **, Item **);
00140   friend bool Item_ref::fix_fields(Session *, Item **);
00141   friend void mark_select_range_as_dependent(Session*,
00142                                              Select_Lex*, Select_Lex*,
00143                                              Field*, Item*, Item_ident*);
00144 };
00145 
00146 /* single value subselect */
00147 
00148 class Item_singlerow_subselect :public Item_subselect
00149 {
00150 protected:
00151   Item_cache *value, **row;
00152 public:
00153   Item_singlerow_subselect(Select_Lex *select_lex);
00154   Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
00155 
00156   void cleanup();
00157   subs_type substype() { return SINGLEROW_SUBS; }
00158 
00159   void reset();
00160   trans_res select_transformer(Join *join);
00161   void store(uint32_t i, Item* item);
00162   double val_real();
00163   int64_t val_int ();
00164   String *val_str (String *);
00165   type::Decimal *val_decimal(type::Decimal *);
00166   bool val_bool();
00167   enum Item_result result_type() const;
00168   enum_field_types field_type() const;
00169   void fix_length_and_dec();
00170 
00171   uint32_t cols();
00172   Item* element_index(uint32_t i) { return reinterpret_cast<Item*>(row[i]); }
00173   Item** addr(uint32_t i) { return (Item**)row + i; }
00174   bool check_cols(uint32_t c);
00175   bool null_inside();
00176   void bring_value();
00177 
00190   Select_Lex* invalidate_and_restore_select_lex();
00191 
00192   friend class select_singlerow_subselect;
00193 };
00194 
00195 /* used in static ALL/ANY optimization */
00196 class Item_maxmin_subselect :public Item_singlerow_subselect
00197 {
00198 protected:
00199   bool max;
00200   bool was_values;  // Set if we have found at least one row
00201 public:
00202   Item_maxmin_subselect(Session *session, Item_subselect *parent,
00203       Select_Lex *select_lex, bool max);
00204   virtual void print(String *str);
00205   void cleanup();
00206   bool any_value() { return was_values; }
00207   void register_value() { was_values= true; }
00208   void reset_value_registration() { was_values= false; }
00209 };
00210 
00211 /* exists subselect */
00212 
00213 class Item_exists_subselect :public Item_subselect
00214 {
00215 protected:
00216   bool value; /* value of this item (boolean: exists/not-exists) */
00217 
00218 public:
00219   Item_exists_subselect(Select_Lex *select_lex);
00220   Item_exists_subselect(): Item_subselect() {}
00221 
00222   subs_type substype() { return EXISTS_SUBS; }
00223   void reset()
00224   {
00225     value= 0;
00226   }
00227 
00228   enum Item_result result_type() const { return INT_RESULT;}
00229   int64_t val_int();
00230   double val_real();
00231   String *val_str(String*);
00232   type::Decimal *val_decimal(type::Decimal *);
00233   bool val_bool();
00234   void fix_length_and_dec();
00235   virtual void print(String *str);
00236 
00237   friend class select_exists_subselect;
00238   friend class subselect_uniquesubquery_engine;
00239   friend class subselect_indexsubquery_engine;
00240 };
00241 
00242 
00258 class Item_in_subselect :public Item_exists_subselect
00259 {
00260 public:
00261   Item *left_expr;
00262 protected:
00263   /*
00264     Cache of the left operand of the subquery predicate. Allocated in the
00265     runtime memory root, for each execution, thus need not be freed.
00266   */
00267   List<Cached_item> *left_expr_cache;
00268   bool first_execution;
00269 
00270   /*
00271     expr & optimizer used in subselect rewriting to store Item for
00272     all JOIN in UNION
00273   */
00274   Item *expr;
00275   Item_in_optimizer *optimizer;
00276   bool was_null;
00277   bool abort_on_null;
00278 
00279 public:
00280   /* Used to trigger on/off conditions that were pushed down to subselect */
00281   bool *pushed_cond_guards;
00282 
00283   /* Priority of this predicate in the convert-to-semi-join-nest process. */
00284   int sj_convert_priority;
00285 
00286   /*
00287     Location of the subquery predicate. It is either
00288      - pointer to join nest if the subquery predicate is in the ON expression
00289      - (TableList*)1 if the predicate is in the WHERE.
00290   */
00291   TableList *expr_join_nest;
00292 
00293   /* The method chosen to execute the IN predicate.  */
00294   enum enum_exec_method {
00295     NOT_TRANSFORMED, /* No execution method was chosen for this IN. */
00296     SEMI_JOIN,   /* IN was converted to semi-join nest and should be removed. */
00297     IN_TO_EXISTS, /* IN was converted to correlated EXISTS. */
00298     MATERIALIZATION /* IN will be executed via subquery materialization. */
00299   };
00300   enum_exec_method exec_method;
00301 
00302   bool *get_cond_guard(int i)
00303   {
00304     return pushed_cond_guards ? pushed_cond_guards + i : NULL;
00305   }
00306   void set_cond_guard_var(int i, bool v)
00307   {
00308     if ( pushed_cond_guards)
00309       pushed_cond_guards[i]= v;
00310   }
00311   bool have_guarded_conds() { return test(pushed_cond_guards); }
00312 
00313   Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
00314 
00315   Item_in_subselect(Item * left_expr, Select_Lex *select_lex);
00316   Item_in_subselect()
00317     :
00318       Item_exists_subselect(),
00319       left_expr(NULL),
00320       left_expr_cache(NULL),
00321       first_execution(true),
00322       optimizer(NULL),
00323       abort_on_null(false),
00324       pushed_cond_guards(NULL),
00325       sj_convert_priority(0),
00326       expr_join_nest(NULL),
00327       exec_method(NOT_TRANSFORMED),
00328       upper_item(NULL)
00329   {}
00330   void cleanup();
00331   subs_type substype() { return IN_SUBS; }
00332   void reset()
00333   {
00334     value= 0;
00335     null_value= 0;
00336     was_null= 0;
00337   }
00338   trans_res select_transformer(Join *join);
00339   trans_res select_in_like_transformer(Join *join, const Comp_creator *func);
00340   trans_res single_value_transformer(Join *join, const Comp_creator *func);
00341   trans_res row_value_transformer(Join * join);
00342   trans_res single_value_in_to_exists_transformer(Join * join,
00343                                                   const Comp_creator *func);
00344   trans_res row_value_in_to_exists_transformer(Join * join);
00345   virtual bool exec();
00346   int64_t val_int();
00347   double val_real();
00348   String *val_str(String*);
00349   type::Decimal *val_decimal(type::Decimal *);
00350   void update_null_value () { (void) val_bool(); }
00351   bool val_bool();
00352   void top_level_item() { abort_on_null=1; }
00353   inline bool is_top_level_item() { return abort_on_null; }
00354   bool test_limit(Select_Lex_Unit *unit);
00355   virtual void print(String *str);
00356   bool fix_fields(Session *session, Item **ref);
00357   bool setup_engine();
00358   bool init_left_expr_cache();
00359   bool is_expensive_processor(unsigned char *arg);
00360 
00361   friend class Item_ref_null_helper;
00362   friend class Item_is_not_null_test;
00363   friend class Item_in_optimizer;
00364   friend class subselect_indexsubquery_engine;
00365   friend class subselect_hash_sj_engine;
00366 };
00367 
00368 
00369 /* ALL/ANY/SOME subselect */
00370 class Item_allany_subselect :public Item_in_subselect
00371 {
00372 public:
00373   chooser_compare_func_creator func_creator;
00374   Comp_creator *func;
00375   bool all;
00376 
00377   Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc,
00378                         Select_Lex *select_lex, bool all);
00379 
00380   // only ALL subquery has upper not
00381   subs_type substype() { return all?ALL_SUBS:ANY_SUBS; }
00382   trans_res select_transformer(Join *join);
00383   virtual void print(String *str);
00384 };
00385 
00386 
00387 class subselect_engine: public memory::SqlAlloc
00388 {
00389 protected:
00390   select_result_interceptor *result; /* results storage class */
00391   Session *session; /* pointer to current Session */
00392   Item_subselect *item; /* item, that use this engine */
00393   enum Item_result res_type; /* type of results */
00394   enum_field_types res_field_type; /* column type of the results */
00395   bool maybe_null; /* may be null (first item in select) */
00396 public:
00397 
00398   enum enum_engine_type {ABSTRACT_ENGINE, SINGLE_SELECT_ENGINE,
00399                          UNION_ENGINE, UNIQUESUBQUERY_ENGINE,
00400                          INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE};
00401 
00402   subselect_engine(Item_subselect *si, select_result_interceptor *res)
00403     :session(NULL)
00404   {
00405     result= res;
00406     item= si;
00407     res_type= STRING_RESULT;
00408     res_field_type= DRIZZLE_TYPE_VARCHAR;
00409     maybe_null= 0;
00410   }
00411   virtual ~subselect_engine() {} // to satisfy compiler
00412   virtual void cleanup()= 0;
00413 
00414   /*
00415     Also sets "session" for subselect_engine::result.
00416     Should be called before prepare().
00417   */
00418   void set_session(Session *session_arg);
00419   Session * get_session() { return session; }
00420   virtual int prepare()= 0;
00421   virtual void fix_length_and_dec(Item_cache** row)= 0;
00422   /*
00423     Execute the engine
00424 
00425     SYNOPSIS
00426       exec()
00427 
00428     DESCRIPTION
00429       Execute the engine. The result of execution is subquery value that is
00430       either captured by previously set up select_result-based 'sink' or
00431       stored somewhere by the exec() method itself.
00432 
00433       A required side effect: If at least one pushed-down predicate is
00434       disabled, subselect_engine->no_rows() must return correct result after
00435       the exec() call.
00436 
00437     RETURN
00438       0 - OK
00439       1 - Either an execution error, or the engine was "changed", and the
00440           caller should call exec() again for the new engine.
00441   */
00442   virtual int exec()= 0;
00443   virtual uint32_t cols()= 0; /* return number of columns in select */
00444   virtual bool uncacheable()= 0; /* query is uncacheable */
00445   virtual bool uncacheable(uint32_t bit_pos)= 0; /* query is uncacheable */
00446   enum Item_result type() { return res_type; }
00447   enum_field_types field_type() { return res_field_type; }
00448   virtual void exclude()= 0;
00449   virtual bool may_be_null() { return maybe_null; }
00450   virtual table_map upper_select_const_tables()= 0;
00451   static table_map calc_const_tables(TableList *);
00452   virtual void print(String *str)= 0;
00453   virtual bool change_result(Item_subselect *si,
00454                              select_result_interceptor *result)= 0;
00455   virtual bool no_tables()= 0;
00456   virtual bool is_executed() const { return false; }
00457   /* Check if subquery produced any rows during last query execution */
00458   virtual bool no_rows() = 0;
00459   virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
00460 
00461 protected:
00462   void set_row(List<Item> &item_list, Item_cache **row);
00463 };
00464 
00465 
00466 class subselect_single_select_engine: public subselect_engine
00467 {
00468   bool prepared; /* simple subselect is prepared */
00469   bool optimized; /* simple subselect is optimized */
00470   bool executed; /* simple subselect is executed */
00471   Select_Lex *select_lex; /* corresponding select_lex */
00472   Join * join; /* corresponding JOIN structure */
00473 public:
00474   subselect_single_select_engine(Select_Lex *select,
00475          select_result_interceptor *result,
00476          Item_subselect *item);
00477   void cleanup();
00478   int prepare();
00479   void fix_length_and_dec(Item_cache** row);
00480   int exec();
00481   uint32_t cols();
00482   bool uncacheable();
00483   bool uncacheable(uint32_t bit_pos);
00484   void exclude();
00485   table_map upper_select_const_tables();
00486   virtual void print (String *str);
00487   bool change_result(Item_subselect *si, select_result_interceptor *result);
00488   bool no_tables();
00489   bool may_be_null();
00490   bool is_executed() const { return executed; }
00491   bool no_rows();
00492   virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
00493   void save_join_if_explain();
00494 
00495   friend class subselect_hash_sj_engine;
00496   friend class Item_in_subselect;
00497 };
00498 
00499 
00500 class subselect_union_engine: public subselect_engine
00501 {
00502   Select_Lex_Unit *unit;  /* corresponding unit structure */
00503 public:
00504   subselect_union_engine(Select_Lex_Unit *u,
00505        select_result_interceptor *result,
00506        Item_subselect *item);
00507   void cleanup();
00508   int prepare();
00509   void fix_length_and_dec(Item_cache** row);
00510   int exec();
00511   uint32_t cols();
00512   bool uncacheable();
00513   bool uncacheable(uint32_t bit_pos);
00514   void exclude();
00515   table_map upper_select_const_tables();
00516   virtual void print (String *str);
00517   bool change_result(Item_subselect *si, select_result_interceptor *result);
00518   bool no_tables();
00519   bool is_executed() const;
00520   bool no_rows();
00521   virtual enum_engine_type engine_type() { return UNION_ENGINE; }
00522 };
00523 
00524 
00525 /*
00526   A subquery execution engine that evaluates the subquery by doing one index
00527   lookup in a unique index.
00528 
00529   This engine is used to resolve subqueries in forms
00530 
00531     outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
00532 
00533   or, tuple-based:
00534 
00535     (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
00536                       FROM tbl WHERE subqwhere)
00537 
00538   i.e. the subquery is a single table SELECT without GROUP BY, aggregate
00539   functions, etc.
00540 */
00541 
00542 class subselect_uniquesubquery_engine: public subselect_engine
00543 {
00544 protected:
00545   JoinTable *tab;
00546   Item *cond; /* The WHERE condition of subselect */
00547   /*
00548     TRUE<=> last execution produced empty set. Valid only when left
00549     expression is NULL.
00550   */
00551   bool empty_result_set;
00552   bool null_keypart; /* TRUE <=> constructed search tuple has a NULL */
00553 public:
00554 
00555   // constructor can assign Session because it will be called after Join::prepare
00556   subselect_uniquesubquery_engine(Session *session_arg, JoinTable *tab_arg,
00557           Item_subselect *subs, Item *where)
00558     :subselect_engine(subs, 0), tab(tab_arg), cond(where)
00559   {
00560     set_session(session_arg);
00561   }
00562   void cleanup();
00563   int prepare();
00564   void fix_length_and_dec(Item_cache** row);
00565   int exec();
00566   uint32_t cols() { return 1; }
00567   bool uncacheable() { return true; }
00568   bool uncacheable(uint32_t) { return true; }
00569   void exclude();
00570   table_map upper_select_const_tables() { return 0; }
00571   virtual void print (String *str);
00572   bool change_result(Item_subselect *si, select_result_interceptor *result);
00573   bool no_tables();
00574   int scan_table();
00575   bool copy_ref_key();
00576   bool no_rows() { return empty_result_set; }
00577   virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
00578 };
00579 
00580 
00581 class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
00582 {
00583   /* FALSE for 'ref', TRUE for 'ref-or-null'. */
00584   bool check_null;
00585   /*
00586     The "having" clause. This clause (further reffered to as "artificial
00587     having") was inserted by subquery transformation code. It contains
00588     Item(s) that have a side-effect: they record whether the subquery has
00589     produced a row with NULL certain components. We need to use it for cases
00590     like
00591       (oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
00592     where we do index lookup on t.key=oe1 but need also to check if there
00593     was a row such that t.no_key IS NULL.
00594 
00595     NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
00596     it should have been in uniquesubquery_engine in order to allow execution of
00597     subqueries like
00598 
00599       (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
00600 
00601     We could use uniquesubquery_engine for the first component and let
00602     Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
00603 
00604     However, subqueries like the above are currently not handled by index
00605     lookup-based subquery engines, the engine applicability check misses
00606     them: it doesn't switch the engine for case of artificial having and
00607     [eq_]ref access (only for artifical having + ref_or_null or no having).
00608     The above example subquery is handled as a full-blown SELECT with eq_ref
00609     access to one table.
00610 
00611     Due to this limitation, the "artificial having" currently needs to be
00612     checked by only in indexsubquery_engine.
00613   */
00614   Item *having;
00615 public:
00616 
00617   // constructor can assign Session because it will be called after Join::prepare
00618   subselect_indexsubquery_engine(Session *session_arg, JoinTable *tab_arg,
00619          Item_subselect *subs, Item *where,
00620                                  Item *having_arg, bool chk_null)
00621     :subselect_uniquesubquery_engine(session_arg, tab_arg, subs, where),
00622      check_null(chk_null),
00623      having(having_arg)
00624   {}
00625   int exec();
00626   virtual void print (String *str);
00627   virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; }
00628 };
00629 
00630 
00631 inline bool Item_subselect::is_evaluated() const
00632 {
00633   return engine->is_executed();
00634 }
00635 
00636 
00637 inline bool Item_subselect::is_uncacheable() const
00638 {
00639   return engine->uncacheable();
00640 }
00641 
00642 
00649 class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
00650 {
00651 protected:
00652   /* TRUE if the subquery was materialized into a temp table. */
00653   bool is_materialized;
00654   /*
00655     The old engine already chosen at parse time and stored in permanent memory.
00656     Through this member we can re-create and re-prepare materialize_join for
00657     each execution of a prepared statement. We akso resuse the functionality
00658     of subselect_single_select_engine::[prepare | cols].
00659   */
00660   subselect_single_select_engine *materialize_engine;
00661   /*
00662     QEP to execute the subquery and materialize its result into a
00663     temporary table. Created during the first call to exec().
00664   */
00665   Join *materialize_join;
00666   /* Temp table context of the outer select's JOIN. */
00667   Tmp_Table_Param *tmp_param;
00668 
00669 public:
00670   subselect_hash_sj_engine(Session *session_in, Item_subselect *in_predicate,
00671                                subselect_single_select_engine *old_engine)
00672     :subselect_uniquesubquery_engine(session_in, NULL, in_predicate, NULL),
00673     is_materialized(false), materialize_engine(old_engine),
00674     materialize_join(NULL), tmp_param(NULL)
00675   {}
00676   ~subselect_hash_sj_engine();
00677 
00678   bool init_permanent(List<Item> *tmp_columns);
00679   void init_runtime();
00680   void cleanup();
00681   int prepare() { return 0; }
00682   int exec();
00683   virtual void print (String *str);
00684   uint32_t cols()
00685   {
00686     return materialize_engine->cols();
00687   }
00688   virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; }
00689 };
00690 
00691 } /* namespace drizzled */
00692