Commit 5bc7d596 authored by sergefp@pylon.mylan's avatar sergefp@pylon.mylan

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

into  mysql.com:/home/psergey/mysql-5.1-bug8804-r12-merge
parents 0e949c6a cced6255
......@@ -12,7 +12,7 @@ insert into t4 values (1,10), (2,10), (3,30), (4, 30);
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
1 PRIMARY t2 ALL NULL NULL NULL NULL # Using where
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func # Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func #
select * from t2 where p NOT IN (select p from t1) order by p;
p u o
4 4 4
......
This diff is collapsed.
......@@ -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 t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 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
3 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 index; Using where
5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_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 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 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 where
6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 func 1 Using where
drop table t1, t2, t3, t4;
CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB;
INSERT INTO t1 VALUES (1),(2);
......
This diff is collapsed.
This diff is collapsed.
......@@ -877,11 +877,35 @@ longlong Item_in_optimizer::val_int()
We disable the predicates we've pushed down into subselect, run the
subselect and see if it has produced any rows.
*/
((Item_in_subselect*)args[1])->enable_pushed_conds= FALSE;
longlong tmp= args[1]->val_bool_result();
result_for_null_param= null_value=
!((Item_in_subselect*)args[1])->engine->no_rows();
((Item_in_subselect*)args[1])->enable_pushed_conds= TRUE;
Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
if (cache->cols() == 1)
{
item_subs->set_cond_guard_var(0, FALSE);
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;
......
......@@ -314,6 +314,7 @@ public:
enum Functype functype() const { return TRIG_COND_FUNC; };
const char *func_name() const { return "trigcond"; };
bool const_item() const { return FALSE; }
bool *get_trig_var() { return trig_var; }
};
class Item_func_not_all :public Item_func_not
......
This diff is collapsed.
......@@ -94,7 +94,7 @@ public:
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
virtual bool exec(bool full_scan);
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
table_map not_null_tables() const { return 0; }
......@@ -104,6 +104,7 @@ public:
Item *get_tmp_table_item(THD *thd);
void update_used_tables();
void print(String *str);
virtual bool have_guarded_conds() { return FALSE; }
bool change_engine(subselect_engine *eng)
{
old_engine= engine;
......@@ -250,13 +251,21 @@ protected:
bool transformed;
public:
/* 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_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
: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; }
......@@ -341,23 +350,22 @@ public:
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.
A required side effect: If at least one pushed-down predicate is
disabled, subselect_engine->no_rows() must return correct result after
the exec() call.
RETURN
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.
*/
virtual int exec(bool full_scan)= 0;
virtual int exec()= 0;
virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
......@@ -392,7 +400,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan);
int exec();
uint cols();
uint8 uncacheable();
void exclude();
......@@ -416,7 +424,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan);
int exec();
uint cols();
uint8 uncacheable();
void exclude();
......@@ -430,11 +438,30 @@ public:
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
{
protected:
st_join_table *tab;
Item *cond;
Item *cond; /* The WHERE condition of subselect */
/*
TRUE<=> last execution produced empty set. Valid only when left
expression is NULL.
......@@ -454,7 +481,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec(bool full_scan);
int exec();
uint cols() { return 1; }
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
void exclude();
......@@ -472,16 +499,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{
/* FALSE for 'ref', TRUE for 'ref-or-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:
// constructor can assign THD because it will be called after JOIN::prepare
subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
Item_subselect *subs, Item *where,
bool chk_null)
Item *having_arg, bool chk_null)
: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);
};
......
......@@ -1532,7 +1532,7 @@ extern const LEX_STRING command_name[];
extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
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 trigname_file_ext;
extern Eq_creator eq_creator;
......
......@@ -524,10 +524,13 @@ char *mysqld_unix_port, *opt_mysql_tmpdir;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *myisam_stats_method_str="nulls_unequal";
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
const char *in_having_cond= "<IN HAVING>";
my_decimal decimal_zero;
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
......
......@@ -504,7 +504,7 @@ public:
void set_thd(THD *thd_arg) { thd= thd_arg; }
friend void lex_start(THD *thd, const uchar *buf, uint length);
friend int subselect_union_engine::exec(bool);
friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types();
};
......
This diff is collapsed.
......@@ -35,8 +35,17 @@ typedef struct keyuse_t {
satisfied if val has NULL 'value'.
*/
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;
class store_key;
......@@ -51,6 +60,18 @@ typedef struct st_table_ref
byte *key_buff2; // key_buff+key_length
store_key **key_copy; //
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
rows will be produced if items[i] IS NULL (see add_not_null_conds())
......@@ -99,6 +120,13 @@ enum enum_nested_loop_state
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
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
typedef int (*Read_record_func)(struct st_join_table *tab);
......@@ -120,7 +148,15 @@ typedef struct st_join_table {
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_unmatched; /* used for optimization purposes only */
/* Special content for EXPLAIN 'Extra' column or NULL if none */
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;
Next_select_func next_select;
READ_RECORD read_record;
......@@ -425,7 +461,7 @@ public:
Item_sum ***func);
int rollup_send_data(uint idx);
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
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