diff --git a/mysql-test/r/ndb_partition_range.result b/mysql-test/r/ndb_partition_range.result index 546c0b1196c..5297e2a733d 100644 --- a/mysql-test/r/ndb_partition_range.result +++ b/mysql-test/r/ndb_partition_range.result @@ -223,3 +223,41 @@ SELECT * FROM t1; id b1 vc bc d f total y t 2 NULL NULL NULL NULL NULL NULL NULL NULL DROP TABLE t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), +partition x234 values in (4,7,8)); +INSERT into t1 VALUES (5,1,1); +select * from t1; +a b c +5 1 1 +UPDATE t1 SET a=8 WHERE a=5 AND b=1; +select * from t1; +a b c +8 1 1 +drop table t1; +CREATE TABLE t1 ( f1 INTEGER, f2 char(20)) engine=ndb +PARTITION BY RANGE(f1) +( PARTITION part1 VALUES LESS THAN (2), +PARTITION part2 VALUES LESS THAN (1000)); +INSERT INTO t1 VALUES(1, '---1---'); +INSERT INTO t1 VALUES(2, '---2---'); +select * from t1; +f1 f2 +1 ---1--- +2 ---2--- +UPDATE t1 SET f1 = f1 + 4 WHERE f1 = 2; +select * from t1; +f1 f2 +1 ---1--- +6 ---2--- +UPDATE t1 SET f1 = f1 + 4 WHERE f1 = 1; +select * from t1; +f1 f2 +5 ---1--- +6 ---2--- +drop table t1; diff --git a/mysql-test/t/ndb_partition_range.test b/mysql-test/t/ndb_partition_range.test index 5b70b26c97b..e64dc80886a 100644 --- a/mysql-test/t/ndb_partition_range.test +++ b/mysql-test/t/ndb_partition_range.test @@ -227,3 +227,34 @@ ALTER TABLE t1 ADD PARTITION (PARTITION p2 VALUES IN (412)); SELECT * FROM t1; DROP TABLE t1; + +# +# Bug #17806 Update on NDB table with list partition causes mysqld to core +# Bug #16385 Partitions: crash when updating a range partitioned NDB table +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), + partition x234 values in (4,7,8)); +INSERT into t1 VALUES (5,1,1); +select * from t1; +UPDATE t1 SET a=8 WHERE a=5 AND b=1; +select * from t1; +drop table t1; + +CREATE TABLE t1 ( f1 INTEGER, f2 char(20)) engine=ndb +PARTITION BY RANGE(f1) +( PARTITION part1 VALUES LESS THAN (2), +PARTITION part2 VALUES LESS THAN (1000)); +INSERT INTO t1 VALUES(1, '---1---'); +INSERT INTO t1 VALUES(2, '---2---'); +select * from t1; +UPDATE t1 SET f1 = f1 + 4 WHERE f1 = 2; +select * from t1; +UPDATE t1 SET f1 = f1 + 4 WHERE f1 = 1; +select * from t1; +drop table t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 17b999f8134..dc95ead2e97 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1684,15 +1684,16 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf, /* Read one complementing record from NDB using primary key from old_data + or hidden key */ -int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data, - uint32 old_part_id) +int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data, + uint32 old_part_id) { uint no_fields= table_share->fields, i; NdbTransaction *trans= m_active_trans; NdbOperation *op; - DBUG_ENTER("complemented_pk_read"); + DBUG_ENTER("complemented_read"); m_write_op= FALSE; if (ha_get_all_bit_in_read_set()) @@ -1706,9 +1707,17 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data, if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) || op->readTuple(lm) != 0) ERR_RETURN(trans->getNdbError()); - int res; - if ((res= set_primary_key_from_record(op, old_data))) - ERR_RETURN(trans->getNdbError()); + if (table_share->primary_key != MAX_KEY) + { + if (set_primary_key_from_record(op, old_data)) + ERR_RETURN(trans->getNdbError()); + } + else + { + // This table has no primary key, use "hidden" primary key + if (set_hidden_key(op, table->s->fields, m_ref)) + ERR_RETURN(op->getNdbError()); + } if (m_use_partition_function) op->setPartitionId(old_part_id); @@ -2501,19 +2510,23 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) DBUG_RETURN(error); } - /* Check for update of primary key for special handling */ - if ((table_share->primary_key != MAX_KEY) && - (key_cmp(table_share->primary_key, old_data, new_data)) || + /* + * Check for update of primary key or partition change + * for special handling + */ + if (((table_share->primary_key != MAX_KEY) && + key_cmp(table_share->primary_key, old_data, new_data)) || (old_part_id != new_part_id)) { int read_res, insert_res, delete_res, undo_res; - DBUG_PRINT("info", ("primary key update, doing pk read+delete+insert")); + DBUG_PRINT("info", ("primary key update or partition change, " + "doing read+delete+insert")); // Get all old fields, since we optimize away fields not in query - read_res= complemented_pk_read(old_data, new_data, old_part_id); + read_res= complemented_read(old_data, new_data, old_part_id); if (read_res) { - DBUG_PRINT("info", ("pk read failed")); + DBUG_PRINT("info", ("read failed")); DBUG_RETURN(read_res); } // Delete old row diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 5a65dcc0531..7498d2bb624 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -731,8 +731,8 @@ private: char* get_tablespace_name(THD *thd); int set_range_data(void *tab, partition_info* part_info); int set_list_data(void *tab, partition_info* part_info); - int complemented_pk_read(const byte *old_data, byte *new_data, - uint32 old_part_id); + int complemented_read(const byte *old_data, byte *new_data, + uint32 old_part_id); int pk_read(const byte *key, uint key_len, byte *buf, uint32 part_id); int ordered_index_scan(const key_range *start_key, const key_range *end_key,