mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Merge rurik.mysql.com:/home/igor/mysql-4.1
into rurik.mysql.com:/home/igor/dev/mysql-4.1-0 mysql-test/r/func_gconcat.result: Auto merged mysql-test/t/func_gconcat.test: Auto merged sql/item_sum.cc: Auto merged
This commit is contained in:
@@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object,
|
|||||||
const char *statement);
|
const char *statement);
|
||||||
|
|
||||||
static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
|
static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
|
||||||
replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0,
|
replace=0,silent=0,ignore=0,opt_compress=0,
|
||||||
opt_low_priority= 0, tty_password= 0;
|
opt_low_priority= 0, tty_password= 0;
|
||||||
|
static uint opt_local_file=0;
|
||||||
static MYSQL mysql_connection;
|
static MYSQL mysql_connection;
|
||||||
static char *opt_password=0, *current_user=0,
|
static char *opt_password=0, *current_user=0,
|
||||||
*current_host=0, *current_db=0, *fields_terminated=0,
|
*current_host=0, *current_db=0, *fields_terminated=0,
|
||||||
|
@@ -456,6 +456,7 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
|
|||||||
#endif
|
#endif
|
||||||
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
|
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
|
||||||
int len);
|
int len);
|
||||||
|
static int handle_no_error(struct st_query *q);
|
||||||
|
|
||||||
static void do_eval(DYNAMIC_STRING* query_eval, const char *query)
|
static void do_eval(DYNAMIC_STRING* query_eval, const char *query)
|
||||||
{
|
{
|
||||||
@@ -2907,22 +2908,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->expected_errno[0].type == ERR_ERRNO &&
|
if (handle_no_error(q))
|
||||||
q->expected_errno[0].code.errnum != 0)
|
|
||||||
{
|
{
|
||||||
/* Error code we wanted was != 0, i.e. not an expected success */
|
error= 1;
|
||||||
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
|
||||||
q->query, q->expected_errno[0].code.errnum);
|
|
||||||
error = 1;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
else if (q->expected_errno[0].type == ERR_SQLSTATE &&
|
|
||||||
strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
|
|
||||||
{
|
|
||||||
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
|
||||||
verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
|
|
||||||
q->query, q->expected_errno[0].code.sqlstate);
|
|
||||||
error = 1;
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3102,10 +3090,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
|||||||
{
|
{
|
||||||
if (q->abort_on_error)
|
if (q->abort_on_error)
|
||||||
{
|
{
|
||||||
die("unable to prepare statement '%s': "
|
die("query '%s' failed: %d: %s", query,
|
||||||
"%s (mysql_stmt_errno=%d returned=%d)",
|
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
||||||
query,
|
|
||||||
mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3186,12 +3172,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we got here the statement was both executed and read succeesfully */
|
/* If we got here the statement was both executed and read succeesfully */
|
||||||
|
if (handle_no_error(q))
|
||||||
if (q->expected_errno[0].type == ERR_ERRNO &&
|
|
||||||
q->expected_errno[0].code.errnum != 0)
|
|
||||||
{
|
{
|
||||||
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
|
||||||
q->query, q->expected_errno[0].code.errnum);
|
|
||||||
error= 1;
|
error= 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -3518,8 +3500,14 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
|
|||||||
dynstr_append_mem(ds,"\n",1);
|
dynstr_append_mem(ds,"\n",1);
|
||||||
if (i)
|
if (i)
|
||||||
{
|
{
|
||||||
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
|
if (q->expected_errno[0].type == ERR_ERRNO)
|
||||||
q->query, mysql_stmt_errno(stmt), q->expected_errno[0]);
|
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
|
||||||
|
q->query, mysql_stmt_errno(stmt),
|
||||||
|
q->expected_errno[0].code.errnum);
|
||||||
|
else
|
||||||
|
verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
|
||||||
|
q->query, mysql_stmt_sqlstate(stmt),
|
||||||
|
q->expected_errno[0].code.sqlstate);
|
||||||
return 1; /* Error */
|
return 1; /* Error */
|
||||||
}
|
}
|
||||||
verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt),
|
verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt),
|
||||||
@@ -3534,6 +3522,43 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Handle absence of errors after execution
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
handle_no_error()
|
||||||
|
q - context of query
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - OK
|
||||||
|
1 - Some error was expected from this query.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int handle_no_error(struct st_query *q)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("handle_no_error");
|
||||||
|
|
||||||
|
if (q->expected_errno[0].type == ERR_ERRNO &&
|
||||||
|
q->expected_errno[0].code.errnum != 0)
|
||||||
|
{
|
||||||
|
/* Error code we wanted was != 0, i.e. not an expected success */
|
||||||
|
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
||||||
|
q->query, q->expected_errno[0].code.errnum);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
else if (q->expected_errno[0].type == ERR_SQLSTATE &&
|
||||||
|
strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
|
||||||
|
{
|
||||||
|
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
||||||
|
verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
|
||||||
|
q->query, q->expected_errno[0].code.sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************\
|
/****************************************************************************\
|
||||||
* Functions to match SQL statements that can be prepared
|
* Functions to match SQL statements that can be prepared
|
||||||
\****************************************************************************/
|
\****************************************************************************/
|
||||||
|
@@ -955,6 +955,10 @@ char_length(a) length(a) a
|
|||||||
2 4 ан
|
2 4 ан
|
||||||
drop table t1;
|
drop table t1;
|
||||||
set names utf8;
|
set names utf8;
|
||||||
|
select 'andre%' like 'andreñ%' escape 'ñ';
|
||||||
|
'andre%' like 'andreñ%' escape 'ñ'
|
||||||
|
1
|
||||||
|
set names utf8;
|
||||||
select 'a\\' like 'a\\';
|
select 'a\\' like 'a\\';
|
||||||
'a\\' like 'a\\'
|
'a\\' like 'a\\'
|
||||||
1
|
1
|
||||||
|
@@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1;
|
|||||||
ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat'
|
ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat'
|
||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850);
|
||||||
|
INSERT INTO t1 VALUES ('<27>');
|
||||||
|
SELECT a FROM t1;
|
||||||
|
a
|
||||||
|
<EFBFBD>
|
||||||
|
SELECT GROUP_CONCAT(a) FROM t1;
|
||||||
|
GROUP_CONCAT(a)
|
||||||
|
<EFBFBD>
|
||||||
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1 (id int);
|
CREATE TABLE t1 (id int);
|
||||||
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
|
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
|
||||||
gc
|
gc
|
||||||
|
@@ -158,3 +158,10 @@ DROP TABLE t1;
|
|||||||
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
|
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
|
||||||
_cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin
|
_cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin
|
||||||
1
|
1
|
||||||
|
set names koi8r;
|
||||||
|
select 'andre%' like 'andre<72>%' escape '<27>';
|
||||||
|
'andre%' like 'andre<72>%' escape '<27>'
|
||||||
|
1
|
||||||
|
select _cp1251'andre%' like convert('andre<72>%' using cp1251) escape '<27>';
|
||||||
|
_cp1251'andre%' like convert('andre<72>%' using cp1251) escape '<27>'
|
||||||
|
1
|
||||||
|
@@ -883,3 +883,136 @@ Warnings:
|
|||||||
Warning 1260 2 line(s) were cut by GROUP_CONCAT()
|
Warning 1260 2 line(s) were cut by GROUP_CONCAT()
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
set group_concat_max_len=default;
|
set group_concat_max_len=default;
|
||||||
|
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
|
||||||
|
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
|
||||||
|
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where
|
||||||
|
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
|
||||||
|
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
@@ -810,6 +810,12 @@ alter table t1 modify a char(2) character set utf8;
|
|||||||
select char_length(a), length(a), a from t1 order by a;
|
select char_length(a), length(a), a from t1 order by a;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bugs#12611
|
||||||
|
# ESCAPE + LIKE do not work when the escape char is a multibyte one
|
||||||
|
#
|
||||||
|
set names utf8;
|
||||||
|
select 'andre%' like 'andreñ%' escape 'ñ';
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0
|
# Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0
|
||||||
|
@@ -281,6 +281,16 @@ select collation(group_concat(a,b)) from t1;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #12829
|
||||||
|
# Cannot convert the charset of a GROUP_CONCAT result
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850);
|
||||||
|
INSERT INTO t1 VALUES ('<27>');
|
||||||
|
SELECT a FROM t1;
|
||||||
|
SELECT GROUP_CONCAT(a) FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
#
|
#
|
||||||
# bug #7769: group_concat returning null is checked in having
|
# bug #7769: group_concat returning null is checked in having
|
||||||
#
|
#
|
||||||
|
@@ -96,4 +96,21 @@ DROP TABLE t1;
|
|||||||
#
|
#
|
||||||
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
|
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check 8bit escape character
|
||||||
|
#
|
||||||
|
set names koi8r;
|
||||||
|
select 'andre%' like 'andre<72>%' escape '<27>';
|
||||||
|
|
||||||
|
# Check 8bit escape character with charset conversion:
|
||||||
|
# For "a LIKE b ESCAPE c" expressions,
|
||||||
|
# escape character is converted into the operation character set,
|
||||||
|
# which is result of aggregation of character sets of "a" and "b".
|
||||||
|
# "c" itself doesn't take part in aggregation, because its collation
|
||||||
|
# doesn't matter, escape character is always compared binary.
|
||||||
|
# In the example below, escape character is converted from koi8r into cp1251:
|
||||||
|
#
|
||||||
|
select _cp1251'andre%' like convert('andre<72>%' using cp1251) escape '<27>';
|
||||||
|
|
||||||
|
#
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@@ -625,4 +625,50 @@ select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a;
|
|||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
set group_concat_max_len=default;
|
set group_concat_max_len=default;
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@@ -592,7 +592,7 @@ while ($num)
|
|||||||
--source var/tmp/sourced1.sql
|
--source var/tmp/sourced1.sql
|
||||||
dec $num;
|
dec $num;
|
||||||
}
|
}
|
||||||
--enable_abort_on_error;
|
--enable_abort_on_error
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@@ -609,7 +609,8 @@ int ha_tina::rnd_init(bool scan)
|
|||||||
records= 0;
|
records= 0;
|
||||||
chain_ptr= chain;
|
chain_ptr= chain;
|
||||||
#ifdef HAVE_MADVISE
|
#ifdef HAVE_MADVISE
|
||||||
(void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
|
if (scan)
|
||||||
|
(void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
@@ -820,6 +820,54 @@ longlong Item_func_interval::val_int()
|
|||||||
return i-1;
|
return i-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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, struct st_table_list *tables, Item **ref)
|
||||||
|
{
|
||||||
|
if (Item_func_opt_neg::fix_fields(thd, tables, 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;
|
||||||
@@ -871,8 +919,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)
|
||||||
@@ -894,7 +943,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)
|
||||||
@@ -914,7 +963,7 @@ longlong Item_func_between::val_int()
|
|||||||
a=args[1]->val();
|
a=args[1]->val();
|
||||||
b=args[2]->val();
|
b=args[2]->val();
|
||||||
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)
|
||||||
@@ -926,7 +975,7 @@ longlong Item_func_between::val_int()
|
|||||||
null_value= value >= a;
|
null_value= value >= a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return (longlong) (!null_value && negated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1019,6 +1068,49 @@ Item_func_ifnull::val_str(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, struct st_table_list *tlist, Item **ref)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 0);
|
||||||
|
args[0]->top_level_item();
|
||||||
|
|
||||||
|
if (Item_func::fix_fields(thd, tlist, 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()
|
||||||
{
|
{
|
||||||
@@ -1750,6 +1842,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, TABLE_LIST *tables, Item **ref)
|
||||||
|
{
|
||||||
|
Item **arg, **arg_end;
|
||||||
|
|
||||||
|
if (Item_func_opt_neg::fix_fields(thd, tables, 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,
|
||||||
@@ -1840,7 +1982,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))
|
||||||
@@ -1849,11 +1991,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2293,7 +2435,42 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
|
|||||||
{
|
{
|
||||||
/* If we are on execution stage */
|
/* If we are on execution stage */
|
||||||
String *escape_str= escape_item->val_str(&tmp_value1);
|
String *escape_str= escape_item->val_str(&tmp_value1);
|
||||||
escape= escape_str ? *(escape_str->ptr()) : '\\';
|
if (escape_str)
|
||||||
|
{
|
||||||
|
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
||||||
|
if (use_mb(cs))
|
||||||
|
{
|
||||||
|
my_wc_t wc;
|
||||||
|
int rc= cs->cset->mb_wc(cs, &wc,
|
||||||
|
(const uchar*) escape_str->ptr(),
|
||||||
|
(const uchar*) escape_str->ptr() +
|
||||||
|
escape_str->length());
|
||||||
|
escape= (int) (rc > 0 ? wc : '\\');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
In the case of 8bit character set, we pass native
|
||||||
|
code instead of Unicode code as "escape" argument.
|
||||||
|
Convert to "cs" if charset of escape differs.
|
||||||
|
*/
|
||||||
|
uint32 unused;
|
||||||
|
if (escape_str->needs_conversion(escape_str->length(),
|
||||||
|
escape_str->charset(), cs, &unused))
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
uint errors;
|
||||||
|
uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(),
|
||||||
|
escape_str->length(),
|
||||||
|
escape_str->charset(), &errors);
|
||||||
|
escape= cnvlen ? ch : '\\';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
escape= *(escape_str->ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
escape= '\\';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We could also do boyer-more for non-const items, but as we would have to
|
We could also do boyer-more for non-const items, but as we would have to
|
||||||
|
@@ -358,17 +358,49 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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 *, struct st_table_list *, Item **);
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
void print(String *str);
|
void print(String *str);
|
||||||
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
|
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
|
||||||
@@ -433,15 +465,9 @@ public:
|
|||||||
longlong val_int();
|
longlong val_int();
|
||||||
String *val_str(String *str);
|
String *val_str(String *str);
|
||||||
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,struct st_table_list *tlist, Item **ref)
|
bool fix_fields(THD *, struct st_table_list *, Item **);
|
||||||
{
|
|
||||||
DBUG_ASSERT(fixed == 0);
|
|
||||||
args[0]->top_level_item();
|
|
||||||
return Item_func::fix_fields(thd, tlist, ref);
|
|
||||||
}
|
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
const char *func_name() const { return "if"; }
|
const char *func_name() const { return "if"; }
|
||||||
table_map not_null_tables() const { return 0; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -736,7 +762,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
@@ -745,11 +771,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 *, struct st_table_list *, Item **);
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
void cleanup()
|
void cleanup()
|
||||||
{
|
{
|
||||||
@@ -769,12 +796,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 */
|
||||||
@@ -879,7 +900,7 @@ class Item_func_like :public Item_bool_func2
|
|||||||
Item *escape_item;
|
Item *escape_item;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
char escape;
|
int escape;
|
||||||
|
|
||||||
Item_func_like(Item *a,Item *b, Item *escape_arg)
|
Item_func_like(Item *a,Item *b, Item *escape_arg)
|
||||||
:Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0),
|
:Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0),
|
||||||
|
@@ -1937,6 +1937,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
args, arg_count, MY_COLL_ALLOW_CONV))
|
args, arg_count, MY_COLL_ALLOW_CONV))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
result.set_charset(collation.collation);
|
||||||
result_field= 0;
|
result_field= 0;
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
max_length= group_concat_max_len;
|
max_length= group_concat_max_len;
|
||||||
|
@@ -849,7 +849,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
|||||||
|
|
||||||
if (cond_func->functype() == Item_func::BETWEEN)
|
if (cond_func->functype() == Item_func::BETWEEN)
|
||||||
{
|
{
|
||||||
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
if (!((Item_func_between *)(cond_func))->negated &&
|
||||||
|
cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
|
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
|
||||||
Item_result cmp_type=field->cmp_type();
|
Item_result cmp_type=field->cmp_type();
|
||||||
@@ -866,7 +867,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
|||||||
if (cond_func->functype() == Item_func::IN_FUNC)
|
if (cond_func->functype() == Item_func::IN_FUNC)
|
||||||
{ // COND OR
|
{ // COND OR
|
||||||
Item_func_in *func=(Item_func_in*) cond_func;
|
Item_func_in *func=(Item_func_in*) cond_func;
|
||||||
if (func->key_item()->type() == Item::FIELD_ITEM)
|
if (!func->negated && func->key_item()->type() == Item::FIELD_ITEM)
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) (func->key_item()))->field;
|
Field *field=((Item_field*) (func->key_item()))->field;
|
||||||
Item_result cmp_type=field->cmp_type();
|
Item_result cmp_type=field->cmp_type();
|
||||||
|
@@ -2598,7 +2598,12 @@ expr_expr:
|
|||||||
expr IN_SYM '(' expr_list ')'
|
expr IN_SYM '(' expr_list ')'
|
||||||
{ $4->push_front($1); $$= new Item_func_in(*$4); }
|
{ $4->push_front($1); $$= new Item_func_in(*$4); }
|
||||||
| expr NOT IN_SYM '(' expr_list ')'
|
| expr NOT IN_SYM '(' expr_list ')'
|
||||||
{ $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); }
|
{
|
||||||
|
$5->push_front($1);
|
||||||
|
Item_func_in *item= new Item_func_in(*$5);
|
||||||
|
item->negate();
|
||||||
|
$$= item;
|
||||||
|
}
|
||||||
| expr IN_SYM in_subselect
|
| expr IN_SYM in_subselect
|
||||||
{ $$= new Item_in_subselect($1, $3); }
|
{ $$= new Item_in_subselect($1, $3); }
|
||||||
| expr NOT IN_SYM in_subselect
|
| expr NOT IN_SYM in_subselect
|
||||||
@@ -2608,7 +2613,11 @@ expr_expr:
|
|||||||
| expr BETWEEN_SYM no_and_expr AND_SYM expr
|
| expr BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_between($1,$3,$5); }
|
{ $$= new Item_func_between($1,$3,$5); }
|
||||||
| expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
| expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
|
{
|
||||||
|
Item_func_between *item= new Item_func_between($1,$4,$6);
|
||||||
|
item->negate();
|
||||||
|
$$= item;
|
||||||
|
}
|
||||||
| expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
| expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
||||||
| expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
| expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
||||||
| expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
| expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
||||||
@@ -2656,7 +2665,11 @@ no_in_expr:
|
|||||||
no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr
|
no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_between($1,$3,$5); }
|
{ $$= new Item_func_between($1,$3,$5); }
|
||||||
| no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
| no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
|
{
|
||||||
|
Item_func_between *item= new Item_func_between($1,$4,$6);
|
||||||
|
item->negate();
|
||||||
|
$$= item;
|
||||||
|
}
|
||||||
| no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
| no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
||||||
| no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
| no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
||||||
| no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
| no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
||||||
@@ -2704,7 +2717,12 @@ no_and_expr:
|
|||||||
no_and_expr IN_SYM '(' expr_list ')'
|
no_and_expr IN_SYM '(' expr_list ')'
|
||||||
{ $4->push_front($1); $$= new Item_func_in(*$4); }
|
{ $4->push_front($1); $$= new Item_func_in(*$4); }
|
||||||
| no_and_expr NOT IN_SYM '(' expr_list ')'
|
| no_and_expr NOT IN_SYM '(' expr_list ')'
|
||||||
{ $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); }
|
{
|
||||||
|
$5->push_front($1);
|
||||||
|
Item_func_in *item= new Item_func_in(*$5);
|
||||||
|
item->negate();
|
||||||
|
$$= item;
|
||||||
|
}
|
||||||
| no_and_expr IN_SYM in_subselect
|
| no_and_expr IN_SYM in_subselect
|
||||||
{ $$= new Item_in_subselect($1, $3); }
|
{ $$= new Item_in_subselect($1, $3); }
|
||||||
| no_and_expr NOT IN_SYM in_subselect
|
| no_and_expr NOT IN_SYM in_subselect
|
||||||
@@ -2714,7 +2732,11 @@ no_and_expr:
|
|||||||
| no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr
|
| no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_between($1,$3,$5); }
|
{ $$= new Item_func_between($1,$3,$5); }
|
||||||
| no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
| no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
|
||||||
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
|
{
|
||||||
|
Item_func_between *item= new Item_func_between($1,$4,$6);
|
||||||
|
item->negate();
|
||||||
|
$$= item;
|
||||||
|
}
|
||||||
| no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
| no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
|
||||||
| no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
| no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
|
||||||
| no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
| no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
|
||||||
|
Reference in New Issue
Block a user