summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarko@hundin.mysql.fi <>2004-12-30 19:13:31 +0200
committermarko@hundin.mysql.fi <>2004-12-30 19:13:31 +0200
commit3653b08986df34efbac3861b6da3322af7b99b64 (patch)
tree3c55af0695b59ba302cf06e4eb5b0f02a2858e2a
parent551456b30ce34f359ea2d72ca393a4f3c35c940e (diff)
downloadmariadb-git-3653b08986df34efbac3861b6da3322af7b99b64.tar.gz
InnoDB: Remove crash in in-place update from NULL to non-NULL. (Bug #7591)
rem0rec.c: rec_init_offsets(): Make the function comment more accurate. rem0rec.ic: rec_get_nth_field(): Return pointer to the field, even to NULL fields. rec_set_nth_field(): Make more accurate debug assertions.
-rw-r--r--innobase/include/rem0rec.ic11
-rw-r--r--innobase/rem/rem0rec.c26
2 files changed, 20 insertions, 17 deletions
diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic
index b9a79c259a4..7d35e8e4110 100644
--- a/innobase/include/rem0rec.ic
+++ b/innobase/include/rem0rec.ic
@@ -880,7 +880,6 @@ rec_get_nth_field(
length = rec_offs_base(offsets)[1 + n];
if (length & REC_OFFS_SQL_NULL) {
- field = NULL;
length = UNIV_SQL_NULL;
} else {
length &= REC_OFFS_MASK;
@@ -1185,6 +1184,7 @@ rec_set_nth_field(
byte* data2;
ulint len2;
+ ut_ad(rec);
ut_ad(rec_offs_validate(rec, NULL, offsets));
if (len == UNIV_SQL_NULL) {
@@ -1195,14 +1195,15 @@ rec_set_nth_field(
}
data2 = rec_get_nth_field(rec, offsets, n, &len2);
- ut_ad(len2 == len);
-
- ut_memcpy(data2, data, len);
-
if (len2 == UNIV_SQL_NULL) {
ut_ad(!rec_offs_comp(offsets));
rec_set_nth_field_null_bit(rec, n, FALSE);
+ ut_ad(len == rec_get_nth_field_size(rec, n));
+ } else {
+ ut_ad(len2 == len);
}
+
+ ut_memcpy(data2, data, len);
}
/**************************************************************
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 90cbffe7a9e..30f98f457ea 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -137,16 +137,18 @@ rec_validate_old(
rec_t* rec); /* in: physical record */
/**********************************************************
-The following function determines the offsets to each field
-in the record. The offsets are written to an array of
-ulint[n+2], with [0] being the number of fields (n), [1] being the
-extra size (if REC_OFFS_COMPACT is set, the record is in the new
-format), and [2]..[n+1] being the offsets past the end of
-fields 0..n, or to the beginning of fields 1..n+1. When the
-high-order bit of the offset at [n+1] is set (REC_OFFS_SQL_NULL),
-the field n is NULL. When the second high-order bit of the offset
-at [n+1] is set (REC_OFFS_EXTERNAL), the field n is being stored
-externally. */
+The following function determines the offsets to each field in the
+record. The offsets are written to a previously allocated array of
+ulint, where rec_offs_n_fields(offsets) has been initialized to the
+number of fields in the record. The rest of the array will be
+initialized by this function. rec_offs_base(offsets)[0] will be set
+to the extra size (if REC_OFFS_COMPACT is set, the record is in the
+new format), and rec_offs_base(offsets)[1..n_fields] will be set to
+offsets past the end of fields 0..n_fields, or to the beginning of
+fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
+is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
+high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
+field i is being stored externally. */
static
void
rec_init_offsets(
@@ -154,8 +156,8 @@ rec_init_offsets(
/* out: the offsets */
rec_t* rec, /* in: physical record */
dict_index_t* index, /* in: record descriptor */
- ulint* offsets)/* in:/out: ulint[n+2];
- n=rec_offs_n_fields(offsets) */
+ ulint* offsets)/* in/out: array of offsets;
+ in: n=rec_offs_n_fields(offsets) */
{
ulint n_fields = rec_offs_n_fields(offsets);
ulint i = 0;