From 9de5a2424fff878e6f0074bc6b214f065b4c494e Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Wed, 7 Nov 2007 09:30:41 +0100 Subject: [PATCH] Bug#22351 - handler::index_next_same() call to key_cmp_if_same() uses the wrong buffer handler::index_next_same() did not take into account that the internally called function key_cmp_if_same() uses the fixed buffer table->record[0] for key comparison instead of the buffer provided by the caller of handler::index_next_same(). Added code to temporarily redirect table->record[0] and the fields used for the key to the record buffer provided by the caller of handler::index_next_same(). The test case is in partition.test already. --- sql/handler.cc | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index 75c3a64bc27..7891661cefc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2522,15 +2522,56 @@ int ha_enable_transaction(THD *thd, bool on) int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) { int error; + DBUG_ENTER("index_next_same"); if (!(error=index_next(buf))) { + my_ptrdiff_t ptrdiff= buf - table->record[0]; + uchar *save_record_0; + KEY *key_info; + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + LINT_INIT(save_record_0); + LINT_INIT(key_info); + LINT_INIT(key_part); + LINT_INIT(key_part_end); + + /* + key_cmp_if_same() compares table->record[0] against 'key'. + In parts it uses table->record[0] directly, in parts it uses + field objects with their local pointers into table->record[0]. + If 'buf' is distinct from table->record[0], we need to move + all record references. This is table->record[0] itself and + the field pointers of the fields used in this key. + */ + if (ptrdiff) + { + save_record_0= table->record[0]; + table->record[0]= buf; + key_info= table->key_info + active_index; + key_part= key_info->key_part; + key_part_end= key_part + key_info->key_parts; + for (; key_part < key_part_end; key_part++) + { + DBUG_ASSERT(key_part->field); + key_part->field->move_field_offset(ptrdiff); + } + } + if (key_cmp_if_same(table, key, active_index, keylen)) { table->status=STATUS_NOT_FOUND; error=HA_ERR_END_OF_FILE; } + + /* Move back if necessary. */ + if (ptrdiff) + { + table->record[0]= save_record_0; + for (key_part= key_info->key_part; key_part < key_part_end; key_part++) + key_part->field->move_field_offset(-ptrdiff); + } } - return error; + DBUG_RETURN(error); }