Commit dfeac169 authored by unknown's avatar unknown

Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  mysql.com:/home/psergey/mysql-5.0-bug8804-r12


sql/item_cmpfunc.cc:
  Auto merged
sql/item_cmpfunc.h:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_select.cc:
  Auto merged
mysql-test/r/subselect.result:
  Manual Merge
parents bf124424 5f97dc6e
...@@ -9,7 +9,7 @@ insert into t2 values (1,1,1),(2,2,2),(3,3,3), (4,4,4), (5,5,5); ...@@ -9,7 +9,7 @@ insert into t2 values (1,1,1),(2,2,2),(3,3,3), (4,4,4), (5,5,5);
explain select * from t2 where p NOT IN (select p from t1); explain select * from t2 where p NOT IN (select p from t1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1
select * from t2 where p NOT IN (select p from t1) order by p; select * from t2 where p NOT IN (select p from t1) order by p;
p u o p u o
4 4 4 4 4 4
...@@ -17,7 +17,7 @@ p u o ...@@ -17,7 +17,7 @@ p u o
explain select * from t2 where p NOT IN (select u from t1); explain select * from t2 where p NOT IN (select u from t1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where
2 DEPENDENT SUBQUERY t1 unique_subquery u u 4 func 1 Using index 2 DEPENDENT SUBQUERY t1 unique_subquery u u 4 func 1
select * from t2 where p NOT IN (select u from t1) order by p; select * from t2 where p NOT IN (select u from t1) order by p;
p u o p u o
4 4 4 4 4 4
...@@ -25,7 +25,7 @@ p u o ...@@ -25,7 +25,7 @@ p u o
explain select * from t2 where p NOT IN (select o from t1); explain select * from t2 where p NOT IN (select o from t1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where
2 DEPENDENT SUBQUERY t1 index_subquery o o 4 func 1 Using index 2 DEPENDENT SUBQUERY t1 index_subquery o o 4 func 1
select * from t2 where p NOT IN (select o from t1) order by p; select * from t2 where p NOT IN (select o from t1) order by p;
p u o p u o
4 4 4 4 4 4
......
This diff is collapsed.
...@@ -126,11 +126,11 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -126,11 +126,11 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where 1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1 1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1 1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1
2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using where
3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using where
4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using where
5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where 5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using where
6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 func 1 Using index; Using where 6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 func 1 Using where
drop table t1, t2, t3, t4; drop table t1, t2, t3, t4;
CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB; CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB;
INSERT INTO t1 VALUES (1),(2); INSERT INTO t1 VALUES (1),(2);
......
This diff is collapsed.
This diff is collapsed.
...@@ -829,11 +829,35 @@ longlong Item_in_optimizer::val_int() ...@@ -829,11 +829,35 @@ longlong Item_in_optimizer::val_int()
We disable the predicates we've pushed down into subselect, run the We disable the predicates we've pushed down into subselect, run the
subselect and see if it has produced any rows. subselect and see if it has produced any rows.
*/ */
((Item_in_subselect*)args[1])->enable_pushed_conds= FALSE; Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
longlong tmp= args[1]->val_bool_result(); if (cache->cols() == 1)
result_for_null_param= null_value= {
!((Item_in_subselect*)args[1])->engine->no_rows(); item_subs->set_cond_guard_var(0, FALSE);
((Item_in_subselect*)args[1])->enable_pushed_conds= TRUE; longlong tmp= args[1]->val_bool_result();
result_for_null_param= null_value= !item_subs->engine->no_rows();
item_subs->set_cond_guard_var(0, TRUE);
}
else
{
uint i;
uint ncols= cache->cols();
/*
Turn off the predicates that are based on column compares for
which the left part is currently NULL
*/
for (i= 0; i < ncols; i++)
{
if (cache->el(i)->null_value)
item_subs->set_cond_guard_var(i, FALSE);
}
longlong tmp= args[1]->val_bool_result();
result_for_null_param= null_value= !item_subs->engine->no_rows();
/* Turn all predicates back on */
for (i= 0; i < ncols; i++)
item_subs->set_cond_guard_var(i, TRUE);
}
} }
} }
return 0; return 0;
......
...@@ -312,6 +312,7 @@ class Item_func_trig_cond: public Item_bool_func ...@@ -312,6 +312,7 @@ class Item_func_trig_cond: public Item_bool_func
enum Functype functype() const { return TRIG_COND_FUNC; }; enum Functype functype() const { return TRIG_COND_FUNC; };
const char *func_name() const { return "trigcond"; }; const char *func_name() const { return "trigcond"; };
bool const_item() const { return FALSE; } bool const_item() const { return FALSE; }
bool *get_trig_var() { return trig_var; }
}; };
class Item_func_not_all :public Item_func_not class Item_func_not_all :public Item_func_not
......
This diff is collapsed.
...@@ -94,7 +94,7 @@ class Item_subselect :public Item_result_field ...@@ -94,7 +94,7 @@ class Item_subselect :public Item_result_field
return null_value; return null_value;
} }
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
virtual bool exec(bool full_scan); virtual bool exec();
virtual void fix_length_and_dec(); virtual void fix_length_and_dec();
table_map used_tables() const; table_map used_tables() const;
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
...@@ -104,6 +104,7 @@ class Item_subselect :public Item_result_field ...@@ -104,6 +104,7 @@ class Item_subselect :public Item_result_field
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
void update_used_tables(); void update_used_tables();
void print(String *str); void print(String *str);
virtual bool have_guarded_conds() { return FALSE; }
bool change_engine(subselect_engine *eng) bool change_engine(subselect_engine *eng)
{ {
old_engine= engine; old_engine= engine;
...@@ -249,13 +250,21 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -249,13 +250,21 @@ class Item_in_subselect :public Item_exists_subselect
bool transformed; bool transformed;
public: public:
/* Used to trigger on/off conditions that were pushed down to subselect */ /* Used to trigger on/off conditions that were pushed down to subselect */
bool enable_pushed_conds; bool *pushed_cond_guards;
bool *get_cond_guard(int i)
{
return pushed_cond_guards ? pushed_cond_guards + i : NULL;
}
void set_cond_guard_var(int i, bool v) { pushed_cond_guards[i]= v; }
bool have_guarded_conds() { return test(pushed_cond_guards); }
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
Item_in_subselect(Item * left_expr, st_select_lex *select_lex); Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect() Item_in_subselect()
:Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0), :Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
enable_pushed_conds(TRUE), upper_item(0) pushed_cond_guards(NULL), upper_item(0)
{} {}
subs_type substype() { return IN_SUBS; } subs_type substype() { return IN_SUBS; }
...@@ -340,23 +349,22 @@ class subselect_engine: public Sql_alloc ...@@ -340,23 +349,22 @@ class subselect_engine: public Sql_alloc
SYNOPSIS SYNOPSIS
exec() 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 DESCRIPTION
Execute the engine. The result of execution is subquery value that is Execute the engine. The result of execution is subquery value that is
either captured by previously set up select_result-based 'sink' or either captured by previously set up select_result-based 'sink' or
stored somewhere by the exec() method itself. stored somewhere by the exec() method itself.
A required side effect: if full_scan==TRUE, subselect_engine->no_rows() A required side effect: If at least one pushed-down predicate is
should return correct result. disabled, subselect_engine->no_rows() must return correct result after
the exec() call.
RETURN RETURN
0 - OK 0 - OK
1 - Either an execution error, or the engine was be "changed", and 1 - Either an execution error, or the engine was "changed", and the
caller should call exec() again for the new engine. caller should call exec() again for the new engine.
*/ */
virtual int exec(bool full_scan)= 0; virtual int exec()= 0;
virtual uint cols()= 0; /* return number of columns in select */ virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */ virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; } enum Item_result type() { return res_type; }
...@@ -391,7 +399,7 @@ class subselect_single_select_engine: public subselect_engine ...@@ -391,7 +399,7 @@ class subselect_single_select_engine: public subselect_engine
void cleanup(); void cleanup();
int prepare(); int prepare();
void fix_length_and_dec(Item_cache** row); void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan); int exec();
uint cols(); uint cols();
uint8 uncacheable(); uint8 uncacheable();
void exclude(); void exclude();
...@@ -415,7 +423,7 @@ class subselect_union_engine: public subselect_engine ...@@ -415,7 +423,7 @@ class subselect_union_engine: public subselect_engine
void cleanup(); void cleanup();
int prepare(); int prepare();
void fix_length_and_dec(Item_cache** row); void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan); int exec();
uint cols(); uint cols();
uint8 uncacheable(); uint8 uncacheable();
void exclude(); void exclude();
...@@ -429,11 +437,30 @@ class subselect_union_engine: public subselect_engine ...@@ -429,11 +437,30 @@ class subselect_union_engine: public subselect_engine
struct st_join_table; struct st_join_table;
/*
A subquery execution engine that evaluates the subquery by doing one index
lookup in a unique index.
This engine is used to resolve subqueries in forms
outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
or, tuple-based:
(oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
FROM tbl WHERE subqwhere)
i.e. the subquery is a single table SELECT without GROUP BY, aggregate
functions, etc.
*/
class subselect_uniquesubquery_engine: public subselect_engine class subselect_uniquesubquery_engine: public subselect_engine
{ {
protected: protected:
st_join_table *tab; st_join_table *tab;
Item *cond; Item *cond; /* The WHERE condition of subselect */
/* /*
TRUE<=> last execution produced empty set. Valid only when left TRUE<=> last execution produced empty set. Valid only when left
expression is NULL. expression is NULL.
...@@ -453,7 +480,7 @@ class subselect_uniquesubquery_engine: public subselect_engine ...@@ -453,7 +480,7 @@ class subselect_uniquesubquery_engine: public subselect_engine
void cleanup(); void cleanup();
int prepare(); int prepare();
void fix_length_and_dec(Item_cache** row); void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan); int exec();
uint cols() { return 1; } uint cols() { return 1; }
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
void exclude(); void exclude();
...@@ -471,16 +498,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine ...@@ -471,16 +498,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{ {
/* FALSE for 'ref', TRUE for 'ref-or-null'. */ /* FALSE for 'ref', TRUE for 'ref-or-null'. */
bool check_null; bool check_null;
/*
The "having" clause. This clause (further reffered to as "artificial
having") was inserted by subquery transformation code. It contains
Item(s) that have a side-effect: they record whether the subquery has
produced a row with NULL certain components. We need to use it for cases
like
(oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
where we do index lookup on t.key=oe1 but need also to check if there
was a row such that t.no_key IS NULL.
NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
it should have been in uniquesubquery_engine in order to allow execution of
subqueries like
(oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
We could use uniquesubquery_engine for the first component and let
Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
However, subqueries like the above are currently not handled by index
lookup-based subquery engines, the engine applicability check misses
them: it doesn't switch the engine for case of artificial having and
[eq_]ref access (only for artifical having + ref_or_null or no having).
The above example subquery is handled as a full-blown SELECT with eq_ref
access to one table.
Due to this limitation, the "artificial having" currently needs to be
checked by only in indexsubquery_engine.
*/
Item *having;
public: public:
// constructor can assign THD because it will be called after JOIN::prepare // constructor can assign THD because it will be called after JOIN::prepare
subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg, subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
Item_subselect *subs, Item *where, Item_subselect *subs, Item *where,
bool chk_null) Item *having_arg, bool chk_null)
:subselect_uniquesubquery_engine(thd, tab_arg, subs, where), :subselect_uniquesubquery_engine(thd, tab_arg, subs, where),
check_null(chk_null) check_null(chk_null),
having(having_arg)
{} {}
int exec(bool full_scan); int exec();
void print (String *str); void print (String *str);
}; };
......
...@@ -1201,7 +1201,7 @@ extern const char *command_name[]; ...@@ -1201,7 +1201,7 @@ extern const char *command_name[];
extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword; extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */ extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str; extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond; extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
extern const char * const triggers_file_ext; extern const char * const triggers_file_ext;
extern const char * const trigname_file_ext; extern const char * const trigname_file_ext;
extern Eq_creator eq_creator; extern Eq_creator eq_creator;
......
...@@ -453,10 +453,13 @@ char *mysqld_unix_port, *opt_mysql_tmpdir; ...@@ -453,10 +453,13 @@ char *mysqld_unix_port, *opt_mysql_tmpdir;
const char **errmesg; /* Error messages */ const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF"; const char *myisam_recover_options_str="OFF";
const char *myisam_stats_method_str="nulls_unequal"; const char *myisam_stats_method_str="nulls_unequal";
/* name of reference on left espression in rewritten IN subquery */ /* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>"; const char *in_left_expr_name= "<left expr>";
/* name of additional condition */ /* name of additional condition */
const char *in_additional_cond= "<IN COND>"; const char *in_additional_cond= "<IN COND>";
const char *in_having_cond= "<IN HAVING>";
my_decimal decimal_zero; my_decimal decimal_zero;
/* classes for comparation parsing/processing */ /* classes for comparation parsing/processing */
Eq_creator eq_creator; Eq_creator eq_creator;
......
...@@ -469,7 +469,7 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -469,7 +469,7 @@ class st_select_lex_unit: public st_select_lex_node {
void set_thd(THD *thd_arg) { thd= thd_arg; } void set_thd(THD *thd_arg) { thd= thd_arg; }
friend void lex_start(THD *thd, uchar *buf, uint length); friend void lex_start(THD *thd, uchar *buf, uint length);
friend int subselect_union_engine::exec(bool); friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types(); List<Item> *get_unit_column_types();
}; };
......
This diff is collapsed.
...@@ -35,8 +35,17 @@ typedef struct keyuse_t { ...@@ -35,8 +35,17 @@ typedef struct keyuse_t {
satisfied if val has NULL 'value'. satisfied if val has NULL 'value'.
*/ */
bool null_rejecting; bool null_rejecting;
/* TRUE<=> This ref access is an outer subquery reference access */ /*
bool outer_ref; !NULL - This KEYUSE was created from an equality that was wrapped into
an Item_func_trig_cond. This means the equality (and validity of
this KEYUSE element) can be turned on and off. The on/off state
is indicted by the pointed value:
*cond_guard == TRUE <=> equality condition is on
*cond_guard == FALSE <=> equality condition is off
NULL - Otherwise (the source equality can't be turned off)
*/
bool *cond_guard;
} KEYUSE; } KEYUSE;
class store_key; class store_key;
...@@ -51,6 +60,18 @@ typedef struct st_table_ref ...@@ -51,6 +60,18 @@ typedef struct st_table_ref
byte *key_buff2; // key_buff+key_length byte *key_buff2; // key_buff+key_length
store_key **key_copy; // store_key **key_copy; //
Item **items; // val()'s for each keypart Item **items; // val()'s for each keypart
/*
Array of pointers to trigger variables. Some/all of the pointers may be
NULL. The ref access can be used iff
for each used key part i, (!cond_guards[i] || *cond_guards[i])
This array is used by subquery code. The subquery code may inject
triggered conditions, i.e. conditions that can be 'switched off'. A ref
access created from such condition is not valid when at least one of the
underlying conditions is switched off (see subquery code for more details)
*/
bool **cond_guards;
/* /*
(null_rejecting & (1<<i)) means the condition is '=' and no matching (null_rejecting & (1<<i)) means the condition is '=' and no matching
rows will be produced if items[i] IS NULL (see add_not_null_conds()) rows will be produced if items[i] IS NULL (see add_not_null_conds())
...@@ -99,6 +120,13 @@ enum enum_nested_loop_state ...@@ -99,6 +120,13 @@ enum enum_nested_loop_state
NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4 NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
}; };
/* Values for JOIN_TAB::packed_info */
#define TAB_INFO_HAVE_VALUE 1
#define TAB_INFO_USING_INDEX 2
#define TAB_INFO_USING_WHERE 4
#define TAB_INFO_FULL_SCAN_ON_NULL 8
typedef enum_nested_loop_state typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool); (*Next_select_func)(JOIN *, struct st_join_table *, bool);
typedef int (*Read_record_func)(struct st_join_table *tab); typedef int (*Read_record_func)(struct st_join_table *tab);
...@@ -119,7 +147,15 @@ typedef struct st_join_table { ...@@ -119,7 +147,15 @@ typedef struct st_join_table {
st_join_table *last_inner; /* last table table for embedding outer join */ st_join_table *last_inner; /* last table table for embedding outer join */
st_join_table *first_upper; /* first inner table for embedding outer join */ st_join_table *first_upper; /* first inner table for embedding outer join */
st_join_table *first_unmatched; /* used for optimization purposes only */ st_join_table *first_unmatched; /* used for optimization purposes only */
/* Special content for EXPLAIN 'Extra' column or NULL if none */
const char *info; const char *info;
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info.
*/
uint packed_info;
Read_record_func read_first_record; Read_record_func read_first_record;
Next_select_func next_select; Next_select_func next_select;
READ_RECORD read_record; READ_RECORD read_record;
...@@ -386,7 +422,7 @@ class JOIN :public Sql_alloc ...@@ -386,7 +422,7 @@ class JOIN :public Sql_alloc
Item_sum ***func); Item_sum ***func);
int rollup_send_data(uint idx); int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table); int rollup_write_data(uint idx, TABLE *table);
bool test_in_subselect(Item **where); void remove_subq_pushed_predicates(Item **where);
/* /*
Release memory and, if possible, the open tables held by this execution Release memory and, if possible, the open tables held by this execution
plan (and nested plans). It's used to release some tables before plan (and nested plans). It's used to release some tables before
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment