summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <sanja@hasky.mysql.fi>2005-08-13 08:19:34 +0300
committerunknown <sanja@hasky.mysql.fi>2005-08-13 08:19:34 +0300
commitad888850c0f7b754a31e58c5a6ad37cb62180716 (patch)
tree94c0a5c04e93056120573588429361768a4daf0b
parentd32c4314ed5935e7a03f443e3f26bae47e572600 (diff)
parente8d9dccb3dd98dfd7973a94d1eafc0b100101deb (diff)
downloadmariadb-git-ad888850c0f7b754a31e58c5a6ad37cb62180716.tar.gz
Merge abelkin@bk-internal.mysql.com:/home/bk/mysql-4.1
into hasky.mysql.fi:/home/sanja/work-merge-5.0 mysql-test/r/subselect.result: Auto merged mysql-test/t/subselect.test: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/item_subselect.cc: merge
-rw-r--r--mysql-test/r/subselect.result60
-rw-r--r--mysql-test/t/subselect.test13
-rw-r--r--sql/item.h9
-rw-r--r--sql/item_cmpfunc.h5
-rw-r--r--sql/item_subselect.cc178
-rw-r--r--sql/sql_parse.cc13
-rw-r--r--sql/sql_select.cc3
7 files changed, 228 insertions, 53 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 7a824a1be42..8a01b4080c3 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -2754,13 +2754,26 @@ one two flag
5 6 N
7 8 N
insert into t2 values (null,null,'N');
+insert into t2 values (null,3,'0');
+insert into t2 values (null,5,'0');
+insert into t2 values (10,null,'0');
+insert into t1 values (10,3,'0');
+insert into t1 values (10,5,'0');
+insert into t1 values (10,10,'0');
SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1;
one two test
-1 2 0
-2 3 0
-3 4 0
+1 2 NULL
+2 3 NULL
+3 4 NULL
5 6 1
7 8 1
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+one two
+5 6
+7 8
SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1;
one two test
1 2 NULL
@@ -2768,6 +2781,47 @@ one two test
3 4 NULL
5 6 1
7 8 1
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+one two test
+1 2 0
+2 3 NULL
+3 4 0
+5 6 0
+7 8 0
+10 3 NULL
+10 5 NULL
+10 10 NULL
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+one two test
+1 2 0
+2 3 NULL
+3 4 0
+5 6 0
+7 8 0
+10 3 NULL
+10 5 NULL
+10 10 NULL
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where
+Warnings:
+Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,<in_optimizer>((test.t1.one,test.t1.two),<exists>(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'0') and ((<cache>(test.t1.one) = test.t2.one) or isnull(test.t2.one)) and ((<cache>(test.t1.two) = test.t2.two) or isnull(test.t2.two))) having (<is_not_null_test>(test.t2.one) and <is_not_null_test>(test.t2.two)))) AS `test` from test.t1
+explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where
+Warnings:
+Note 1003 select test.t1.one AS `one`,test.t1.two AS `two` from test.t1 where <in_optimizer>((test.t1.one,test.t1.two),<exists>(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where ((test.t2.flag = _latin1'N') and (<cache>(test.t1.one) = test.t2.one) and (<cache>(test.t1.two) = test.t2.two))))
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort
+Warnings:
+Note 1003 select test.t1.one AS `one`,test.t1.two AS `two`,<in_optimizer>((test.t1.one,test.t1.two),<exists>(select test.t2.one AS `one`,test.t2.two AS `two` from test.t2 where (test.t2.flag = _latin1'0') group by test.t2.one,test.t2.two having (((<cache>(test.t1.one) = test.t2.one) or isnull(test.t2.one)) and ((<cache>(test.t1.two) = test.t2.two) or isnull(test.t2.two)) and <is_not_null_test>(test.t2.one) and <is_not_null_test>(test.t2.two)))) AS `test` from test.t1
DROP TABLE t1,t2;
CREATE TABLE t1 (a char(5), b char(5));
INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa');
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 657ccefbe2a..56d2be72ed7 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1774,9 +1774,20 @@ SELECT * FROM t1
WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N');
insert into t2 values (null,null,'N');
+insert into t2 values (null,3,'0');
+insert into t2 values (null,5,'0');
+insert into t2 values (10,null,'0');
+insert into t1 values (10,3,'0');
+insert into t1 values (10,5,'0');
+insert into t1 values (10,10,'0');
SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1;
+SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1;
-
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1;
+explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
+explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
DROP TABLE t1,t2;
#
diff --git a/sql/item.h b/sql/item.h
index a72156c9315..ae5fbe5a44b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1587,6 +1587,15 @@ public:
bool val_bool();
bool get_date(TIME *ltime, uint fuzzydate);
void print(String *str);
+ /*
+ we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
+ */
+ table_map used_tables() const
+ {
+ return (depended_from ?
+ OUTER_REF_TABLE_BIT :
+ (*ref)->used_tables() | RAND_TABLE_BIT);
+ }
};
class Item_null_helper :public Item_ref_null_helper
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 75c8411b844..a4165407159 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -913,6 +913,11 @@ public:
longlong val_int();
const char *func_name() const { return "<is_not_null_test>"; }
void update_used_tables();
+ /*
+ we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
+ */
+ table_map used_tables() const
+ { return used_tables_cache | RAND_TABLE_BIT; }
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index accc6d420be..1eddb36b34c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -969,6 +969,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ select_lex->where->top_level_item();
/*
we do not check join->conds->fixed, because Item_and can't be fixed
after creation
@@ -1032,8 +1033,12 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Item_subselect::trans_res
Item_in_subselect::row_value_transformer(JOIN *join)
{
- Item *item= 0;
SELECT_LEX *select_lex= join->select_lex;
+ Item *having_item= 0;
+ uint cols_num= left_expr->cols();
+ bool is_having_used= (join->having || select_lex->with_sum_func ||
+ select_lex->group_list.first ||
+ !select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::row_value_transformer");
if (select_lex->item_list.elements != left_expr->cols())
@@ -1065,71 +1070,156 @@ Item_in_subselect::row_value_transformer(JOIN *join)
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
+ if (is_having_used)
{
- uint n= left_expr->cols();
- List_iterator_fast<Item> li(select_lex->item_list);
- for (uint i= 0; i < n; i++)
+ /*
+ (l1, l2, l3) IN (SELECT v1, v2, v3 ... HAVING having) =>
+ EXISTS (SELECT ... HAVING having and
+ (l1 = v1 or is null v1) and
+ (l2 = v2 or is null v2) and
+ (l3 = v3 or is null v3) and
+ is_not_null_test(v1) and
+ is_not_null_test(v2) and
+ is_not_null_test(v3))
+ where is_not_null_test used to register nulls in case if we have
+ not found matching to return correct NULL value
+ */
+ Item *item_having_part2= 0;
+ for (uint i= 0; i < cols_num; i++)
{
- Item *func;
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
check_cols(left_expr->el(i)->cols()))
DBUG_RETURN(RES_ERROR);
- if (join->having || select_lex->with_sum_func ||
- select_lex->group_list.elements)
- func= new Item_ref_null_helper(&select_lex->context,
- this,
- select_lex->ref_pointer_array+i,
- (char *) "<no matter>",
- (char *) "<list ref>");
- else
- func= li++;
- func=
- eq_creator.create(new Item_direct_ref(&select_lex->context,
- (*optimizer->get_cache())->
- addr(i),
- (char *)"<no matter>",
- (char *)in_left_expr_name),
- func);
- item= and_items(item, func);
+ Item *item_eq=
+ new Item_func_eq(new
+ Item_direct_ref((*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
+ new
+ Item_direct_ref(select_lex->ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ Item *item_isnull=
+ new Item_func_isnull(new
+ Item_direct_ref( select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ having_item=
+ and_items(having_item,
+ new Item_cond_or(item_eq, item_isnull));
+ item_having_part2=
+ and_items(item_having_part2,
+ new
+ Item_is_not_null_test(this,
+ new
+ Item_direct_ref(select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ )
+ );
+ item_having_part2->top_level_item();
}
+ having_item= and_items(having_item, item_having_part2);
+ having_item->top_level_item();
}
- if (join->having || select_lex->with_sum_func ||
- select_lex->group_list.first ||
- !select_lex->table_list.elements)
+ else
{
/*
- AND can't be changed during fix_fields()
- we can assign select_lex->having here, and pass 0 as last
- argument (reference) to fix_fields()
+ (l1, l2, l3) IN (SELECT v1, v2, v3 ... WHERE where) =>
+ EXISTS (SELECT ... WHERE where and
+ (l1 = v1 or is null v1) and
+ (l2 = v2 or is null v2) and
+ (l3 = v3 or is null v3)
+ HAVING is_not_null_test(v1) and
+ is_not_null_test(v2) and
+ is_not_null_test(v3))
+ where is_not_null_test register NULLs values but reject rows
+
+ in case when we do not need correct NULL, we have simplier construction:
+ EXISTS (SELECT ... WHERE where and
+ (l1 = v1) and
+ (l2 = v2) and
+ (l3 = v3)
*/
- select_lex->having= join->having= and_items(join->having, item);
- select_lex->having_fix_field= 1;
+ Item *where_item= 0;
+ for (uint i= 0; i < cols_num; i++)
+ {
+ Item *item, *item_isnull;
+ DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
+ if (select_lex->ref_pointer_array[i]->
+ check_cols(left_expr->el(i)->cols()))
+ DBUG_RETURN(RES_ERROR);
+ item=
+ new Item_func_eq(new
+ Item_direct_ref((*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)in_left_expr_name),
+ new
+ Item_direct_ref( select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+ if (!abort_on_null)
+ {
+ having_item=
+ and_items(having_item,
+ new
+ Item_is_not_null_test(this,
+ new
+ Item_direct_ref(select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ )
+ );
+ item_isnull= new
+ Item_func_isnull(new
+ Item_direct_ref( select_lex->
+ ref_pointer_array+i,
+ (char *)"<no matter>",
+ (char *)"<list ref>")
+ );
+
+ item= new Item_cond_or(item, item_isnull);
+ }
+
+ where_item= and_items(where_item, item);
+ }
/*
- join->having can't be fixed after creation, so we do not check
- join->having->fixed
+ AND can't be changed during fix_fields()
+ we can assign select_lex->where here, and pass 0 as last
+ argument (reference) to fix_fields()
*/
- if (join->having->fix_fields(thd, 0))
- {
- select_lex->having_fix_field= 0;
+ select_lex->where= join->conds= and_items(join->conds, where_item);
+ select_lex->where->top_level_item();
+ if (join->conds->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR);
- }
- select_lex->having_fix_field= 0;
}
- else
+ if (having_item)
{
+ bool res;
+ select_lex->having= join->having= and_items(join->having, having_item);
+ select_lex->having->top_level_item();
/*
AND can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
*/
- select_lex->where= join->conds= and_items(join->conds, item);
- /*
- join->conds can't be fixed after creation, so we do not check
- join->conds->fixed
- */
- if (join->conds->fix_fields(thd, 0))
+ select_lex->having_fix_field= 1;
+ res= join->having->fix_fields(thd, 0);
+ select_lex->having_fix_field= 0;
+ if (res)
+ {
DBUG_RETURN(RES_ERROR);
+ }
}
DBUG_RETURN(RES_OK);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4fc11d63370..7d7ee895296 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2316,11 +2316,16 @@ mysql_execute_command(THD *thd)
/*
Skip if we are in the slave thread, some table rules have been
given and the table list says the query should not be replicated.
- Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it
- (otherwise we have stale files on slave caused by exclusion of one tmp
- table).
+
+ Exceptions are:
+
+ - SET: we always execute it (e.g., SET ONE_SHOT TIME_ZONE = 'XYZ')
+
+ - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
+ have stale files on slave caused by exclusion of one tmp table).
*/
- if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
+ if (lex->sql_command != SQLCOM_SET_OPTION &&
+ !(lex->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) &&
all_tables_not_ok(thd, all_tables))
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f26656ba609..464c350a602 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1576,7 +1576,8 @@ JOIN::exec()
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
~ (table_map) 0,
~used_tables);
- DBUG_EXECUTE("where",print_where(conds,"having after sort"););
+ DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
+ "having after sort"););
}
}
{