Bug #21143080: UPDATE ON VARCHAR AND TEXT COLUMNS PRODUCE

INCORRECT RESULTS

Issue:
-----
Updating varchar and text fields in the same update
statement can produce incorrect results. When a varchar
field is assigned to the text field and the varchar field
is then set to a different value, the text field's result
contains the varchar field's new value.

SOLUTION:
---------
Currently the blob type does not allocate space for the
string to be stored. Instead it contains a pointer to the
varchar string. So when the varchar field is changed as
part of the update statement, the value contained in the
blob also changes.

The fix would be to actually store the value by allocating
space for the blob's string. We can avoid allocating this
space when the varchar field is not being written into.
This commit is contained in:
Sreeharsha Ramanavarapu 2015-07-16 07:56:39 +05:30
parent e57e1b235e
commit 888fabd690
4 changed files with 47 additions and 10 deletions

View File

@ -551,3 +551,16 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function
DROP VIEW v1;
DROP FUNCTION f1;
DROP TABLE t1;
# Bug #21143080: UPDATE ON VARCHAR AND TEXT COLUMNS PRODUCE INCORRECT
# RESULTS
CREATE TABLE t1 (a VARCHAR(50), b TEXT, c CHAR(50)) ENGINE=INNODB;
INSERT INTO t1 (a, b, c) VALUES ('start trail', '', 'even longer string');
UPDATE t1 SET b = a, a = 'inject';
SELECT a, b FROM t1;
a b
inject start trail
UPDATE t1 SET b = c, c = 'inject';
SELECT c, b FROM t1;
c b
inject even longer string
DROP TABLE t1;

View File

@ -503,3 +503,16 @@ UPDATE v1 SET pk = 7 WHERE pk > 0;
DROP VIEW v1;
DROP FUNCTION f1;
DROP TABLE t1;
--echo # Bug #21143080: UPDATE ON VARCHAR AND TEXT COLUMNS PRODUCE INCORRECT
--echo # RESULTS
CREATE TABLE t1 (a VARCHAR(50), b TEXT, c CHAR(50)) ENGINE=INNODB;
INSERT INTO t1 (a, b, c) VALUES ('start trail', '', 'even longer string');
UPDATE t1 SET b = a, a = 'inject';
SELECT a, b FROM t1;
UPDATE t1 SET b = c, c = 'inject';
SELECT c, b FROM t1;
DROP TABLE t1;

View File

@ -1,7 +1,7 @@
#ifndef FIELD_INCLUDED
#define FIELD_INCLUDED
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -511,6 +511,17 @@ public:
}
/* Hash value */
virtual void hash(ulong *nr, ulong *nr2);
/**
Checks whether a string field is part of write_set.
@return
FALSE - If field is not char/varchar/....
- If field is char/varchar/.. and is not part of write set.
TRUE - If field is char/varchar/.. and is part of write set.
*/
virtual bool is_updatable() const { return FALSE; }
friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
friend class Copy_field;
@ -798,6 +809,11 @@ public:
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
bool is_updatable() const
{
DBUG_ASSERT(table && table->write_set);
return bitmap_is_set(table->write_set, field_index);
}
};
/* base class for float and double and decimal (old one) */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -800,15 +800,10 @@ int field_conv(Field *to,Field *from)
{ // Be sure the value is stored
Field_blob *blob=(Field_blob*) to;
from->val_str(&blob->value);
/*
Copy value if copy_blobs is set, or source is not a string and
we have a pointer to its internal string conversion buffer.
*/
if (to->table->copy_blobs ||
(!blob->value.is_alloced() &&
from->real_type() != MYSQL_TYPE_STRING &&
from->real_type() != MYSQL_TYPE_VARCHAR))
if (!blob->value.is_alloced() && from->is_updatable())
blob->value.copy();
return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
}
if (from->real_type() == MYSQL_TYPE_ENUM &&