Commit b0dde216 authored by unknown's avatar unknown

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).
parent 36a050d6
......@@ -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;
......
......@@ -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;
......@@ -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);
......
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