summaryrefslogtreecommitdiff
path: root/storage/innobase/rem
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2018-05-03 15:17:16 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-05-03 15:17:16 +0300
commit6c43068d6342bd1a7c1dbb24079ac4da4ba9b4ff (patch)
treeba126c01ece73aaa499dcd592c0144b227b1d6f0 /storage/innobase/rem
parent01843d191094d524428c786d4fd6310d4b6f9224 (diff)
downloadmariadb-git-6c43068d6342bd1a7c1dbb24079ac4da4ba9b4ff.tar.gz
MDEV-15060 Assertion in row_log_table_apply_op after instant ADD when the table is emptied during subsequent ALTER TABLE
During an online table rebuild, a table could be emptied and converted from 'instant ADD' format to plain (pre-10.3) format. All online_log records for rebuilding the table must be written and parsed in the format of the table that existed at the start of the operation. row_log_t::n_core_fields: A new field for recording index->n_core_fields when online ALTER is initiated in row_log_allocate(). row_log_t::is_instant(): Determine if the log is in the instant format. Only invoked by the row_log_table_ family of functions. dict_index_t::get_n_nullable(): Remove is_instant() debug assertions. Because a table can be converted to non-instant format during a table-rebuilding ALTER TABLE, these assertions would be bogus when executing row_log_table_apply(). rec_init_offsets_temp(): Add the parameter n_core for passing the original index->n_core_fields. rec_init_offsets_temp(): Add a 3-parameter variant. rec_init_offsets_comp_ordinary(): Add the parameter n_core for passing the index->n_core_fields.
Diffstat (limited to 'storage/innobase/rem')
-rw-r--r--storage/innobase/rem/rem0rec.cc48
1 files changed, 36 insertions, 12 deletions
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
index 6da2866b0c1..7d1a35d82e4 100644
--- a/storage/innobase/rem/rem0rec.cc
+++ b/storage/innobase/rem/rem0rec.cc
@@ -298,6 +298,7 @@ in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED.
This is a special case of rec_init_offsets() and rec_get_offsets_func().
@param[in] rec leaf-page record
@param[in] index the index that the record belongs in
+@param[in] n_core number of core fields (index->n_core_fields)
@param[in,out] offsets offsets, with valid rec_offs_n_fields(offsets)
@param[in] format record format */
static inline
@@ -306,17 +307,19 @@ rec_init_offsets_comp_ordinary(
const rec_t* rec,
const dict_index_t* index,
ulint* offsets,
+ ulint n_core,
rec_leaf_format format)
{
ulint offs = 0;
ulint any = 0;
const byte* nulls = rec;
const byte* lens = NULL;
- ulint n_fields = index->n_core_fields;
+ ulint n_fields = n_core;
ulint null_mask = 1;
- ut_ad(index->n_core_fields > 0);
- ut_ad(index->n_fields >= index->n_core_fields);
+ ut_ad(index->n_core_fields >= n_core);
+ ut_ad(n_core > 0);
+ ut_ad(index->n_fields >= n_core);
ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable));
ut_ad(format == REC_LEAF_TEMP || format == REC_LEAF_TEMP_COLUMNS_ADDED
|| dict_table_is_comp(index->table));
@@ -344,17 +347,17 @@ ordinary:
/* We would have !index->is_instant() when rolling back
an instant ADD COLUMN operation. */
nulls -= REC_N_NEW_EXTRA_BYTES;
+ ut_ad(index->is_instant());
/* fall through */
case REC_LEAF_TEMP_COLUMNS_ADDED:
- ut_ad(index->is_instant());
- n_fields = unsigned(index->n_core_fields) + 1
- + rec_get_n_add_field(nulls);
+ n_fields = n_core + 1 + rec_get_n_add_field(nulls);
ut_ad(n_fields <= index->n_fields);
const ulint n_nullable = index->get_n_nullable(n_fields);
const ulint n_null_bytes = UT_BITS_IN_BYTES(n_nullable);
ut_d(n_null = n_nullable);
ut_ad(n_null <= index->n_nullable);
- ut_ad(n_null_bytes >= index->n_core_null_bytes);
+ ut_ad(n_null_bytes >= index->n_core_null_bytes
+ || n_core < index->n_core_fields);
lens = --nulls - n_null_bytes;
}
@@ -614,11 +617,13 @@ rec_init_offsets(
case REC_STATUS_COLUMNS_ADDED:
ut_ad(leaf);
rec_init_offsets_comp_ordinary(rec, index, offsets,
+ index->n_core_fields,
REC_LEAF_COLUMNS_ADDED);
return;
case REC_STATUS_ORDINARY:
ut_ad(leaf);
rec_init_offsets_comp_ordinary(rec, index, offsets,
+ index->n_core_fields,
REC_LEAF_ORDINARY);
return;
}
@@ -1689,25 +1694,44 @@ rec_get_converted_size_temp(
@param[in] rec temporary file record
@param[in] index index of that the record belongs to
@param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets)
-@param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED
-*/
+@param[in] n_core number of core fields (index->n_core_fields)
+@param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED */
void
rec_init_offsets_temp(
const rec_t* rec,
const dict_index_t* index,
ulint* offsets,
+ ulint n_core,
rec_comp_status_t status)
{
ut_ad(status == REC_STATUS_ORDINARY
|| status == REC_STATUS_COLUMNS_ADDED);
- ut_ad(status == REC_STATUS_ORDINARY || index->is_instant());
-
- rec_init_offsets_comp_ordinary(rec, index, offsets,
+ /* The table may have been converted to plain format
+ if it was emptied during an ALTER TABLE operation. */
+ ut_ad(index->n_core_fields == n_core || !index->is_instant());
+ ut_ad(index->n_core_fields >= n_core);
+ rec_init_offsets_comp_ordinary(rec, index, offsets, n_core,
status == REC_STATUS_COLUMNS_ADDED
? REC_LEAF_TEMP_COLUMNS_ADDED
: REC_LEAF_TEMP);
}
+/** Determine the offset to each field in temporary file.
+@param[in] rec temporary file record
+@param[in] index index of that the record belongs to
+@param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets)
+*/
+void
+rec_init_offsets_temp(
+ const rec_t* rec,
+ const dict_index_t* index,
+ ulint* offsets)
+{
+ ut_ad(!index->is_instant());
+ rec_init_offsets_comp_ordinary(rec, index, offsets,
+ index->n_core_fields, REC_LEAF_TEMP);
+}
+
/** Convert a data tuple prefix to the temporary file format.
@param[out] rec record in temporary file format
@param[in] index clustered or secondary index