Commit 51bd08c8 authored by Marko Mäkelä's avatar Marko Mäkelä

Fix instant ADD after instant DROP

row_metadata_to_tuple(), row_rec_to_index_entry_impl():
Add the parameter "pad" to determine whether
the tuple should be padded to the index fields (on ALTER TABLE it should),
or whether it should remain at its original size (on rollback).

trx_undo_page_report_modify(): Avoid out-of-bounds access to record fields.

row_quiesce_write_index_fields(): Do not crash when the table contains
an instantly dropped column.
parent 5180257c
......@@ -56,6 +56,7 @@ ROLLBACK;
InnoDB 0 transactions not purged
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
connect ddl, localhost, root;
ALTER TABLE t2 DROP COLUMN c3;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum');
connection default;
......@@ -69,12 +70,12 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
SELECT * FROM t1;
id c2
SELECT * FROM t2;
id c2 c3
2 1 De finibus bonorum
16 1551 Omnium enim rerum
64 42 De finibus bonorum
128 1571 principia parva sunt
347 33101 et malorum
id c2
2 1
64 42
16 1551
128 1571
347 33101
BEGIN;
INSERT INTO t1 SET id=1;
DELETE FROM t2;
......@@ -87,26 +88,27 @@ header=0x010000030074 (id=0x696e66696d756d00)
header=0x010008030000 (id=0x73757072656d756d00)
t2 clustered index root page(type 18):
N_RECS=6; LEVEL=0
header=0x010000030088 (id=0x696e66696d756d00)
header=0x1000100b00b9 (id=0x80000000,
DB_TRX_ID=0x000000000000,
DB_ROLL_PTR=0x80000000000000,
header=0x01000003008f (id=0x696e66696d756d00)
header=0x3000100c00d4 (id=0x80000000,
DB_TRX_ID=0x000000000042,
DB_ROLL_PTR=0x060000013a03a8,
BLOB=0x0000000600000006000000260000000000000008,
c2=NULL(4 bytes),
c3=0x44652066696e6962757320626f6e6f72756d)
header=0x0000180900d9 (id=0x80000002,
header=0x0000180900f4 (id=0x80000002,
DB_TRX_ID=0x000000000000,
DB_ROLL_PTR=0x80000000000000,
c2=0x80000001)
header=0x0000200b013e (id=0x80000010,
header=0x0000200b0124 (id=0x80000010,
DB_TRX_ID=0x000000000000,
DB_ROLL_PTR=0x80000000000000,
c2=0x8000060f,
c3=0x4f6d6e69756d20656e696d20726572756d)
header=0x00003009010a (id=0x80000040,
header=0x000028090144 (id=0x80000040,
DB_TRX_ID=0x000000000000,
DB_ROLL_PTR=0x80000000000000,
c2=0x8000002a)
header=0x0000280b015e (id=0x80000080,
header=0x0000300b0179 (id=0x80000080,
DB_TRX_ID=0x000000000000,
DB_ROLL_PTR=0x80000000000000,
c2=0x80000623,
......@@ -133,7 +135,6 @@ Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL,
`c2` int(11) DEFAULT NULL,
`c3` text NOT NULL DEFAULT 'De finibus bonorum',
PRIMARY KEY (`id`),
UNIQUE KEY `c2` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
......
......@@ -74,6 +74,7 @@ ROLLBACK;
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
connect ddl, localhost, root;
ALTER TABLE t2 DROP COLUMN c3;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
--send
ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum');
......@@ -124,16 +125,38 @@ for (my $offset= 0x65; $offset;
my $n_fields= unpack("n", substr($page,$offset-4,2)) >> 1 & 0x3ff;
my $start= 0;
my $name;
for (my $i= 0; $i < $n_fields; $i++) {
my $end= unpack("C", substr($page, $offset-7-$i, 1));
print ",\n " if $i;
print "$fields[$i]=";
if ($end & 0x80) {
print "NULL(", ($end & 0x7f) - $start, " bytes)"
} else {
print "0x", unpack("H*", substr($page,$offset+$start,$end-$start))
if (unpack("C", substr($page,$offset-3,1)) & 1) {
for (my $i= 0; $i < $n_fields; $i++) {
my $end= unpack("C", substr($page, $offset-7-$i, 1));
print ",\n " if $i;
print "$fields[$i]=";
if ($end & 0x80) {
print "NULL(", ($end & 0x7f) - $start, " bytes)"
} else {
print "0x", unpack("H*", substr($page,$offset+$start,$end-$start))
}
$start= $end & 0x7f;
}
} else {
for (my $i= 0; $i < $n_fields; $i++) {
my $end= unpack("n", substr($page, $offset-8-2*$i, 2));
print ",\n " if $i;
if ($i > 2 && !(~unpack("C",substr($page,$offset-6,1)) & 0x30)) {
if ($i == 3) {
print "BLOB=";
} else {
print "$fields[$i - 1]=";
}
} else {
print "$fields[$i]=";
}
if ($end & 0x8000) {
print "NULL(", ($end & 0x7fff) - $start, " bytes)"
} else {
print "0x", unpack("H*", substr($page,$offset+$start,($end-$start) & 0x3fff))
}
$start= $end & 0x3fff;
}
$start= $end & 0x7f;
}
print ")\n";
}
......
......@@ -4732,9 +4732,10 @@ btr_cur_pessimistic_update(
ut_ad(update->is_metadata());
ut_ad(flags & BTR_NO_LOCKING_FLAG);
ut_ad(index->is_instant());
new_entry = row_metadata_to_tuple(rec, index, *offsets,
&n_ext, entry_heap,
update->info_bits);
new_entry = row_metadata_to_tuple(
rec, index, *offsets,
&n_ext, entry_heap,
update->info_bits, !thr_get_trx(thr)->in_rollback);
ut_ad(new_entry->n_fields
== ulint(index->n_fields)
+ update->is_alter_metadata());
......
......@@ -238,7 +238,8 @@ row_rec_to_index_entry(
@param[in] offsets rec_get_offsets(rec)
@param[out] n_ext number of externally stored fields
@param[in,out] heap memory heap for allocations
@param[in] info_bits the info_bits after an update */
@param[in] info_bits the info_bits after an update
@param[in] pad whether to pad to index->n_fields */
dtuple_t*
row_metadata_to_tuple(
const rec_t* rec,
......@@ -246,7 +247,8 @@ row_metadata_to_tuple(
const ulint* offsets,
ulint* n_ext,
mem_heap_t* heap,
ulint info_bits)
ulint info_bits,
bool pad)
MY_ATTRIBUTE((nonnull,warn_unused_result));
/*******************************************************************//**
......
......@@ -73,17 +73,16 @@ row_quiesce_write_index_fields(
return(DB_IO_ERROR);
}
const char* field_name = field->name ? field->name : "";
/* Include the NUL byte in the length. */
ib_uint32_t len = static_cast<ib_uint32_t>(strlen(field->name) + 1);
ut_a(len > 1);
ib_uint32_t len = static_cast<ib_uint32_t>(strlen(field_name) + 1);
mach_write_to_4(row, len);
DBUG_EXECUTE_IF("ib_export_io_write_failure_10",
close(fileno(file)););
if (fwrite(row, 1, sizeof(len), file) != sizeof(len)
|| fwrite(field->name, 1, len, file) != len) {
|| fwrite(field_name, 1, len, file) != len) {
ib_senderrf(
thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
......
......@@ -709,6 +709,7 @@ row_build_w_add_vcol(
@param[out] n_ext number of externally stored columns
@param[in,out] heap memory heap for allocations
@param[in] info_bits (only used if mblob=2)
@param[in] pad (only used if mblob=2)
@return index entry built; does not set info_bits, and the data fields
in the entry will point directly to rec */
template<bool metadata, int mblob = 0>
......@@ -720,7 +721,8 @@ row_rec_to_index_entry_impl(
const ulint* offsets,
ulint* n_ext,
mem_heap_t* heap,
ulint info_bits = 0)
ulint info_bits = 0,
bool pad = false)
{
ut_ad(rec != NULL);
ut_ad(heap != NULL);
......@@ -741,9 +743,15 @@ row_rec_to_index_entry_impl(
ut_ad(info_bits == REC_INFO_METADATA_ALTER
|| info_bits == REC_INFO_METADATA_ADD);
ut_ad(rec_len <= ulint(index->n_fields + got));
rec_len += !got && info_bits == REC_INFO_METADATA_ALTER;
if (pad) {
rec_len = ulint(index->n_fields)
+ (info_bits == REC_INFO_METADATA_ALTER);
} else if (!got && info_bits == REC_INFO_METADATA_ALTER) {
rec_len++;
}
} else {
ut_ad(info_bits == 0);
ut_ad(!pad);
}
dtuple_t* entry = dtuple_create(heap, rec_len);
dfield_t* dfield = entry->fields;
......@@ -825,6 +833,14 @@ row_rec_to_index_entry_impl(
for (; i < rec_len; i++, dfield++) {
dict_col_copy_type(dict_index_get_nth_col(index, j++),
&dfield->type);
if (mblob == 2 && pad
&& i >= rec_offs_n_fields(offsets)) {
field = index->instant_field_value(j - 1,
&len);
dfield_set_data(dfield, field, len);
continue;
}
field = rec_get_nth_field(rec, offsets, i, &len);
dfield_set_data(dfield, field, len);
......@@ -913,7 +929,8 @@ row_rec_to_index_entry(
@param[in] offsets rec_get_offsets(rec)
@param[out] n_ext number of externally stored fields
@param[in,out] heap memory heap for allocations
@param[in] info_bits the info_bits after an update */
@param[in] info_bits the info_bits after an update
@param[in] pad whether to pad to index->n_fields */
dtuple_t*
row_metadata_to_tuple(
const rec_t* rec,
......@@ -921,7 +938,8 @@ row_metadata_to_tuple(
const ulint* offsets,
ulint* n_ext,
mem_heap_t* heap,
ulint info_bits)
ulint info_bits,
bool pad)
{
ut_ad(info_bits == REC_INFO_METADATA_ALTER
|| info_bits == REC_INFO_METADATA_ADD);
......@@ -939,7 +957,7 @@ row_metadata_to_tuple(
dtuple_t* entry = info_bits == REC_INFO_METADATA_ALTER
|| rec_is_alter_metadata(copy_rec, *index)
? row_rec_to_index_entry_impl<true,2>(
copy_rec, index, offsets, n_ext, heap, info_bits)
copy_rec, index, offsets, n_ext, heap, info_bits, pad)
: row_rec_to_index_entry_impl<true>(
copy_rec, index, offsets, n_ext, heap);
......
......@@ -1165,7 +1165,8 @@ trx_undo_page_report_modify(
return 0;
}
if (rec_offs_nth_extern(offsets, pos)) {
if (rec_offs_n_fields(offsets) > pos
&& rec_offs_nth_extern(offsets, pos)) {
ut_ad(col || pos == index->first_user_field());
ut_ad(col || update->is_alter_metadata());
ut_ad(col
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment