summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <holyfoot/hf@mysql.com/hfmain.(none)>2007-04-19 21:43:42 +0500
committerunknown <holyfoot/hf@mysql.com/hfmain.(none)>2007-04-19 21:43:42 +0500
commit611456362f520bd5b3380e7cf90cfb2aaadd18be (patch)
tree0eaec27c535b248bcfac6751f1bea94265b8d1cd
parentcc76701e8f47ca52ca209150f49ba665a215c1d0 (diff)
downloadmariadb-git-611456362f520bd5b3380e7cf90cfb2aaadd18be.tar.gz
Bug #27123 (partition + on duplicate key update + varchar = Can't find
record in table) key_restore function didn't work as intended in the case of VARCHAR or BLOB fields, stored the restored key in field->ptr instead of to_record. That produced the wrong key so search returned wrong result mysql-test/r/partition.result: result added mysql-test/t/partition.test: testcase sql/field.cc: Field_blob::store_length made static sql/field.h: Field_blob::store_length and set_ptr functions implemented in slightly different way sql/ha_ndbcluster.cc: set_ptr_offset used sql/key.cc: set key_part->field->ptr to the proper place inside the to_record so the restored key will be placed there as key_restore is supposed to behave
-rw-r--r--mysql-test/r/partition.result8
-rw-r--r--mysql-test/t/partition.test11
-rw-r--r--sql/field.cc2
-rw-r--r--sql/field.h17
-rw-r--r--sql/ha_ndbcluster.cc8
-rw-r--r--sql/key.cc23
6 files changed, 53 insertions, 16 deletions
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result
index 2e5fa4b9195..46b704dc7b7 100644
--- a/mysql-test/r/partition.result
+++ b/mysql-test/r/partition.result
@@ -1238,4 +1238,12 @@ t2 CREATE TABLE `t2` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (i) (PARTITION p01 VALUES LESS THAN (1000) ENGINE = MyISAM) */
DROP TABLE t1, t2;
set @@sql_mode=@org_mode;
+create table t1 (c1 varchar(255),c2 tinyint,primary key(c1))
+partition by key (c1) partitions 10 ;
+insert into t1 values ('aaa','1') on duplicate key update c2 = c2 + 1;
+insert into t1 values ('aaa','1') on duplicate key update c2 = c2 + 1;
+select * from t1;
+c1 c2
+aaa 2
+drop table t1;
End of 5.1 tests
diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test
index 399f3c4a41d..d6421b0ca3d 100644
--- a/mysql-test/t/partition.test
+++ b/mysql-test/t/partition.test
@@ -1492,4 +1492,15 @@ show create table t2;
DROP TABLE t1, t2;
set @@sql_mode=@org_mode;
+#
+# Bug #27123 partition + on duplicate key update + varchar = Can't find record in <table>
+#
+create table t1 (c1 varchar(255),c2 tinyint,primary key(c1))
+ partition by key (c1) partitions 10 ;
+insert into t1 values ('aaa','1') on duplicate key update c2 = c2 + 1;
+insert into t1 values ('aaa','1') on duplicate key update c2 = c2 + 1;
+select * from t1;
+drop table t1;
+
+
--echo End of 5.1 tests
diff --git a/sql/field.cc b/sql/field.cc
index a48a3ff7bcd..240c48bdf0c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6969,7 +6969,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
}
-void Field_blob::store_length(uint32 number)
+void Field_blob::store_length(char *ptr, uint packlength, uint32 number)
{
switch (packlength) {
case 1:
diff --git a/sql/field.h b/sql/field.h
index 3d1ac7528c1..ac26ce13477 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1274,7 +1274,12 @@ public:
}
int reset(void) { bzero(ptr, packlength+sizeof(char*)); return 0; }
void reset_fields() { bzero((char*) &value,sizeof(value)); }
- void store_length(uint32 number);
+ static void store_length(char *ptr, uint packlength, uint32 number);
+ inline void store_length(uint32 number)
+ {
+ store_length(ptr, packlength, number);
+ }
+
inline uint32 get_length(uint row_offset=0)
{ return get_length(ptr+row_offset); }
uint32 get_length(const char *ptr);
@@ -1292,11 +1297,17 @@ public:
memcpy(ptr,length,packlength);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
+ void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length,char *data)
+ {
+ char *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,char*);
+ store_length(ptr_ofs, packlength, length);
+ memcpy_fixed(ptr_ofs+packlength,&data,sizeof(char*));
+ }
inline void set_ptr(uint32 length,char *data)
{
- store_length(length);
- memcpy_fixed(ptr+packlength,&data,sizeof(char*));
+ set_ptr_offset(0, length, data);
}
+
void get_key_image(char *buff,uint length, imagetype type);
void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 5a0f27073d4..5f5e4d3ed51 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -853,9 +853,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
i, offset, (long) buf, len, (int)ptrdiff));
DBUG_ASSERT(len == len64);
// Ugly hack assumes only ptr needs to be changed
- field_blob->ptr+= ptrdiff;
- field_blob->set_ptr(len, buf);
- field_blob->ptr-= ptrdiff;
+ field_blob->set_ptr_offset(ptrdiff, len, buf);
}
offset+= size;
}
@@ -864,9 +862,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
// have to set length even in this case
char *buf= buffer + offset; // or maybe NULL
uint32 len= 0;
- field_blob->ptr+= ptrdiff;
- field_blob->set_ptr(len, buf);
- field_blob->ptr-= ptrdiff;
+ field_blob->set_ptr_offset(ptrdiff, len, buf);
DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull));
}
}
diff --git a/sql/key.cc b/sql/key.cc
index faa7bf1f04b..5054998bd99 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -221,23 +221,34 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
}
if (key_part->key_part_flag & HA_BLOB_PART)
{
+ /*
+ This in fact never happens, as we have only partial BLOB
+ keys yet anyway, so it's difficult to find any sence to
+ restore the part of a record.
+ Maybe this branch is to be removed, but now we
+ have to ignore GCov compaining.
+ */
uint blob_length= uint2korr(from_key);
+ Field_blob *field= (Field_blob*) key_part->field;
from_key+= HA_KEY_BLOB_LENGTH;
key_length-= HA_KEY_BLOB_LENGTH;
- ((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
- (char*) from_key);
+ field->set_ptr_offset(to_record - field->table->record[0],
+ (ulong) blob_length, (char*) from_key);
length= key_part->length;
}
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
{
+ Field *field= key_part->field;
my_bitmap_map *old_map;
+ my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
+ field->move_field_offset(ptrdiff);
key_length-= HA_KEY_BLOB_LENGTH;
length= min(key_length, key_part->length);
- old_map= dbug_tmp_use_all_columns(key_part->field->table,
- key_part->field->table->write_set);
- key_part->field->set_key_image((char *) from_key, length);
- dbug_tmp_restore_column_map(key_part->field->table->write_set, old_map);
+ old_map= dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ field->set_key_image((char *) from_key, length);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
from_key+= HA_KEY_BLOB_LENGTH;
+ field->move_field_offset(-ptrdiff);
}
else
{