Commit fe630ff0 authored by unknown's avatar unknown

Merge mysql.com:/home/alexi/mysql-5.0

into  mysql.com:/home/alexi/dev/mysql-5.0-0


sql/item_cmpfunc.cc:
  Auto merged
sql/item_cmpfunc.h:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
parents 80530e74 43904698
...@@ -200,7 +200,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas ...@@ -200,7 +200,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas
INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Clculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
CREATE TABLE t2 ( CREATE TABLE t2 (
idAssignatura int(11) DEFAULT '0' NOT NULL, idAssignatura int(11) DEFAULT '0' NOT NULL,
Grup int(11) DEFAULT '0' NOT NULL, Grup int(11) DEFAULT '0' NOT NULL,
...@@ -1001,3 +1001,136 @@ SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; ...@@ -1001,3 +1001,136 @@ SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40;
c11 c21 c11 c21
40 NULL 40 NULL
DROP TABLE t1, t2; DROP TABLE t1, t2;
CREATE TABLE t1 (a int PRIMARY KEY, b int);
CREATE TABLE t2 (a int PRIMARY KEY, b int);
INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10);
INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b;
a b a b
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b;
a b a b
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b);
a b a b
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b;
a b a b
2 1 NULL NULL
3 2 3 0
4 3 4 1
6 5 6 4
8 7 NULL NULL
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b;
a b a b
2 1 NULL NULL
3 2 3 0
4 3 4 1
6 5 6 4
8 7 NULL NULL
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b);
a b a b
2 1 NULL NULL
3 2 3 0
4 3 4 1
6 5 6 4
8 7 NULL NULL
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b;
a b a b
2 1 NULL NULL
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
8 7 NULL NULL
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b);
a b a b
2 1 NULL NULL
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
8 7 NULL NULL
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b);
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b);
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b));
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b;
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b);
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b));
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b);
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b));
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b;
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b));
a b a b
3 2 3 0
4 3 4 1
6 5 6 4
7 8 7 5
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
DROP TABLE t1,t2;
...@@ -135,7 +135,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas ...@@ -135,7 +135,7 @@ INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas
INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL);
INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Clculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL);
CREATE TABLE t2 ( CREATE TABLE t2 (
idAssignatura int(11) DEFAULT '0' NOT NULL, idAssignatura int(11) DEFAULT '0' NOT NULL,
...@@ -590,7 +590,6 @@ INSERT INTO t2 VALUES("0", "EN", "0-EN"); ...@@ -590,7 +590,6 @@ INSERT INTO t2 VALUES("0", "EN", "0-EN");
INSERT INTO t2 VALUES("0", "SV", "0-SV"); INSERT INTO t2 VALUES("0", "SV", "0-SV");
INSERT INTO t2 VALUES("10", "EN", "10-EN"); INSERT INTO t2 VALUES("10", "EN", "10-EN");
INSERT INTO t2 VALUES("10", "SV", "10-SV"); INSERT INTO t2 VALUES("10", "SV", "10-SV");
SELECT t1.id, t1.text_id, t2.text_data SELECT t1.id, t1.text_id, t2.text_data
FROM t1 LEFT JOIN t2 FROM t1 LEFT JOIN t2
ON t1.text_id = t2.text_id ON t1.text_id = t2.text_id
...@@ -713,3 +712,49 @@ INSERT INTO t1 VALUES (30), (40), (50); ...@@ -713,3 +712,49 @@ INSERT INTO t1 VALUES (30), (40), (50);
INSERT INTO t2 VALUES (300), (400), (500); INSERT INTO t2 VALUES (300), (400), (500);
SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Test for bugs
# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN
# #12102: erroneously missing outer join elimination in case of WHERE IN/IF
#
CREATE TABLE t1 (a int PRIMARY KEY, b int);
CREATE TABLE t2 (a int PRIMARY KEY, b int);
INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10);
INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b));
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b));
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b);
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b));
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b;
SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b));
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1);
DROP TABLE t1,t2;
...@@ -988,6 +988,53 @@ longlong Item_func_interval::val_int() ...@@ -988,6 +988,53 @@ longlong Item_func_interval::val_int()
} }
/*
Perform context analysis of a BETWEEN item tree
SYNOPSIS:
fix_fields()
thd reference to the global context of the query thread
tables list of all open tables involved in the query
ref pointer to Item* variable where pointer to resulting "fixed"
item is to be assigned
DESCRIPTION
This function performs context analysis (name resolution) and calculates
various attributes of the item tree with Item_func_between as its root.
The function saves in ref the pointer to the item or to a newly created
item that is considered as a replacement for the original one.
NOTES
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
a predicate/function level. Then it's easy to show that:
T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2))
T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2)))
RETURN
0 ok
1 got error
*/
bool
Item_func_between::fix_fields(THD *thd, Item **ref)
{
if (Item_func_opt_neg::fix_fields(thd, ref))
return 1;
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
if (pred_level && !negated)
return 0;
/* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
not_null_tables_cache= args[0]->not_null_tables() |
(args[1]->not_null_tables() & args[2]->not_null_tables());
return 0;
}
void Item_func_between::fix_length_and_dec() void Item_func_between::fix_length_and_dec()
{ {
max_length= 1; max_length= 1;
...@@ -1040,8 +1087,9 @@ longlong Item_func_between::val_int() ...@@ -1040,8 +1087,9 @@ longlong Item_func_between::val_int()
a=args[1]->val_str(&value1); a=args[1]->val_str(&value1);
b=args[2]->val_str(&value2); b=args[2]->val_str(&value2);
if (!args[1]->null_value && !args[2]->null_value) if (!args[1]->null_value && !args[2]->null_value)
return (sortcmp(value,a,cmp_collation.collation) >= 0 && return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0; sortcmp(value,b,cmp_collation.collation) <= 0) !=
negated);
if (args[1]->null_value && args[2]->null_value) if (args[1]->null_value && args[2]->null_value)
null_value=1; null_value=1;
else if (args[1]->null_value) else if (args[1]->null_value)
...@@ -1063,7 +1111,7 @@ longlong Item_func_between::val_int() ...@@ -1063,7 +1111,7 @@ longlong Item_func_between::val_int()
a=args[1]->val_int(); a=args[1]->val_int();
b=args[2]->val_int(); b=args[2]->val_int();
if (!args[1]->null_value && !args[2]->null_value) if (!args[1]->null_value && !args[2]->null_value)
return (value >= a && value <= b) ? 1 : 0; return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value) if (args[1]->null_value && args[2]->null_value)
null_value=1; null_value=1;
else if (args[1]->null_value) else if (args[1]->null_value)
...@@ -1084,8 +1132,8 @@ longlong Item_func_between::val_int() ...@@ -1084,8 +1132,8 @@ longlong Item_func_between::val_int()
a_dec= args[1]->val_decimal(&a_buf); a_dec= args[1]->val_decimal(&a_buf);
b_dec= args[2]->val_decimal(&b_buf); b_dec= args[2]->val_decimal(&b_buf);
if (!args[1]->null_value && !args[2]->null_value) if (!args[1]->null_value && !args[2]->null_value)
return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0); return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
my_decimal_cmp(dec, b_dec) <= 0) != negated);
if (args[1]->null_value && args[2]->null_value) if (args[1]->null_value && args[2]->null_value)
null_value=1; null_value=1;
else if (args[1]->null_value) else if (args[1]->null_value)
...@@ -1101,7 +1149,7 @@ longlong Item_func_between::val_int() ...@@ -1101,7 +1149,7 @@ longlong Item_func_between::val_int()
a= args[1]->val_real(); a= args[1]->val_real();
b= args[2]->val_real(); b= args[2]->val_real();
if (!args[1]->null_value && !args[2]->null_value) if (!args[1]->null_value && !args[2]->null_value)
return (value >= a && value <= b) ? 1 : 0; return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value) if (args[1]->null_value && args[2]->null_value)
null_value=1; null_value=1;
else if (args[1]->null_value) else if (args[1]->null_value)
...@@ -1113,7 +1161,7 @@ longlong Item_func_between::val_int() ...@@ -1113,7 +1161,7 @@ longlong Item_func_between::val_int()
null_value= value >= a; null_value= value >= a;
} }
} }
return 0; return (longlong) (!null_value && negated);
} }
...@@ -1244,6 +1292,49 @@ Item_func_ifnull::str_op(String *str) ...@@ -1244,6 +1292,49 @@ Item_func_ifnull::str_op(String *str)
} }
/*
Perform context analysis of an IF item tree
SYNOPSIS:
fix_fields()
thd reference to the global context of the query thread
tables list of all open tables involved in the query
ref pointer to Item* variable where pointer to resulting "fixed"
item is to be assigned
DESCRIPTION
This function performs context analysis (name resolution) and calculates
various attributes of the item tree with Item_func_if as its root.
The function saves in ref the pointer to the item or to a newly created
item that is considered as a replacement for the original one.
NOTES
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
a predicate/function level. Then it's easy to show that:
T0(IF(e,e1,e2) = T1(IF(e,e1,e2))
T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2))
RETURN
0 ok
1 got error
*/
bool
Item_func_if::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
args[0]->top_level_item();
if (Item_func::fix_fields(thd, ref))
return 1;
not_null_tables_cache= (args[1]->not_null_tables()
& args[2]->not_null_tables());
return 0;
}
void void
Item_func_if::fix_length_and_dec() Item_func_if::fix_length_and_dec()
{ {
...@@ -2184,6 +2275,56 @@ bool Item_func_in::nulls_in_row() ...@@ -2184,6 +2275,56 @@ bool Item_func_in::nulls_in_row()
} }
/*
Perform context analysis of an IN item tree
SYNOPSIS:
fix_fields()
thd reference to the global context of the query thread
tables list of all open tables involved in the query
ref pointer to Item* variable where pointer to resulting "fixed"
item is to be assigned
DESCRIPTION
This function performs context analysis (name resolution) and calculates
various attributes of the item tree with Item_func_in as its root.
The function saves in ref the pointer to the item or to a newly created
item that is considered as a replacement for the original one.
NOTES
Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on
a predicate/function level. Then it's easy to show that:
T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei)))
T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei)))
RETURN
0 ok
1 got error
*/
bool
Item_func_in::fix_fields(THD *thd, Item **ref)
{
Item **arg, **arg_end;
if (Item_func_opt_neg::fix_fields(thd, ref))
return 1;
/* not_null_tables_cache == union(T1(e),union(T1(ei))) */
if (pred_level && negated)
return 0;
/* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
not_null_tables_cache= ~(table_map) 0;
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++)
not_null_tables_cache&= (*arg)->not_null_tables();
not_null_tables_cache|= (*args)->not_null_tables();
return 0;
}
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{ {
return cs->coll->strnncollsp(cs, return cs->coll->strnncollsp(cs,
...@@ -2283,7 +2424,7 @@ longlong Item_func_in::val_int() ...@@ -2283,7 +2424,7 @@ longlong Item_func_in::val_int()
{ {
int tmp=array->find(args[0]); int tmp=array->find(args[0]);
null_value=args[0]->null_value || (!tmp && have_null); null_value=args[0]->null_value || (!tmp && have_null);
return tmp; return (longlong) (!null_value && tmp != negated);
} }
in_item->store_value(args[0]); in_item->store_value(args[0]);
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
...@@ -2292,11 +2433,11 @@ longlong Item_func_in::val_int() ...@@ -2292,11 +2433,11 @@ longlong Item_func_in::val_int()
for (uint i=1 ; i < arg_count ; i++) for (uint i=1 ; i < arg_count ; i++)
{ {
if (!in_item->cmp(args[i]) && !args[i]->null_value) if (!in_item->cmp(args[i]) && !args[i]->null_value)
return 1; // Would maybe be nice with i ? return (longlong) (!negated);
have_null|= args[i]->null_value; have_null|= args[i]->null_value;
} }
null_value= have_null; null_value= have_null;
return 0; return (longlong) (!null_value && negated);
} }
......
...@@ -401,17 +401,49 @@ class Item_func_ne :public Item_bool_rowready_func2 ...@@ -401,17 +401,49 @@ class Item_func_ne :public Item_bool_rowready_func2
}; };
class Item_func_between :public Item_int_func /*
The class Item_func_opt_neg is defined to factor out the functionality
common for the classes Item_func_between and Item_func_in. The objects
of these classes can express predicates or there negations.
The alternative approach would be to create pairs Item_func_between,
Item_func_notbetween and Item_func_in, Item_func_notin.
*/
class Item_func_opt_neg :public Item_int_func
{
public:
bool negated; /* <=> the item represents NOT <func> */
bool pred_level; /* <=> [NOT] <func> is used on a predicate level */
public:
Item_func_opt_neg(Item *a, Item *b, Item *c)
:Item_int_func(a, b, c), negated(0), pred_level(0) {}
Item_func_opt_neg(List<Item> &list)
:Item_int_func(list), negated(0), pred_level(0) {}
public:
inline void negate() { negated= !negated; }
inline void top_level_item() { pred_level= 1; }
Item *neg_transformer(THD *thd)
{
negated= !negated;
return this;
}
};
class Item_func_between :public Item_func_opt_neg
{ {
DTCollation cmp_collation; DTCollation cmp_collation;
public: public:
Item_result cmp_type; Item_result cmp_type;
String value0,value1,value2; String value0,value1,value2;
Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} Item_func_between(Item *a, Item *b, Item *c)
:Item_func_opt_neg(a, b, c) {}
longlong val_int(); longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_KEY; } optimize_type select_optimize() const { return OPTIMIZE_KEY; }
enum Functype functype() const { return BETWEEN; } enum Functype functype() const { return BETWEEN; }
const char *func_name() const { return "between"; } const char *func_name() const { return "between"; }
bool fix_fields(THD *, Item **);
void fix_length_and_dec(); void fix_length_and_dec();
void print(String *str); void print(String *str);
bool is_bool_func() { return 1; } bool is_bool_func() { return 1; }
...@@ -505,16 +537,10 @@ class Item_func_if :public Item_func ...@@ -505,16 +537,10 @@ class Item_func_if :public Item_func
String *val_str(String *str); String *val_str(String *str);
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd, Item **ref) bool fix_fields(THD *, Item **);
{
DBUG_ASSERT(fixed == 0);
args[0]->top_level_item();
return Item_func::fix_fields(thd, ref);
}
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const; uint decimal_precision() const;
const char *func_name() const { return "if"; } const char *func_name() const { return "if"; }
table_map not_null_tables() const { return 0; }
}; };
...@@ -819,7 +845,7 @@ class cmp_item_sort_string_in_static :public cmp_item_string ...@@ -819,7 +845,7 @@ class cmp_item_sort_string_in_static :public cmp_item_string
} }
}; };
class Item_func_in :public Item_int_func class Item_func_in :public Item_func_opt_neg
{ {
Item_result cmp_type; Item_result cmp_type;
in_vector *array; in_vector *array;
...@@ -828,11 +854,12 @@ class Item_func_in :public Item_int_func ...@@ -828,11 +854,12 @@ class Item_func_in :public Item_int_func
DTCollation cmp_collation; DTCollation cmp_collation;
public: public:
Item_func_in(List<Item> &list) Item_func_in(List<Item> &list)
:Item_int_func(list), array(0), in_item(0), have_null(0) :Item_func_opt_neg(list), array(0), in_item(0), have_null(0)
{ {
allowed_arg_cols= 0; // Fetch this value from first argument allowed_arg_cols= 0; // Fetch this value from first argument
} }
longlong val_int(); longlong val_int();
bool fix_fields(THD *, Item **);
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const { return 1; } uint decimal_precision() const { return 1; }
void cleanup() void cleanup()
...@@ -853,12 +880,6 @@ class Item_func_in :public Item_int_func ...@@ -853,12 +880,6 @@ class Item_func_in :public Item_int_func
bool nulls_in_row(); bool nulls_in_row();
bool is_bool_func() { return 1; } bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
/*
IN() protect from NULL only first argument, if construction like
"expression IN ()" will be allowed, we will need to check number of
argument here, because "NOT(NULL IN ())" is TRUE.
*/
table_map not_null_tables() const { return args[0]->not_null_tables(); }
}; };
/* Functions used by where clause */ /* Functions used by where clause */
......
...@@ -3524,18 +3524,9 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) ...@@ -3524,18 +3524,9 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
} }
Item_func *cond_func= (Item_func*) cond; Item_func *cond_func= (Item_func*) cond;
if (cond_func->functype() == Item_func::NOT_FUNC) if (cond_func->functype() == Item_func::BETWEEN ||
{ cond_func->functype() == Item_func::IN_FUNC)
/* Optimize NOT BETWEEN and NOT IN */ inv= ((Item_func_opt_neg *) cond_func)->negated;
Item *arg= cond_func->arguments()[0];
if (arg->type() != Item::FUNC_ITEM)
DBUG_RETURN(0);
cond_func= (Item_func*) arg;
if (cond_func->functype() != Item_func::BETWEEN &&
cond_func->functype() != Item_func::IN_FUNC)
DBUG_RETURN(0);
inv= TRUE;
}
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0); DBUG_RETURN(0);
......
...@@ -2862,19 +2862,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, ...@@ -2862,19 +2862,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
if (cond->type() != Item::FUNC_ITEM) if (cond->type() != Item::FUNC_ITEM)
return; return;
Item_func *cond_func= (Item_func*) cond; Item_func *cond_func= (Item_func*) cond;
if (cond_func->functype() == Item_func::NOT_FUNC)
{
Item *item= cond_func->arguments()[0];
/*
At this moment all NOT before simple comparison predicates
are eliminated. NOT IN and NOT BETWEEN are treated similar
IN and BETWEEN respectively.
*/
if (item->type() == Item::FUNC_ITEM &&
((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY)
add_key_fields(key_fields,and_level,item,usable_tables);
return;
}
switch (cond_func->select_optimize()) { switch (cond_func->select_optimize()) {
case Item_func::OPTIMIZE_NONE: case Item_func::OPTIMIZE_NONE:
break; break;
......
...@@ -4279,7 +4279,9 @@ predicate: ...@@ -4279,7 +4279,9 @@ predicate:
else else
{ {
$5->push_front($1); $5->push_front($1);
$$= negate_expression(YYTHD, new Item_func_in(*$5)); Item_func_in *item = new Item_func_in(*$5);
item->negate();
$$= item;
} }
} }
| bit_expr IN_SYM in_subselect | bit_expr IN_SYM in_subselect
...@@ -4289,7 +4291,11 @@ predicate: ...@@ -4289,7 +4291,11 @@ predicate:
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); } { $$= new Item_func_between($1,$3,$5); }
| bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } {
Item_func_between *item= new Item_func_between($1,$4,$6);
item->negate();
$$= item;
}
| bit_expr SOUNDS_SYM LIKE bit_expr | bit_expr SOUNDS_SYM LIKE bit_expr
{ $$= new Item_func_eq(new Item_func_soundex($1), { $$= new Item_func_eq(new Item_func_soundex($1),
new Item_func_soundex($4)); } new Item_func_soundex($4)); }
......
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