Commit a73e8189 authored by mskold@mysql.com's avatar mskold@mysql.com

Fix for bug#17899 Partitions: crash, NDB, Select .. ORDER BY

parent 39aa4776
drop table if exists t1;
CREATE TABLE t1 ( f_int1 INTEGER NOT NULL, f_int2 INTEGER NOT NULL,
f_char1 CHAR(10),
f_char2 CHAR(10), f_charbig VARCHAR(1000),
PRIMARY KEY (f_int1,f_int2))
PARTITION BY LIST(MOD(f_int1 + f_int2,4))
(PARTITION part_3 VALUES IN (-3),
PARTITION part_2 VALUES IN (-2),
PARTITION part_1 VALUES IN (-1),
PARTITION part0 VALUES IN (0),
PARTITION part1 VALUES IN (1),
PARTITION part2 VALUES IN (2),
PARTITION part3 VALUES IN (3,4,5));
INSERT INTO t1 SET f_int1 = -2, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 1, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 2, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 3, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 4, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 5, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 20, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
SELECT * FROM t1 ORDER BY f_int1;
f_int1 f_int2 f_char1 f_char2 f_charbig
-2 20 20 20 ===20===
1 1 1 1 ===1===
2 1 1 1 ===1===
3 1 1 1 ===1===
4 1 1 1 ===1===
5 1 1 1 ===1===
20 1 1 1 ===1===
DROP TABLE t1;
CREATE TABLE t1 ( f_int1 INTEGER, f_int2 INTEGER, f_char1 CHAR(10),
f_char2 CHAR(10), f_charbig VARCHAR(1000))
PARTITION BY LIST(f_int1)
(PARTITION part_1 VALUES IN (-1),
PARTITION part0 VALUES IN (0,1),
PARTITION part1 VALUES IN (2));
INSERT INTO t1 SET f_int1 = -1, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 0, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 1, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 2, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 20, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
ERROR HY000: Table has no partition for value 20
SELECT * FROM t1 ORDER BY f_int1;
f_int1 f_int2 f_char1 f_char2 f_charbig
-1 20 20 20 ===20===
0 20 20 20 ===20===
1 1 1 1 ===1===
2 1 1 1 ===1===
DROP TABLE t1;
--source include/have_ndb.inc
#
# Simple test for the partition storage engine
# Focuses on range partitioning tests
#
#-- source include/have_partition.inc
--disable_warnings
drop table if exists t1;
--enable_warnings
#
# Partition by list, basic
#
CREATE TABLE t1 ( f_int1 INTEGER NOT NULL, f_int2 INTEGER NOT NULL,
f_char1 CHAR(10),
f_char2 CHAR(10), f_charbig VARCHAR(1000),
PRIMARY KEY (f_int1,f_int2))
PARTITION BY LIST(MOD(f_int1 + f_int2,4))
(PARTITION part_3 VALUES IN (-3),
PARTITION part_2 VALUES IN (-2),
PARTITION part_1 VALUES IN (-1),
PARTITION part0 VALUES IN (0),
PARTITION part1 VALUES IN (1),
PARTITION part2 VALUES IN (2),
PARTITION part3 VALUES IN (3,4,5));
INSERT INTO t1 SET f_int1 = -2, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 1, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 2, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 3, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 4, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 5, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 20, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
SELECT * FROM t1 ORDER BY f_int1;
DROP TABLE t1;
#
# Partition by list, no pk
#
CREATE TABLE t1 ( f_int1 INTEGER, f_int2 INTEGER, f_char1 CHAR(10),
f_char2 CHAR(10), f_charbig VARCHAR(1000))
PARTITION BY LIST(f_int1)
(PARTITION part_1 VALUES IN (-1),
PARTITION part0 VALUES IN (0,1),
PARTITION part1 VALUES IN (2));
INSERT INTO t1 SET f_int1 = -1, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 0, f_int2 = 20, f_char1 = '20', f_char2 = '20', f_charbig = '===20===';
INSERT INTO t1 SET f_int1 = 1, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
INSERT INTO t1 SET f_int1 = 2, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
--error 1504
INSERT INTO t1 SET f_int1 = 20, f_int2 = 1, f_char1 = '1', f_char2 = '1', f_charbig = '===1===';
SELECT * FROM t1 ORDER BY f_int1;
DROP TABLE t1;
...@@ -954,6 +954,19 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, ...@@ -954,6 +954,19 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
DBUG_RETURN(m_value[fieldnr].rec == NULL); DBUG_RETURN(m_value[fieldnr].rec == NULL);
} }
/*
Instruct NDB to fetch the partition id (fragment id)
*/
int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
{
DBUG_ENTER("get_ndb_partition_id");
uint partition_id_fieldnr= table_share->fields + 1;
m_value[partition_id_fieldnr].rec=
ndb_op->getValue(NdbDictionary::Column::FRAGMENT,
(char *)&m_part_id);
DBUG_RETURN(m_value[partition_id_fieldnr].rec == NULL);
}
/* /*
Check if any set or get of blob value in current query. Check if any set or get of blob value in current query.
...@@ -1646,8 +1659,6 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf, ...@@ -1646,8 +1659,6 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
op->readTuple(lm) != 0) op->readTuple(lm) != 0)
ERR_RETURN(trans->getNdbError()); ERR_RETURN(trans->getNdbError());
if (m_use_partition_function)
op->setPartitionId(part_id);
if (table_share->primary_key == MAX_KEY) if (table_share->primary_key == MAX_KEY)
{ {
// This table has no primary key, use "hidden" primary key // This table has no primary key, use "hidden" primary key
...@@ -1669,6 +1680,17 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf, ...@@ -1669,6 +1680,17 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
if ((res= define_read_attrs(buf, op))) if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res); DBUG_RETURN(res);
if (m_use_partition_function)
{
op->setPartitionId(part_id);
// If table has user defined partitioning
// and no indexes, we need to read the partition id
// to support ORDER BY queries
if (table_share->primary_key == MAX_KEY &&
get_ndb_partition_id(op))
ERR_RETURN(trans->getNdbError());
}
if (execute_no_commit_ie(this,trans) != 0) if (execute_no_commit_ie(this,trans) != 0)
{ {
table->status= STATUS_NOT_FOUND; table->status= STATUS_NOT_FOUND;
...@@ -2187,14 +2209,25 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, ...@@ -2187,14 +2209,25 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
DBUG_RETURN(res); DBUG_RETURN(res);
} }
if (!restart && generate_scan_filter(m_cond_stack, op)) if (!restart)
{
if (generate_scan_filter(m_cond_stack, op))
DBUG_RETURN(ndb_err(trans)); DBUG_RETURN(ndb_err(trans));
if (!restart && (res= define_read_attrs(buf, op))) if (res= define_read_attrs(buf, op))
{ {
DBUG_RETURN(res); DBUG_RETURN(res);
} }
// If table has user defined partitioning
// and no primary key, we need to read the partition id
// to support ORDER BY queries
if (m_use_partition_function &&
(table_share->primary_key == MAX_KEY) &&
(get_ndb_partition_id(op)))
ERR_RETURN(trans->getNdbError());
}
if (execute_no_commit(this,trans) != 0) if (execute_no_commit(this,trans) != 0)
DBUG_RETURN(ndb_err(trans)); DBUG_RETURN(ndb_err(trans));
...@@ -2249,6 +2282,12 @@ int ha_ndbcluster::full_table_scan(byte *buf) ...@@ -2249,6 +2282,12 @@ int ha_ndbcluster::full_table_scan(byte *buf)
*/ */
m_active_cursor->setPartitionId(part_spec.start_part); m_active_cursor->setPartitionId(part_spec.start_part);
} }
// If table has user defined partitioning
// and no primary key, we need to read the partition id
// to support ORDER BY queries
if ((table_share->primary_key == MAX_KEY) &&
(get_ndb_partition_id(op)))
ERR_RETURN(trans->getNdbError());
} }
if (generate_scan_filter(m_cond_stack, op)) if (generate_scan_filter(m_cond_stack, op))
...@@ -3217,17 +3256,32 @@ int ha_ndbcluster::rnd_pos(byte *buf, byte *pos) ...@@ -3217,17 +3256,32 @@ int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
// Perform a pk_read using primary key "index" // Perform a pk_read using primary key "index"
{ {
part_id_range part_spec; part_id_range part_spec;
uint key_length= ref_length;
if (m_use_partition_function) if (m_use_partition_function)
{
if (table_share->primary_key == MAX_KEY)
{
/*
The partition id has been fetched from ndb
and has been stored directly after the hidden key
*/
key_length= ref_length - sizeof(m_part_id);
part_spec.start_part= part_spec.end_part= *(pos + key_length);
}
else
{ {
key_range key_spec; key_range key_spec;
KEY *key_info= table->key_info + active_index; KEY *key_info= table->key_info + active_index;
key_spec.key= pos; key_spec.key= pos;
key_spec.length= ref_length; key_spec.length= key_length;
key_spec.flag= HA_READ_KEY_EXACT; key_spec.flag= HA_READ_KEY_EXACT;
get_full_part_id_from_key(table, buf, key_info, &key_spec, &part_spec); get_full_part_id_from_key(table, buf, key_info,
&key_spec, &part_spec);
DBUG_ASSERT(part_spec.start_part == part_spec.end_part); DBUG_ASSERT(part_spec.start_part == part_spec.end_part);
} }
DBUG_RETURN(pk_read(pos, ref_length, buf, part_spec.start_part)); DBUG_PRINT("info", ("partition id %u", part_spec.start_part));
}
DBUG_RETURN(pk_read(pos, key_length, buf, part_spec.start_part));
} }
} }
...@@ -3244,6 +3298,7 @@ void ha_ndbcluster::position(const byte *record) ...@@ -3244,6 +3298,7 @@ void ha_ndbcluster::position(const byte *record)
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
KEY_PART_INFO *end; KEY_PART_INFO *end;
byte *buff; byte *buff;
uint key_length= ref_length;
DBUG_ENTER("position"); DBUG_ENTER("position");
if (table_share->primary_key != MAX_KEY) if (table_share->primary_key != MAX_KEY)
...@@ -3290,18 +3345,25 @@ void ha_ndbcluster::position(const byte *record) ...@@ -3290,18 +3345,25 @@ void ha_ndbcluster::position(const byte *record)
{ {
// No primary key, get hidden key // No primary key, get hidden key
DBUG_PRINT("info", ("Getting hidden key")); DBUG_PRINT("info", ("Getting hidden key"));
// If table has user defined partition save the partition id as well
if(m_use_partition_function)
{
DBUG_PRINT("info", ("Saving partition id %u in %u", m_part_id));
key_length= ref_length - sizeof(m_part_id);
memcpy(ref+key_length, (void *)&m_part_id, sizeof(m_part_id));
}
#ifndef DBUG_OFF #ifndef DBUG_OFF
int hidden_no= table->s->fields; int hidden_no= table->s->fields;
const NDBTAB *tab= (const NDBTAB *) m_table; const NDBTAB *tab= (const NDBTAB *) m_table;
const NDBCOL *hidden_col= tab->getColumn(hidden_no); const NDBCOL *hidden_col= tab->getColumn(hidden_no);
DBUG_ASSERT(hidden_col->getPrimaryKey() && DBUG_ASSERT(hidden_col->getPrimaryKey() &&
hidden_col->getAutoIncrement() && hidden_col->getAutoIncrement() &&
ref_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH); key_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH);
#endif #endif
memcpy(ref, m_ref, ref_length); memcpy(ref, m_ref, key_length);
} }
DBUG_DUMP("ref", (char*)ref, ref_length); DBUG_DUMP("ref", (char*)ref, key_length);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -5173,8 +5235,17 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked) ...@@ -5173,8 +5235,17 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
{ {
key= table->key_info+table_share->primary_key; key= table->key_info+table_share->primary_key;
ref_length= key->key_length; ref_length= key->key_length;
DBUG_PRINT("info", (" ref_length: %d", ref_length));
} }
else // (table_share->primary_key == MAX_KEY)
{
if (m_use_partition_function)
{
ref_length+= sizeof(m_part_id);
}
}
DBUG_PRINT("info", ("ref_length: %d", ref_length));
// Init table lock structure // Init table lock structure
if (!(m_share=get_share(name, table))) if (!(m_share=get_share(name, table)))
DBUG_RETURN(1); DBUG_RETURN(1);
......
...@@ -761,6 +761,7 @@ static void set_tabname(const char *pathname, char *tabname); ...@@ -761,6 +761,7 @@ static void set_tabname(const char *pathname, char *tabname);
int set_ndb_value(NdbOperation*, Field *field, uint fieldnr, int set_ndb_value(NdbOperation*, Field *field, uint fieldnr,
int row_offset= 0, bool *set_blob_value= 0); int row_offset= 0, bool *set_blob_value= 0);
int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, byte*); int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, byte*);
int ha_ndbcluster::get_ndb_partition_id(NdbOperation *);
friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg); friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
int get_ndb_blobs_value(NdbBlob *last_ndb_blob); int get_ndb_blobs_value(NdbBlob *last_ndb_blob);
int set_primary_key(NdbOperation *op, const byte *key); int set_primary_key(NdbOperation *op, const byte *key);
...@@ -824,6 +825,7 @@ static void set_tabname(const char *pathname, char *tabname); ...@@ -824,6 +825,7 @@ static void set_tabname(const char *pathname, char *tabname);
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
byte m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH]; byte m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH];
partition_info *m_part_info; partition_info *m_part_info;
uint32 m_part_id;
byte *m_rec0; byte *m_rec0;
Field **m_part_field_array; Field **m_part_field_array;
bool m_use_partition_function; bool m_use_partition_function;
......
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