diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-07-01 18:37:15 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-07-01 18:37:15 +0300 |
commit | 9c16460e63a5002d5949f67f57dce71e666547ec (patch) | |
tree | bb29fe94f869d828ed5768dbc72021d1911e2831 | |
parent | 747dccfe23e46b928b005669124e7ad94a1fdefb (diff) | |
parent | 0e1ba364a12b6569c75a7dadc38b7ef2b4910d34 (diff) | |
download | mariadb-git-9c16460e63a5002d5949f67f57dce71e666547ec.tar.gz |
Merge 10.3 into 10.4
-rw-r--r-- | mysql-test/main/type_varchar.result | 18 | ||||
-rw-r--r-- | mysql-test/main/type_varchar.test | 16 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/foreign-keys.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/instant_alter_debug.result | 29 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/foreign-keys.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/instant_alter_debug.test | 25 | ||||
-rw-r--r-- | sql/sql_const.h | 2 | ||||
-rw-r--r-- | sql/sql_type.cc | 7 | ||||
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 3 | ||||
-rw-r--r-- | storage/innobase/page/page0page.cc | 180 | ||||
-rw-r--r-- | storage/maria/ma_check.c | 7 | ||||
-rw-r--r-- | storage/maria/ma_close.c | 6 | ||||
-rw-r--r-- | storage/maria/ma_dynrec.c | 38 |
13 files changed, 233 insertions, 102 deletions
diff --git a/mysql-test/main/type_varchar.result b/mysql-test/main/type_varchar.result index 8911d36a020..cec279913b4 100644 --- a/mysql-test/main/type_varchar.result +++ b/mysql-test/main/type_varchar.result @@ -687,7 +687,23 @@ DROP TABLE t1,t2; # 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=''; CREATE TABLE t1 (c VARCHAR(1) DEFAULT 'foo'); diff --git a/mysql-test/main/type_varchar.test b/mysql-test/main/type_varchar.test index 86f16afc56f..9d0ad8a128b 100644 --- a/mysql-test/main/type_varchar.test +++ b/mysql-test/main/type_varchar.test @@ -329,9 +329,23 @@ DROP TABLE t1,t2; --echo # End of 10.0 tests --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 # Start of 10.4 tests +--echo # End of 10.3 tests --echo # SET sql_mode=''; diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result index 9dee6efcb04..f64e84fe429 100644 --- a/mysql-test/suite/innodb/r/foreign-keys.result +++ b/mysql-test/suite/innodb/r/foreign-keys.result @@ -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; connect con1, localhost, root; 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; ERROR HY000: Lock wait timeout exceeded; try restarting transaction PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 866aeb48f67..7ab24a7671b 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -264,6 +264,33 @@ a b c d 2 3 4 1 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-18098 Crash after rollback of instant DROP COLUMN # @@ -299,5 +326,5 @@ SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants -21 +22 SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test index e5950e01a11..d16ae9ed826 100644 --- a/mysql-test/suite/innodb/t/foreign-keys.test +++ b/mysql-test/suite/innodb/t/foreign-keys.test @@ -140,7 +140,7 @@ send ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE; connect con1, localhost, root; 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 UPDATE t2 SET pk=10 WHERE pk=1; PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index 73a222cb23c..267e2a2c22d 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -301,6 +301,31 @@ SELECT * FROM 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 # MDEV-17899 Assertion failures on rollback of instant ADD/DROP --echo # MDEV-18098 Crash after rollback of instant DROP COLUMN --echo # diff --git a/sql/sql_const.h b/sql/sql_const.h index 7aa4249f5ad..f7c820c727b 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -64,7 +64,7 @@ CREATE TABLE t1 (c VARBINARY(65534)); CREATE TABLE t1 (c VARBINARY(65535)); 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_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 2e3bd5f956f..adddf365b45 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2015 MariaDB Foundation. + Copyright (c) 2015,2019 MariaDB 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 @@ -1173,6 +1173,8 @@ Type_handler::string_type_handler(uint max_octet_length) return &type_handler_long_blob; else if (max_octet_length >= 65536) return &type_handler_medium_blob; + else if (max_octet_length >= MAX_FIELD_VARCHARLENGTH) + return &type_handler_blob; return &type_handler_varchar; } @@ -2256,6 +2258,7 @@ Field *Type_handler_varchar::make_conversion_table_field(TABLE *table, const Field *target) const { + DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH); return new(table->in_use->mem_root) Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata), (uchar *) "", 1, Field::NONE, &empty_clex_str, @@ -3326,6 +3329,8 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, TABLE *table) const { + DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <= + MAX_FIELD_VARCHARLENGTH); return new (table->in_use->mem_root) Field_varstring(addr.ptr(), attr.max_length, HA_VARCHAR_PACKLENGTH(attr.max_length), diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 2c93077e0d2..d6eff63b360 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -3494,7 +3494,8 @@ btr_lift_page_up( /* btr_page_empty() is supposed to zero-initialize the field. */ 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); btr_set_instant(father_block, *index, mtr); } diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index 1b735677b20..2a345d87686 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2366,18 +2366,11 @@ page_validate( the page record type definition */ { 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* old_rec = NULL; ulint offs; ulint n_slots; - ibool ret = FALSE; + ibool ret = TRUE; ulint i; ulint* offsets = NULL; ulint* old_offsets = NULL; @@ -2391,7 +2384,13 @@ page_validate( if (UNIV_UNLIKELY((ibool) !!page_is_comp(page) != dict_table_is_comp(index->table))) { 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 (UNIV_UNLIKELY(!page_simple_validate_new(page))) { @@ -2416,19 +2415,12 @@ page_validate( if (max_trx_id == 0 || max_trx_id > sys_max_trx_id) { ib::error() << "PAGE_MAX_TRX_ID out of bounds: " << max_trx_id << ", " << sys_max_trx_id; - goto func_exit2; + ret = FALSE; } } else { 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 overlap. */ @@ -2437,20 +2429,45 @@ page_validate( if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP) <= page_dir_get_nth_slot(page, n_slots - 1)))) { - ib::warn() << "Record heap and dir overlap on space " - << page_get_space_id(page) << " page " - << 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); + ib::warn() << "Record heap and directory overlap"; + goto func_exit2; + } - 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 it is consistent with the directory. */ - count = 0; - data_size = 0; - own_count = 1; + ulint count = 0, data_size = 0, own_count = 1, slot_no = 0; slot_no = 0; slot = page_dir_get_nth_slot(page, slot_no); @@ -2465,11 +2482,13 @@ page_validate( && UNIV_UNLIKELY(rec_get_node_ptr_flag(rec) == page_is_leaf(page))) { ib::error() << "'node_ptr' flag mismatch"; - goto func_exit; + ret = FALSE; + goto next_rec; } 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 */ @@ -2481,16 +2500,10 @@ page_validate( /* For spatial index, on nonleaf leavel, we allow recs to be equal. */ - bool rtr_equal_nodeptrs = - (ret == 0 && dict_index_is_spatial(index) - && !page_is_leaf(page)); + if (ret <= 0 && !(ret == 0 && index->is_spatial() + && !page_is_leaf(page))) { - if (ret <= 0 && !rtr_equal_nodeptrs) { - - ib::error() << "Records in wrong order on" - " space " << page_get_space_id(page) - << " page " << page_get_page_no(page) - << " index " << index->name; + ib::error() << "Records in wrong order"; fputs("\nInnoDB: previous record ", stderr); /* For spatial index, print the mbr info.*/ @@ -2511,7 +2524,7 @@ page_validate( putc('\n', stderr); } - goto func_exit; + ret = FALSE; } } @@ -2531,41 +2544,41 @@ page_validate( offs = page_offset(rec_get_start(rec, offsets)); i = rec_offs_size(offsets); if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { - ib::error() << "Record offset out of bounds"; - goto func_exit; + ib::error() << "Record offset out of bounds: " + << offs << '+' << i; + ret = FALSE; + goto next_rec; } - while (i--) { if (UNIV_UNLIKELY(buf[offs + i])) { - /* No other record may overlap this */ - ib::error() << "Record overlaps another"; - goto func_exit; + ib::error() << "Record overlaps another: " + << offs << '+' << i; + ret = FALSE; + break; } - buf[offs + i] = 1; } - if (page_is_comp(page)) { - rec_own_count = rec_get_n_owned_new(rec); - } else { - rec_own_count = rec_get_n_owned_old(rec); - } - - if (UNIV_UNLIKELY(rec_own_count != 0)) { + if (ulint rec_own_count = page_is_comp(page) + ? rec_get_n_owned_new(rec) + : rec_get_n_owned_old(rec)) { /* This is a record pointed to by a dir slot */ if (UNIV_UNLIKELY(rec_own_count != own_count)) { - ib::error() << "Wrong owned count " - << rec_own_count << ", " << own_count; - goto func_exit; + ib::error() << "Wrong owned count at " << offs + << ": " << rec_own_count + << ", " << own_count; + ret = FALSE; } if (page_dir_slot_get_rec(slot) != rec) { ib::error() << "Dir slot does not" - " point to right rec"; - goto func_exit; + " point to right rec at " << offs; + ret = FALSE; } - page_dir_slot_check(slot); + if (ret) { + page_dir_slot_check(slot); + } own_count = 0; if (!page_rec_is_supremum(rec)) { @@ -2574,6 +2587,7 @@ page_validate( } } +next_rec: if (page_rec_is_supremum(rec)) { break; } @@ -2598,14 +2612,14 @@ page_validate( } } else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) { n_owned_zero: - ib::error() << "n owned is zero"; - goto func_exit; + ib::error() << "n owned is zero at " << offs; + ret = FALSE; } if (UNIV_UNLIKELY(slot_no != n_slots - 1)) { ib::error() << "n slots wrong " << slot_no << " " << (n_slots - 1); - goto func_exit; + ret = FALSE; } if (UNIV_UNLIKELY(ulint(page_header_get_field(page, PAGE_N_RECS)) @@ -2614,65 +2628,57 @@ n_owned_zero: ib::error() << "n recs wrong " << page_header_get_field(page, PAGE_N_RECS) + PAGE_HEAP_NO_USER_LOW << " " << (count + 1); - goto func_exit; + ret = FALSE; } if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) { ib::error() << "Summed data size " << data_size << ", returned by func " << page_get_data_size(page); - goto func_exit; + ret = FALSE; } /* Check then the free list */ - rec = page_header_get_ptr(page, PAGE_FREE); - - while (rec != NULL) { + for (rec = page_header_get_ptr(page, PAGE_FREE); + rec; + rec = page_rec_get_next_const(rec)) { offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page), ULINT_UNDEFINED, &heap); if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) { - - goto func_exit; + ret = FALSE; + continue; } count++; offs = page_offset(rec_get_start(rec, offsets)); i = rec_offs_size(offsets); if (UNIV_UNLIKELY(offs + i >= srv_page_size)) { - ib::error() << "Record offset out of bounds"; - goto func_exit; + ib::error() << "Free record offset out of bounds: " + << offs << '+' << i; + ret = FALSE; + continue; } - while (i--) { - if (UNIV_UNLIKELY(buf[offs + i])) { - ib::error() << "Record overlaps another" - " in free list"; - goto func_exit; + ib::error() << "Free record overlaps another: " + << offs << '+' << i; + ret = FALSE; + break; } - buf[offs + i] = 1; } - - rec = page_rec_get_next_const(rec); } if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) { ib::error() << "N heap is wrong " << page_dir_get_n_heap(page) << " " << count + 1; - goto func_exit; + ret = FALSE; } - ret = TRUE; - -func_exit: mem_heap_free(heap); - if (UNIV_UNLIKELY(ret == FALSE)) { -func_exit2: - ib::error() << "Apparent corruption in space " - << page_get_space_id(page) << " page " - << page_get_page_no(page) << " index " << index->name; + if (UNIV_UNLIKELY(!ret)) { + goto func_exit2; } return(ret); diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 7fdfe948cb9..2431afcd1e9 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -5432,7 +5432,12 @@ int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param) info->cur_row.checksum= (*share->calc_check_checksum)(info, sort_param-> 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; do diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c index 03501dc49cf..44f65230c5d 100644 --- a/storage/maria/ma_close.c +++ b/storage/maria/ma_close.c @@ -114,8 +114,10 @@ int maria_close(register MARIA_HA *info) share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) error= my_errno; unmap_file(info); - if (((share->changed && share->base.born_transactional) || - maria_is_crashed(info) || (share->temporary && !share->deleting))) + if (!internal_table && + (((share->changed && share->base.born_transactional) || + maria_is_crashed(info) || + (share->temporary && !share->deleting)))) { if (save_global_changed) { diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index 5273c1bddb7..ae6fc57c114 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -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, record); + if (!reclength) + return 1; return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET, reclength)); } @@ -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, record); + if (!length) + return 1; return (update_dynamic_record(info, pos, info->rec_buff + MARIA_REC_BUFF_OFFSET, length)); @@ -258,12 +262,19 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record) reclength2= _ma_rec_pack(info, rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), record); + if (!reclength2) + { + error= 1; + goto err; + } + DBUG_PRINT("info",("reclength: %lu reclength2: %lu", reclength, reclength2)); DBUG_ASSERT(reclength2 <= reclength); error= write_dynamic_record(info, rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), reclength2); +err: my_safe_afree(rec_buff, reclength); return(error != 0); } @@ -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 */ return(1); } - reclength2= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), - record); + reclength2= _ma_rec_pack(info, rec_buff+ + ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), + record); + if (!reclength2) + { + error= 1; + goto err; + } DBUG_ASSERT(reclength2 <= reclength); error=update_dynamic_record(info,pos, rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER), reclength2); +err: my_safe_afree(rec_buff, reclength); return(error != 0); } @@ -938,7 +956,12 @@ err: } - /* 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, register const uchar *from) @@ -1042,6 +1065,11 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, tmp_length= uint2korr(from); 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); to+= tmp_length; continue; @@ -1613,7 +1641,9 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, if (!(buffer=(uchar*) my_safe_alloca(buffer_length))) DBUG_RETURN(1); } - reclength= _ma_rec_pack(info,buffer,record); + if (!(reclength= _ma_rec_pack(info,buffer,record))) + goto err; + record= buffer; filepos= info->cur_row.lastpos; |