diff options
author | unknown <svoj@mysql.com/april.(none)> | 2008-02-14 16:27:01 +0400 |
---|---|---|
committer | unknown <svoj@mysql.com/april.(none)> | 2008-02-14 16:27:01 +0400 |
commit | 55f6727b708d99562b48ba5391a43ec235375125 (patch) | |
tree | cdd454142b5832960821036c7bef3be056a90650 | |
parent | 863b86db2485dddbfdbb8200531b7af265daa5db (diff) | |
download | mariadb-git-55f6727b708d99562b48ba5391a43ec235375125.tar.gz |
BUG#33946 - Join on Federated tables with Unique index gives error 1430
from storage engine
Federated may crash a server, return wrong result set, return
"ERROR 1030 (HY000): Got error 1430 from storage engine" message
when local (engine=federated) table has a key against nullable
column.
The problem was wrong implementation of function that creates
WHERE clause for remote query from key.
mysql-test/r/federated.result:
A test case for BUG#33946.
mysql-test/t/federated.test:
A test case for BUG#33946.
sql/ha_federated.cc:
Fixed that federated adds " IS NULL " condition to a remote query,
whereas "IS NOT NULL" requested by original query.
Fixed that federated didn't check for end of key buffer, didn't
setup key buffer pointer and remaining lenght of key buffer,
didn't add " AND " between conditions in case original query
has IS [NOT] NULL condition against nullable column.
Fixed that federated wrongly shifts key buffer pointer by extra
one byte when key part may be null (was: store_length + 1,
now: store_length).
-rw-r--r-- | mysql-test/r/federated.result | 24 | ||||
-rw-r--r-- | mysql-test/t/federated.test | 21 | ||||
-rw-r--r-- | sql/ha_federated.cc | 22 |
3 files changed, 64 insertions, 3 deletions
diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index a005db4deac..3a934e7fe3c 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -2045,6 +2045,30 @@ select 1 from t1 order by a; drop table t1; drop table t1; drop view v1; +CREATE TABLE t1 (a INT, b INT, KEY(a,b)); +INSERT INTO t1 VALUES(NULL,1),(1,NULL),(NULL,NULL),(1,1),(2,2); +CREATE TABLE t1 (a INT, b INT, KEY(a,b)) ENGINE=federated +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1'; +SELECT * FROM t1 WHERE a IS NULL; +a b +NULL NULL +NULL 1 +SELECT * FROM t1 WHERE a IS NOT NULL; +a b +1 NULL +1 1 +2 2 +SELECT * FROM t1 WHERE a=1 AND b=1; +a b +1 1 +SELECT * FROM t1 WHERE a IS NULL AND b=1; +a b +NULL 1 +SELECT * FROM t1 WHERE a IS NOT NULL AND b=1; +a b +1 1 +DROP TABLE t1; +DROP TABLE t1; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index d4f22650a32..934db5cd68b 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1716,5 +1716,26 @@ connection slave; drop table t1; drop view v1; +# +# BUG#33946 - Join on Federated tables with Unique index gives error 1430 +# from storage engine +# +connection slave; +CREATE TABLE t1 (a INT, b INT, KEY(a,b)); +INSERT INTO t1 VALUES(NULL,1),(1,NULL),(NULL,NULL),(1,1),(2,2); + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE t1 (a INT, b INT, KEY(a,b)) ENGINE=federated +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1'; +SELECT * FROM t1 WHERE a IS NULL; +SELECT * FROM t1 WHERE a IS NOT NULL; +SELECT * FROM t1 WHERE a=1 AND b=1; +SELECT * FROM t1 WHERE a IS NULL AND b=1; +SELECT * FROM t1 WHERE a IS NOT NULL AND b=1; +DROP TABLE t1; + +connection slave; +DROP TABLE t1; source include/federated_cleanup.inc; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index ac1e0962ffb..c0743bd6c9a 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1094,10 +1094,20 @@ bool ha_federated::create_where_from_key(String *to, { if (*ptr++) { + /* + We got "IS [NOT] NULL" condition against nullable column. We + distinguish between "IS NOT NULL" and "IS NULL" by flag. For + "IS NULL", flag is set to HA_READ_KEY_EXACT. + */ if (emit_key_part_name(&tmp, key_part) || - tmp.append(FEDERATED_ISNULL)) + tmp.append(ranges[i]->flag == HA_READ_KEY_EXACT ? + FEDERATED_ISNULL : " IS NOT NULL ")) DBUG_RETURN(1); - continue; + /* + We need to adjust pointer and length to be prepared for next + key part. As well as check if this was last key part. + */ + goto prepare_for_next_key_part; } } @@ -1199,12 +1209,18 @@ bool ha_federated::create_where_from_key(String *to, if (tmp.append(FEDERATED_CLOSEPAREN)) DBUG_RETURN(1); +prepare_for_next_key_part: if (store_length >= length) break; DBUG_PRINT("info", ("remainder %d", remainder)); DBUG_ASSERT(remainder > 1); length-= store_length; - ptr+= store_length; + /* + For nullable columns, null-byte is already skipped before, that is + ptr was incremented by 1. Since store_length still counts null-byte, + we need to subtract 1 from store_length. + */ + ptr+= store_length - test(key_part->null_bit); if (tmp.append(FEDERATED_AND)) DBUG_RETURN(1); |