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