Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
1e6736b5
Commit
1e6736b5
authored
Sep 07, 2005
by
igor@rurik.mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge rurik.mysql.com:/home/igor/mysql-4.1
into rurik.mysql.com:/home/igor/dev/mysql-4.1-0
parents
af9740d0
1e187246
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
544 additions
and
63 deletions
+544
-63
client/mysqlimport.c
client/mysqlimport.c
+2
-1
client/mysqltest.c
client/mysqltest.c
+51
-26
mysql-test/r/ctype_utf8.result
mysql-test/r/ctype_utf8.result
+4
-0
mysql-test/r/func_gconcat.result
mysql-test/r/func_gconcat.result
+9
-0
mysql-test/r/func_like.result
mysql-test/r/func_like.result
+7
-0
mysql-test/r/join_outer.result
mysql-test/r/join_outer.result
+133
-0
mysql-test/t/ctype_utf8.test
mysql-test/t/ctype_utf8.test
+6
-0
mysql-test/t/func_gconcat.test
mysql-test/t/func_gconcat.test
+10
-0
mysql-test/t/func_like.test
mysql-test/t/func_like.test
+17
-0
mysql-test/t/join_outer.test
mysql-test/t/join_outer.test
+46
-0
mysql-test/t/mysqltest.test
mysql-test/t/mysqltest.test
+1
-1
sql/examples/ha_tina.cc
sql/examples/ha_tina.cc
+2
-1
sql/item_cmpfunc.cc
sql/item_cmpfunc.cc
+186
-9
sql/item_cmpfunc.h
sql/item_cmpfunc.h
+39
-18
sql/item_sum.cc
sql/item_sum.cc
+1
-0
sql/opt_range.cc
sql/opt_range.cc
+3
-2
sql/sql_yacc.yy
sql/sql_yacc.yy
+27
-5
No files found.
client/mysqlimport.c
View file @
1e6736b5
...
...
@@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object,
const
char
*
statement
);
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
;
static
uint
opt_local_file
=
0
;
static
MYSQL
mysql_connection
;
static
char
*
opt_password
=
0
,
*
current_user
=
0
,
*
current_host
=
0
,
*
current_db
=
0
,
*
fields_terminated
=
0
,
...
...
client/mysqltest.c
View file @
1e6736b5
...
...
@@ -456,6 +456,7 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif
static
void
replace_dynstr_append_mem
(
DYNAMIC_STRING
*
ds
,
const
char
*
val
,
int
len
);
static
int
handle_no_error
(
struct
st_query
*
q
);
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
&&
q
->
expected_errno
[
0
].
code
.
errnum
!=
0
)
if
(
handle_no_error
(
q
))
{
/* 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
);
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
;
error
=
1
;
goto
end
;
}
...
...
@@ -3102,10 +3090,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
{
if
(
q
->
abort_on_error
)
{
die
(
"unable to prepare statement '%s': "
"%s (mysql_stmt_errno=%d returned=%d)"
,
query
,
mysql_stmt_error
(
stmt
),
mysql_stmt_errno
(
stmt
),
err
);
die
(
"query '%s' failed: %d: %s"
,
query
,
mysql_stmt_errno
(
stmt
),
mysql_stmt_error
(
stmt
));
}
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
(
q
->
expected_errno
[
0
].
type
==
ERR_ERRNO
&&
q
->
expected_errno
[
0
].
code
.
errnum
!=
0
)
if
(
handle_no_error
(
q
))
{
verbose_msg
(
"query '%s' succeeded - should have failed with errno %d..."
,
q
->
query
,
q
->
expected_errno
[
0
].
code
.
errnum
);
error
=
1
;
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
);
if
(
i
)
{
if
(
q
->
expected_errno
[
0
].
type
==
ERR_ERRNO
)
verbose_msg
(
"query '%s' failed with wrong errno %d instead of %d..."
,
q
->
query
,
mysql_stmt_errno
(
stmt
),
q
->
expected_errno
[
0
]);
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 */
}
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
;
}
/*
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
\****************************************************************************/
...
...
mysql-test/r/ctype_utf8.result
View file @
1e6736b5
...
...
@@ -955,6 +955,10 @@ char_length(a) length(a) a
2 4 ан
drop table t1;
set names utf8;
select 'andre%' like 'andreñ%' escape 'ñ';
'andre%' like 'andreñ%' escape 'ñ'
1
set names utf8;
select 'a\\' like 'a\\';
'a\\' like 'a\\'
1
...
...
mysql-test/r/func_gconcat.result
View file @
1e6736b5
...
...
@@ -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'
drop table t1;
drop table t2;
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850);
INSERT INTO t1 VALUES ('');
SELECT a FROM t1;
a
SELECT GROUP_CONCAT(a) FROM t1;
GROUP_CONCAT(a)
DROP TABLE t1;
CREATE TABLE t1 (id int);
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
gc
...
...
mysql-test/r/func_like.result
View file @
1e6736b5
...
...
@@ -158,3 +158,10 @@ DROP TABLE t1;
select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin;
_cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin
1
set names koi8r;
select 'andre%' like 'andre%' escape '';
'andre%' like 'andre%' escape ''
1
select _cp1251'andre%' like convert('andre%' using cp1251) escape '';
_cp1251'andre%' like convert('andre%' using cp1251) escape ''
1
mysql-test/r/join_outer.result
View file @
1e6736b5
...
...
@@ -883,3 +883,136 @@ Warnings:
Warning 1260 2 line(s) were cut by GROUP_CONCAT()
drop table t1, t2;
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;
mysql-test/t/ctype_utf8.test
View file @
1e6736b5
...
...
@@ -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
;
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
...
...
mysql-test/t/func_gconcat.test
View file @
1e6736b5
...
...
@@ -281,6 +281,16 @@ select collation(group_concat(a,b)) from t1;
drop
table
t1
;
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
(
''
);
SELECT
a
FROM
t1
;
SELECT
GROUP_CONCAT
(
a
)
FROM
t1
;
DROP
TABLE
t1
;
#
# bug #7769: group_concat returning null is checked in having
#
...
...
mysql-test/t/func_like.test
View file @
1e6736b5
...
...
@@ -96,4 +96,21 @@ DROP TABLE t1;
#
select
_cp866
'aaaaaaaaa'
like
_cp866
'%aaaa%'
collate
cp866_bin
;
#
# Check 8bit escape character
#
set
names
koi8r
;
select
'andre%'
like
'andre%'
escape
''
;
# 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%'
using
cp1251
)
escape
''
;
#
# End of 4.1 tests
mysql-test/t/join_outer.test
View file @
1e6736b5
...
...
@@ -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
;
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
mysql-test/t/mysqltest.test
View file @
1e6736b5
...
...
@@ -592,7 +592,7 @@ while ($num)
--
source
var
/
tmp
/
sourced1
.
sql
dec
$num
;
}
--
enable_abort_on_error
;
--
enable_abort_on_error
--
enable_query_log
# ----------------------------------------------------------------------------
...
...
sql/examples/ha_tina.cc
View file @
1e6736b5
...
...
@@ -609,6 +609,7 @@ int ha_tina::rnd_init(bool scan)
records
=
0
;
chain_ptr
=
chain
;
#ifdef HAVE_MADVISE
if
(
scan
)
(
void
)
madvise
(
share
->
mapped_file
,
share
->
file_stat
.
st_size
,
MADV_SEQUENTIAL
);
#endif
...
...
sql/item_cmpfunc.cc
View file @
1e6736b5
...
...
@@ -820,6 +820,54 @@ longlong Item_func_interval::val_int()
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
()
{
max_length
=
1
;
...
...
@@ -871,8 +919,9 @@ longlong Item_func_between::val_int()
a
=
args
[
1
]
->
val_str
(
&
value1
);
b
=
args
[
2
]
->
val_str
(
&
value2
);
if
(
!
args
[
1
]
->
null_value
&&
!
args
[
2
]
->
null_value
)
return
(
sortcmp
(
value
,
a
,
cmp_collation
.
collation
)
>=
0
&&
sortcmp
(
value
,
b
,
cmp_collation
.
collation
)
<=
0
)
?
1
:
0
;
return
(
longlong
)
((
sortcmp
(
value
,
a
,
cmp_collation
.
collation
)
>=
0
&&
sortcmp
(
value
,
b
,
cmp_collation
.
collation
)
<=
0
)
!=
negated
);
if
(
args
[
1
]
->
null_value
&&
args
[
2
]
->
null_value
)
null_value
=
1
;
else
if
(
args
[
1
]
->
null_value
)
...
...
@@ -894,7 +943,7 @@ longlong Item_func_between::val_int()
a
=
args
[
1
]
->
val_int
();
b
=
args
[
2
]
->
val_int
();
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
)
null_value
=
1
;
else
if
(
args
[
1
]
->
null_value
)
...
...
@@ -914,7 +963,7 @@ longlong Item_func_between::val_int()
a
=
args
[
1
]
->
val
();
b
=
args
[
2
]
->
val
();
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
)
null_value
=
1
;
else
if
(
args
[
1
]
->
null_value
)
...
...
@@ -926,7 +975,7 @@ longlong Item_func_between::val_int()
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
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
)
{
return
cs
->
coll
->
strnncollsp
(
cs
,
...
...
@@ -1840,7 +1982,7 @@ longlong Item_func_in::val_int()
{
int
tmp
=
array
->
find
(
args
[
0
]);
null_value
=
args
[
0
]
->
null_value
||
(
!
tmp
&&
have_null
);
return
tmp
;
return
(
longlong
)
(
!
null_value
&&
tmp
!=
negated
)
;
}
in_item
->
store_value
(
args
[
0
]);
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
++
)
{
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
;
}
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 */
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
...
...
sql/item_cmpfunc.h
View file @
1e6736b5
...
...
@@ -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
;
public:
Item_result
cmp_type
;
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
();
optimize_type
select_optimize
()
const
{
return
OPTIMIZE_KEY
;
}
enum
Functype
functype
()
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
print
(
String
*
str
);
CHARSET_INFO
*
compare_collation
()
{
return
cmp_collation
.
collation
;
}
...
...
@@ -433,15 +465,9 @@ public:
longlong
val_int
();
String
*
val_str
(
String
*
str
);
enum
Item_result
result_type
()
const
{
return
cached_result_type
;
}
bool
fix_fields
(
THD
*
thd
,
struct
st_table_list
*
tlist
,
Item
**
ref
)
{
DBUG_ASSERT
(
fixed
==
0
);
args
[
0
]
->
top_level_item
();
return
Item_func
::
fix_fields
(
thd
,
tlist
,
ref
);
}
bool
fix_fields
(
THD
*
,
struct
st_table_list
*
,
Item
**
);
void
fix_length_and_dec
();
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
;
in_vector
*
array
;
...
...
@@ -745,11 +771,12 @@ class Item_func_in :public Item_int_func
DTCollation
cmp_collation
;
public:
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
}
longlong
val_int
();
bool
fix_fields
(
THD
*
,
struct
st_table_list
*
,
Item
**
);
void
fix_length_and_dec
();
void
cleanup
()
{
...
...
@@ -769,12 +796,6 @@ class Item_func_in :public Item_int_func
bool
nulls_in_row
();
bool
is_bool_func
()
{
return
1
;
}
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 */
...
...
@@ -879,7 +900,7 @@ class Item_func_like :public Item_bool_func2
Item
*
escape_item
;
public:
char
escape
;
int
escape
;
Item_func_like
(
Item
*
a
,
Item
*
b
,
Item
*
escape_arg
)
:
Item_bool_func2
(
a
,
b
),
canDoTurboBM
(
FALSE
),
pattern
(
0
),
pattern_len
(
0
),
...
...
sql/item_sum.cc
View file @
1e6736b5
...
...
@@ -1937,6 +1937,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
args
,
arg_count
,
MY_COLL_ALLOW_CONV
))
return
1
;
result
.
set_charset
(
collation
.
collation
);
result_field
=
0
;
null_value
=
1
;
max_length
=
group_concat_max_len
;
...
...
sql/opt_range.cc
View file @
1e6736b5
...
...
@@ -849,7 +849,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
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
;
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
)
{
// COND OR
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
;
Item_result
cmp_type
=
field
->
cmp_type
();
...
...
sql/sql_yacc.yy
View file @
1e6736b5
...
...
@@ -2598,7 +2598,12 @@ expr_expr:
expr IN_SYM '(' expr_list ')'
{ $4->push_front($1); $$= new Item_func_in(*$4); }
| 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
{ $$= new Item_in_subselect($1, $3); }
| expr NOT IN_SYM in_subselect
...
...
@@ -2608,7 +2613,11 @@ expr_expr:
| expr BETWEEN_SYM no_and_expr AND_SYM expr
{ $$= new Item_func_between($1,$3,$5); }
| 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_SYM expr { $$= new Item_cond_or($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
{ $$= new Item_func_between($1,$3,$5); }
| 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_SYM expr { $$= new Item_cond_or($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 ')'
{ $4->push_front($1); $$= new Item_func_in(*$4); }
| 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
{ $$= new Item_in_subselect($1, $3); }
| 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
{ $$= new Item_func_between($1,$3,$5); }
| 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_SYM expr { $$= new Item_cond_or($1,$3); }
| no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment