summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@oracle.com>2011-10-25 17:33:38 +0300
committerMarko Mäkelä <marko.makela@oracle.com>2011-10-25 17:33:38 +0300
commit013ba71dfdd6f9d49730c1a918d1d089976faefd (patch)
tree730c3fbdaf5501f23b6ce997a3c31b77350d169a /storage/innobase
parentdce337406ea07b4581bf724133d5262fddd365f3 (diff)
downloadmariadb-git-013ba71dfdd6f9d49730c1a918d1d089976faefd.tar.gz
Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR
In the ON UPDATE CASCADE clause of FOREIGN KEY constraints, the calculated update vector was not fully initialized. This bug was introduced in the InnoDB Plugin when implementing support for ROW_FORMAT=DYNAMIC. Additionally, the data type information was not initialized, but apparently it has never been needed in this case. Nevertheless, it is not good programming practice to pass uninitialized values around. calc_row_difference(): Declare the update field uninitialized in Valgrind. Copy the data type information as well, except when the field is SQL NULL. In the built-in InnoDB, initialize ufield->extern_storage = FALSE (an initialization bug that had gone unnoticed this far). The InnoDB Plugin and later have this flag to dfield_t and have always initialized it properly. row_ins_cascade_calc_update_vec(): Reduce the scope of some pointers. Initialize orig_len. (This caused the bug in InnoDB Plugin and later.) row_ins_foreign_check_on_constraint(): Simplify a condition. Declare the update vector uninitialized. rb:771 approved by Jimmy Yang
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/handler/ha_innodb.cc10
-rw-r--r--storage/innobase/row/row0ins.c15
2 files changed, 15 insertions, 10 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 2d230e1c297..44b9a7fba36 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4264,14 +4264,16 @@ calc_row_difference(
/* The field has changed */
ufield = uvect->fields + n_changed;
+ UNIV_MEM_INVALID(ufield, sizeof *ufield);
/* Let us use a dummy dfield to make the conversion
from the MySQL column format to the InnoDB format */
- dict_col_copy_type_noninline(prebuilt->table->cols + i,
- &dfield.type);
-
if (n_len != UNIV_SQL_NULL) {
+ dict_col_copy_type_noninline(
+ prebuilt->table->cols + i,
+ &dfield.type);
+
buf = row_mysql_store_col_in_innobase_format(
&dfield,
(byte*)buf,
@@ -4282,11 +4284,13 @@ calc_row_difference(
prebuilt->table));
ufield->new_val.data = dfield.data;
ufield->new_val.len = dfield.len;
+ ufield->new_val.type = dfield.type;
} else {
ufield->new_val.data = NULL;
ufield->new_val.len = UNIV_SQL_NULL;
}
+ ufield->extern_storage = FALSE;
ufield->exp = NULL;
ufield->field_no = dict_col_get_clust_pos_noninline(
&prebuilt->table->cols[i], clust_index);
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index 6366beb6b47..f6e6c81534b 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -425,11 +425,9 @@ row_ins_cascade_calc_update_vec(
dict_table_t* table = foreign->foreign_table;
dict_index_t* index = foreign->foreign_index;
upd_t* update;
- upd_field_t* ufield;
dict_table_t* parent_table;
dict_index_t* parent_index;
upd_t* parent_update;
- upd_field_t* parent_ufield;
ulint n_fields_updated;
ulint parent_field_no;
ulint i;
@@ -465,12 +463,14 @@ row_ins_cascade_calc_update_vec(
dict_index_get_nth_col_no(parent_index, i));
for (j = 0; j < parent_update->n_fields; j++) {
- parent_ufield = parent_update->fields + j;
+ const upd_field_t* parent_ufield
+ = &parent_update->fields[j];
if (parent_ufield->field_no == parent_field_no) {
ulint min_size;
const dict_col_t* col;
+ upd_field_t* ufield;
col = dict_index_get_nth_col(index, i);
@@ -975,10 +975,9 @@ row_ins_foreign_check_on_constraint(
goto nonstandard_exit_func;
}
- if ((node->is_delete
- && (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL))
- || (!node->is_delete
- && (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
+ if (node->is_delete
+ ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
+ : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) {
/* Build the appropriate update vector which sets
foreign->n_fields first fields in rec to SQL NULL */
@@ -987,6 +986,8 @@ row_ins_foreign_check_on_constraint(
update->info_bits = 0;
update->n_fields = foreign->n_fields;
+ UNIV_MEM_INVALID(update->fields,
+ update->n_fields * sizeof *update->fields);
for (i = 0; i < foreign->n_fields; i++) {
(update->fields + i)->field_no