Commit 9c16460e authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.3 into 10.4

parents 747dccfe 0e1ba364
...@@ -687,7 +687,23 @@ DROP TABLE t1,t2; ...@@ -687,7 +687,23 @@ DROP TABLE t1,t2;
# End of 10.0 tests # End of 10.0 tests
# #
# #
# Start of 10.4 tests # MDEV-17551
# Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
# pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
# thread)' failed in _ma_state_info_write or ER_CRASHED_ON_USAGE
# upon SELECT with UNION
#
CREATE TABLE t1 (b BLOB, vb BLOB AS (b) VIRTUAL);
INSERT INTO t1 (b) VALUES ('foobar');
SELECT 'foo' AS f1, CONVERT( 'bar' USING latin1 ) AS f2 FROM t1
UNION
SELECT b AS f1, CONVERT( vb USING latin1 ) AS f2 FROM t1;
f1 f2
foo bar
foobar foobar
DROP TABLE t1;
#
# End of 10.3 tests
# #
SET sql_mode=''; SET sql_mode='';
CREATE TABLE t1 (c VARCHAR(1) DEFAULT 'foo'); CREATE TABLE t1 (c VARCHAR(1) DEFAULT 'foo');
......
...@@ -329,9 +329,23 @@ DROP TABLE t1,t2; ...@@ -329,9 +329,23 @@ DROP TABLE t1,t2;
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #
--echo #
--echo # MDEV-17551
--echo # Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
--echo # pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
--echo # thread)' failed in _ma_state_info_write or ER_CRASHED_ON_USAGE
--echo # upon SELECT with UNION
--echo #
CREATE TABLE t1 (b BLOB, vb BLOB AS (b) VIRTUAL);
INSERT INTO t1 (b) VALUES ('foobar');
SELECT 'foo' AS f1, CONVERT( 'bar' USING latin1 ) AS f2 FROM t1
UNION
SELECT b AS f1, CONVERT( vb USING latin1 ) AS f2 FROM t1;
DROP TABLE t1;
--echo # --echo #
--echo # Start of 10.4 tests --echo # End of 10.3 tests
--echo # --echo #
SET sql_mode=''; SET sql_mode='';
......
...@@ -110,7 +110,7 @@ SET debug_sync='alter_table_intermediate_table_created SIGNAL ready WAIT_FOR go' ...@@ -110,7 +110,7 @@ SET debug_sync='alter_table_intermediate_table_created SIGNAL ready WAIT_FOR go'
ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE; ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE;
connect con1, localhost, root; connect con1, localhost, root;
SET debug_sync='now WAIT_FOR ready'; SET debug_sync='now WAIT_FOR ready';
SET lock_wait_timeout=1; SET lock_wait_timeout=0;
UPDATE t2 SET pk=10 WHERE pk=1; UPDATE t2 SET pk=10 WHERE pk=1;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction ERROR HY000: Lock wait timeout exceeded; try restarting transaction
PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1';
......
...@@ -264,6 +264,33 @@ a b c d ...@@ -264,6 +264,33 @@ a b c d
2 3 4 1 2 3 4 1
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-19916 Corruption after instant ADD/DROP and shrinking the tree
#
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
SET @old_limit = @@innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug = 2;
INSERT INTO t1 VALUES (1),(5),(4),(3),(2);
SET GLOBAL innodb_limit_optimistic_insert_debug = @old_limit;
ALTER TABLE t1 ADD COLUMN b INT, ALGORITHM=INSTANT;
SET @old_defragment = @@innodb_defragment;
SET GLOBAL innodb_defragment = 1;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
SET GLOBAL innodb_defragment = @old_defragment;
ALTER TABLE t1 ADD vb INT AS (b) VIRTUAL;
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
SELECT * FROM t1;
a b vb
1 NULL NULL
2 NULL NULL
3 NULL NULL
4 NULL NULL
5 NULL NULL
DROP TABLE t1;
#
# MDEV-17899 Assertion failures on rollback of instant ADD/DROP # MDEV-17899 Assertion failures on rollback of instant ADD/DROP
# MDEV-18098 Crash after rollback of instant DROP COLUMN # MDEV-18098 Crash after rollback of instant DROP COLUMN
# #
...@@ -299,5 +326,5 @@ SELECT variable_value-@old_instant instants ...@@ -299,5 +326,5 @@ SELECT variable_value-@old_instant instants
FROM information_schema.global_status FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
instants instants
21 22
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
...@@ -140,7 +140,7 @@ send ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE; ...@@ -140,7 +140,7 @@ send ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE;
connect con1, localhost, root; connect con1, localhost, root;
SET debug_sync='now WAIT_FOR ready'; SET debug_sync='now WAIT_FOR ready';
SET lock_wait_timeout=1; # change to 0 in 10.3 SET lock_wait_timeout=0;
--error ER_LOCK_WAIT_TIMEOUT --error ER_LOCK_WAIT_TIMEOUT
UPDATE t2 SET pk=10 WHERE pk=1; UPDATE t2 SET pk=10 WHERE pk=1;
PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1';
......
...@@ -300,6 +300,31 @@ SET DEBUG_SYNC = RESET; ...@@ -300,6 +300,31 @@ SET DEBUG_SYNC = RESET;
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-19916 Corruption after instant ADD/DROP and shrinking the tree
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
# Create an index tree with 2 levels of node pointer pages.
SET @old_limit = @@innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug = 2;
INSERT INTO t1 VALUES (1),(5),(4),(3),(2);
SET GLOBAL innodb_limit_optimistic_insert_debug = @old_limit;
ALTER TABLE t1 ADD COLUMN b INT, ALGORITHM=INSTANT;
SET @old_defragment = @@innodb_defragment;
SET GLOBAL innodb_defragment = 1;
OPTIMIZE TABLE t1;
SET GLOBAL innodb_defragment = @old_defragment;
# Exploit MDEV-17468 to force the table definition to be reloaded
ALTER TABLE t1 ADD vb INT AS (b) VIRTUAL;
CHECK TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
--echo # --echo #
--echo # MDEV-17899 Assertion failures on rollback of instant ADD/DROP --echo # MDEV-17899 Assertion failures on rollback of instant ADD/DROP
--echo # MDEV-18098 Crash after rollback of instant DROP COLUMN --echo # MDEV-18098 Crash after rollback of instant DROP COLUMN
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
CREATE TABLE t1 (c VARBINARY(65534)); CREATE TABLE t1 (c VARBINARY(65534));
CREATE TABLE t1 (c VARBINARY(65535)); CREATE TABLE t1 (c VARBINARY(65535));
Like VARCHAR(65536), they will be converted to BLOB automatically Like VARCHAR(65536), they will be converted to BLOB automatically
in non-sctict mode. in non-strict mode.
*/ */
#define MAX_FIELD_VARCHARLENGTH (65535-2-1) #define MAX_FIELD_VARCHARLENGTH (65535-2-1)
#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ #define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */
......
/* /*
Copyright (c) 2015 MariaDB Foundation. Copyright (c) 2015,2019 MariaDB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -1173,6 +1173,8 @@ Type_handler::string_type_handler(uint max_octet_length) ...@@ -1173,6 +1173,8 @@ Type_handler::string_type_handler(uint max_octet_length)
return &type_handler_long_blob; return &type_handler_long_blob;
else if (max_octet_length >= 65536) else if (max_octet_length >= 65536)
return &type_handler_medium_blob; return &type_handler_medium_blob;
else if (max_octet_length >= MAX_FIELD_VARCHARLENGTH)
return &type_handler_blob;
return &type_handler_varchar; return &type_handler_varchar;
} }
...@@ -2256,6 +2258,7 @@ Field *Type_handler_varchar::make_conversion_table_field(TABLE *table, ...@@ -2256,6 +2258,7 @@ Field *Type_handler_varchar::make_conversion_table_field(TABLE *table,
const Field *target) const Field *target)
const const
{ {
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH);
return new(table->in_use->mem_root) return new(table->in_use->mem_root)
Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata), Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata),
(uchar *) "", 1, Field::NONE, &empty_clex_str, (uchar *) "", 1, Field::NONE, &empty_clex_str,
...@@ -3326,6 +3329,8 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, ...@@ -3326,6 +3329,8 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
TABLE *table) const TABLE *table) const
{ {
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <=
MAX_FIELD_VARCHARLENGTH);
return new (table->in_use->mem_root) return new (table->in_use->mem_root)
Field_varstring(addr.ptr(), attr.max_length, Field_varstring(addr.ptr(), attr.max_length,
HA_VARCHAR_PACKLENGTH(attr.max_length), HA_VARCHAR_PACKLENGTH(attr.max_length),
......
...@@ -3494,7 +3494,8 @@ btr_lift_page_up( ...@@ -3494,7 +3494,8 @@ btr_lift_page_up(
/* btr_page_empty() is supposed to zero-initialize the field. */ /* btr_page_empty() is supposed to zero-initialize the field. */
ut_ad(!page_get_instant(father_block->frame)); ut_ad(!page_get_instant(father_block->frame));
if (page_level == 0 && index->is_instant()) { if (index->is_instant()
&& father_block->page.id.page_no() == root_page_no) {
ut_ad(!father_page_zip); ut_ad(!father_page_zip);
btr_set_instant(father_block, *index, mtr); btr_set_instant(father_block, *index, mtr);
} }
......
...@@ -2366,18 +2366,11 @@ page_validate( ...@@ -2366,18 +2366,11 @@ page_validate(
the page record type definition */ the page record type definition */
{ {
const page_dir_slot_t* slot; const page_dir_slot_t* slot;
mem_heap_t* heap;
byte* buf;
ulint count;
ulint own_count;
ulint rec_own_count;
ulint slot_no;
ulint data_size;
const rec_t* rec; const rec_t* rec;
const rec_t* old_rec = NULL; const rec_t* old_rec = NULL;
ulint offs; ulint offs;
ulint n_slots; ulint n_slots;
ibool ret = FALSE; ibool ret = TRUE;
ulint i; ulint i;
ulint* offsets = NULL; ulint* offsets = NULL;
ulint* old_offsets = NULL; ulint* old_offsets = NULL;
...@@ -2391,7 +2384,13 @@ page_validate( ...@@ -2391,7 +2384,13 @@ page_validate(
if (UNIV_UNLIKELY((ibool) !!page_is_comp(page) if (UNIV_UNLIKELY((ibool) !!page_is_comp(page)
!= dict_table_is_comp(index->table))) { != dict_table_is_comp(index->table))) {
ib::error() << "'compact format' flag mismatch"; ib::error() << "'compact format' flag mismatch";
goto func_exit2; func_exit2:
ib::error() << "Apparent corruption in space "
<< page_get_space_id(page) << " page "
<< page_get_page_no(page)
<< " of index " << index->name
<< " of table " << index->table->name;
return FALSE;
} }
if (page_is_comp(page)) { if (page_is_comp(page)) {
if (UNIV_UNLIKELY(!page_simple_validate_new(page))) { if (UNIV_UNLIKELY(!page_simple_validate_new(page))) {
...@@ -2416,19 +2415,12 @@ page_validate( ...@@ -2416,19 +2415,12 @@ page_validate(
if (max_trx_id == 0 || max_trx_id > sys_max_trx_id) { if (max_trx_id == 0 || max_trx_id > sys_max_trx_id) {
ib::error() << "PAGE_MAX_TRX_ID out of bounds: " ib::error() << "PAGE_MAX_TRX_ID out of bounds: "
<< max_trx_id << ", " << sys_max_trx_id; << max_trx_id << ", " << sys_max_trx_id;
goto func_exit2; ret = FALSE;
} }
} else { } else {
ut_ad(srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN); ut_ad(srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN);
} }
heap = mem_heap_create(srv_page_size + 200);
/* The following buffer is used to check that the
records in the page record heap do not overlap */
buf = static_cast<byte*>(mem_heap_zalloc(heap, srv_page_size));
/* Check first that the record heap and the directory do not /* Check first that the record heap and the directory do not
overlap. */ overlap. */
...@@ -2437,20 +2429,45 @@ page_validate( ...@@ -2437,20 +2429,45 @@ page_validate(
if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP) if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP)
<= page_dir_get_nth_slot(page, n_slots - 1)))) { <= page_dir_get_nth_slot(page, n_slots - 1)))) {
ib::warn() << "Record heap and dir overlap on space " ib::warn() << "Record heap and directory overlap";
<< page_get_space_id(page) << " page " goto func_exit2;
<< page_get_page_no(page) << " index " << index->name }
<< ", " << page_header_get_ptr(page, PAGE_HEAP_TOP)
<< ", " << page_dir_get_nth_slot(page, n_slots - 1);
goto func_exit; switch (uint16_t type = fil_page_get_type(page)) {
case FIL_PAGE_RTREE:
if (!index->is_spatial()) {
wrong_page_type:
ib::warn() << "Wrong page type " << type;
ret = FALSE;
}
break;
case FIL_PAGE_TYPE_INSTANT:
if (index->is_instant()
&& page_get_page_no(page) == index->page) {
break;
}
goto wrong_page_type;
case FIL_PAGE_INDEX:
if (index->is_spatial()) {
goto wrong_page_type;
}
if (index->is_instant()
&& page_get_page_no(page) == index->page) {
goto wrong_page_type;
}
break;
default:
goto wrong_page_type;
} }
/* The following buffer is used to check that the
records in the page record heap do not overlap */
mem_heap_t* heap = mem_heap_create(srv_page_size + 200);;
byte* buf = static_cast<byte*>(mem_heap_zalloc(heap, srv_page_size));
/* Validate the record list in a loop checking also that /* Validate the record list in a loop checking also that
it is consistent with the directory. */ it is consistent with the directory. */
count = 0; ulint count = 0, data_size = 0, own_count = 1, slot_no = 0;
data_size = 0;
own_count = 1;
slot_no = 0; slot_no = 0;
slot = page_dir_get_nth_slot(page, slot_no); slot = page_dir_get_nth_slot(page, slot_no);
...@@ -2465,11 +2482,13 @@ page_validate( ...@@ -2465,11 +2482,13 @@ page_validate(
&& UNIV_UNLIKELY(rec_get_node_ptr_flag(rec) && UNIV_UNLIKELY(rec_get_node_ptr_flag(rec)
== page_is_leaf(page))) { == page_is_leaf(page))) {
ib::error() << "'node_ptr' flag mismatch"; ib::error() << "'node_ptr' flag mismatch";
goto func_exit; ret = FALSE;
goto next_rec;
} }
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) { if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
goto func_exit; ret = FALSE;
goto next_rec;
} }
/* Check that the records are in the ascending order */ /* Check that the records are in the ascending order */
...@@ -2481,16 +2500,10 @@ page_validate( ...@@ -2481,16 +2500,10 @@ page_validate(
/* For spatial index, on nonleaf leavel, we /* For spatial index, on nonleaf leavel, we
allow recs to be equal. */ allow recs to be equal. */
bool rtr_equal_nodeptrs = if (ret <= 0 && !(ret == 0 && index->is_spatial()
(ret == 0 && dict_index_is_spatial(index) && !page_is_leaf(page))) {
&& !page_is_leaf(page));
if (ret <= 0 && !rtr_equal_nodeptrs) { ib::error() << "Records in wrong order";
ib::error() << "Records in wrong order on"
" space " << page_get_space_id(page)
<< " page " << page_get_page_no(page)
<< " index " << index->name;
fputs("\nInnoDB: previous record ", stderr); fputs("\nInnoDB: previous record ", stderr);
/* For spatial index, print the mbr info.*/ /* For spatial index, print the mbr info.*/
...@@ -2511,7 +2524,7 @@ page_validate( ...@@ -2511,7 +2524,7 @@ page_validate(
putc('\n', stderr); putc('\n', stderr);
} }
goto func_exit; ret = FALSE;
} }
} }
...@@ -2531,41 +2544,41 @@ page_validate( ...@@ -2531,41 +2544,41 @@ page_validate(
offs = page_offset(rec_get_start(rec, offsets)); offs = page_offset(rec_get_start(rec, offsets));
i = rec_offs_size(offsets); i = rec_offs_size(offsets);
if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { if (UNIV_UNLIKELY(offs + i >= srv_page_size)) {
ib::error() << "Record offset out of bounds"; ib::error() << "Record offset out of bounds: "
goto func_exit; << offs << '+' << i;
ret = FALSE;
goto next_rec;
} }
while (i--) { while (i--) {
if (UNIV_UNLIKELY(buf[offs + i])) { if (UNIV_UNLIKELY(buf[offs + i])) {
/* No other record may overlap this */ ib::error() << "Record overlaps another: "
ib::error() << "Record overlaps another"; << offs << '+' << i;
goto func_exit; ret = FALSE;
break;
} }
buf[offs + i] = 1; buf[offs + i] = 1;
} }
if (page_is_comp(page)) { if (ulint rec_own_count = page_is_comp(page)
rec_own_count = rec_get_n_owned_new(rec); ? rec_get_n_owned_new(rec)
} else { : rec_get_n_owned_old(rec)) {
rec_own_count = rec_get_n_owned_old(rec);
}
if (UNIV_UNLIKELY(rec_own_count != 0)) {
/* This is a record pointed to by a dir slot */ /* This is a record pointed to by a dir slot */
if (UNIV_UNLIKELY(rec_own_count != own_count)) { if (UNIV_UNLIKELY(rec_own_count != own_count)) {
ib::error() << "Wrong owned count " ib::error() << "Wrong owned count at " << offs
<< rec_own_count << ", " << own_count; << ": " << rec_own_count
goto func_exit; << ", " << own_count;
ret = FALSE;
} }
if (page_dir_slot_get_rec(slot) != rec) { if (page_dir_slot_get_rec(slot) != rec) {
ib::error() << "Dir slot does not" ib::error() << "Dir slot does not"
" point to right rec"; " point to right rec at " << offs;
goto func_exit; ret = FALSE;
} }
page_dir_slot_check(slot); if (ret) {
page_dir_slot_check(slot);
}
own_count = 0; own_count = 0;
if (!page_rec_is_supremum(rec)) { if (!page_rec_is_supremum(rec)) {
...@@ -2574,6 +2587,7 @@ page_validate( ...@@ -2574,6 +2587,7 @@ page_validate(
} }
} }
next_rec:
if (page_rec_is_supremum(rec)) { if (page_rec_is_supremum(rec)) {
break; break;
} }
...@@ -2598,14 +2612,14 @@ page_validate( ...@@ -2598,14 +2612,14 @@ page_validate(
} }
} else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) { } else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
n_owned_zero: n_owned_zero:
ib::error() << "n owned is zero"; ib::error() << "n owned is zero at " << offs;
goto func_exit; ret = FALSE;
} }
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) { if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
ib::error() << "n slots wrong " << slot_no << " " ib::error() << "n slots wrong " << slot_no << " "
<< (n_slots - 1); << (n_slots - 1);
goto func_exit; ret = FALSE;
} }
if (UNIV_UNLIKELY(ulint(page_header_get_field(page, PAGE_N_RECS)) if (UNIV_UNLIKELY(ulint(page_header_get_field(page, PAGE_N_RECS))
...@@ -2614,65 +2628,57 @@ page_validate( ...@@ -2614,65 +2628,57 @@ page_validate(
ib::error() << "n recs wrong " ib::error() << "n recs wrong "
<< page_header_get_field(page, PAGE_N_RECS) << page_header_get_field(page, PAGE_N_RECS)
+ PAGE_HEAP_NO_USER_LOW << " " << (count + 1); + PAGE_HEAP_NO_USER_LOW << " " << (count + 1);
goto func_exit; ret = FALSE;
} }
if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) { if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) {
ib::error() << "Summed data size " << data_size ib::error() << "Summed data size " << data_size
<< ", returned by func " << page_get_data_size(page); << ", returned by func " << page_get_data_size(page);
goto func_exit; ret = FALSE;
} }
/* Check then the free list */ /* Check then the free list */
rec = page_header_get_ptr(page, PAGE_FREE); for (rec = page_header_get_ptr(page, PAGE_FREE);
rec;
while (rec != NULL) { rec = page_rec_get_next_const(rec)) {
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
page_is_leaf(page), page_is_leaf(page),
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) { if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
ret = FALSE;
goto func_exit; continue;
} }
count++; count++;
offs = page_offset(rec_get_start(rec, offsets)); offs = page_offset(rec_get_start(rec, offsets));
i = rec_offs_size(offsets); i = rec_offs_size(offsets);
if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { if (UNIV_UNLIKELY(offs + i >= srv_page_size)) {
ib::error() << "Record offset out of bounds"; ib::error() << "Free record offset out of bounds: "
goto func_exit; << offs << '+' << i;
ret = FALSE;
continue;
} }
while (i--) { while (i--) {
if (UNIV_UNLIKELY(buf[offs + i])) { if (UNIV_UNLIKELY(buf[offs + i])) {
ib::error() << "Record overlaps another" ib::error() << "Free record overlaps another: "
" in free list"; << offs << '+' << i;
goto func_exit; ret = FALSE;
break;
} }
buf[offs + i] = 1; buf[offs + i] = 1;
} }
rec = page_rec_get_next_const(rec);
} }
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) { if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
ib::error() << "N heap is wrong " ib::error() << "N heap is wrong "
<< page_dir_get_n_heap(page) << " " << count + 1; << page_dir_get_n_heap(page) << " " << count + 1;
goto func_exit; ret = FALSE;
} }
ret = TRUE;
func_exit:
mem_heap_free(heap); mem_heap_free(heap);
if (UNIV_UNLIKELY(ret == FALSE)) { if (UNIV_UNLIKELY(!ret)) {
func_exit2: goto func_exit2;
ib::error() << "Apparent corruption in space "
<< page_get_space_id(page) << " page "
<< page_get_page_no(page) << " index " << index->name;
} }
return(ret); return(ret);
......
...@@ -5432,7 +5432,12 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param) ...@@ -5432,7 +5432,12 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
info->cur_row.checksum= (*share->calc_check_checksum)(info, info->cur_row.checksum= (*share->calc_check_checksum)(info,
sort_param-> sort_param->
record); record);
reclength= _ma_rec_pack(info,from,sort_param->record); if (!(reclength= _ma_rec_pack(info,from,sort_param->record)))
{
_ma_check_print_error(param,"Got error %d when packing record",
my_errno);
DBUG_RETURN(1);
}
flag=0; flag=0;
do do
......
...@@ -114,8 +114,10 @@ int maria_close(register MARIA_HA *info) ...@@ -114,8 +114,10 @@ int maria_close(register MARIA_HA *info)
share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE))
error= my_errno; error= my_errno;
unmap_file(info); unmap_file(info);
if (((share->changed && share->base.born_transactional) || if (!internal_table &&
maria_is_crashed(info) || (share->temporary && !share->deleting))) (((share->changed && share->base.born_transactional) ||
maria_is_crashed(info) ||
(share->temporary && !share->deleting))))
{ {
if (save_global_changed) if (save_global_changed)
{ {
......
...@@ -224,6 +224,8 @@ my_bool _ma_write_dynamic_record(MARIA_HA *info, const uchar *record) ...@@ -224,6 +224,8 @@ my_bool _ma_write_dynamic_record(MARIA_HA *info, const uchar *record)
{ {
ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET, ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
record); record);
if (!reclength)
return 1;
return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET, return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
reclength)); reclength));
} }
...@@ -234,6 +236,8 @@ my_bool _ma_update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS pos, ...@@ -234,6 +236,8 @@ my_bool _ma_update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS pos,
{ {
uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET, uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET,
record); record);
if (!length)
return 1;
return (update_dynamic_record(info, pos, return (update_dynamic_record(info, pos,
info->rec_buff + MARIA_REC_BUFF_OFFSET, info->rec_buff + MARIA_REC_BUFF_OFFSET,
length)); length));
...@@ -258,12 +262,19 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record) ...@@ -258,12 +262,19 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
reclength2= _ma_rec_pack(info, reclength2= _ma_rec_pack(info,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
record); record);
if (!reclength2)
{
error= 1;
goto err;
}
DBUG_PRINT("info",("reclength: %lu reclength2: %lu", DBUG_PRINT("info",("reclength: %lu reclength2: %lu",
reclength, reclength2)); reclength, reclength2));
DBUG_ASSERT(reclength2 <= reclength); DBUG_ASSERT(reclength2 <= reclength);
error= write_dynamic_record(info, error= write_dynamic_record(info,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength2); reclength2);
err:
my_safe_afree(rec_buff, reclength); my_safe_afree(rec_buff, reclength);
return(error != 0); return(error != 0);
} }
...@@ -293,12 +304,19 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos, ...@@ -293,12 +304,19 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */ my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1); return(1);
} }
reclength2= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), reclength2= _ma_rec_pack(info, rec_buff+
record); ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
record);
if (!reclength2)
{
error= 1;
goto err;
}
DBUG_ASSERT(reclength2 <= reclength); DBUG_ASSERT(reclength2 <= reclength);
error=update_dynamic_record(info,pos, error=update_dynamic_record(info,pos,
rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
reclength2); reclength2);
err:
my_safe_afree(rec_buff, reclength); my_safe_afree(rec_buff, reclength);
return(error != 0); return(error != 0);
} }
...@@ -938,7 +956,12 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos, ...@@ -938,7 +956,12 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
} }
/* Pack a record. Return new reclength */ /**
Pack a record.
@return new reclength
@return 0 in case of wrong data in record
*/
uint _ma_rec_pack(MARIA_HA *info, register uchar *to, uint _ma_rec_pack(MARIA_HA *info, register uchar *to,
register const uchar *from) register const uchar *from)
...@@ -1042,6 +1065,11 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, ...@@ -1042,6 +1065,11 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to,
tmp_length= uint2korr(from); tmp_length= uint2korr(from);
store_key_length_inc(to,tmp_length); store_key_length_inc(to,tmp_length);
} }
if (tmp_length > column->length)
{
my_errno= HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(0);
}
memcpy(to, from+pack_length,tmp_length); memcpy(to, from+pack_length,tmp_length);
to+= tmp_length; to+= tmp_length;
continue; continue;
...@@ -1613,7 +1641,9 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1613,7 +1641,9 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
if (!(buffer=(uchar*) my_safe_alloca(buffer_length))) if (!(buffer=(uchar*) my_safe_alloca(buffer_length)))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
reclength= _ma_rec_pack(info,buffer,record); if (!(reclength= _ma_rec_pack(info,buffer,record)))
goto err;
record= buffer; record= buffer;
filepos= info->cur_row.lastpos; filepos= info->cur_row.lastpos;
......
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