From 1b1b9413854d4aaf21d8eaf529c23567eb5e0daf Mon Sep 17 00:00:00 2001 From: Teodor Mircea Ionita Date: Thu, 16 Aug 2018 16:39:50 +0300 Subject: [PATCH 1/5] MDEV-17022: check if mtr --mem location is writeable --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ba49d88a85f..ade3f99104e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1457,7 +1457,7 @@ sub command_line_setup { foreach my $fs (@tmpfs_locations) { - if ( -d $fs ) + if ( -d $fs && -w $fs ) { my $template= "var_${opt_build_thread}_XXXX"; $opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0); From 064ba8cc9f429fbf403f8d2c564e5f59f6799df9 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 17 Nov 2017 08:00:32 +0800 Subject: [PATCH 2/5] item_cmp_type: simplier for a faster codepath The common case for this function is that both types are the same. The Item_result defination from include/mysql.h.pp is the following enum enum Item_result { STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT, TIME_RESULT }; The compilers aren't quite smart enough to optimize to this shortcut so this makes it quicker. Before the change: 0000000000012730 : 12730: 89 f0 mov %esi,%eax 12732: 09 f8 or %edi,%eax 12734: 74 4c je 12782 12736: 83 ff 02 cmp $0x2,%edi 12739: 75 0a jne 12745 1273b: b8 02 00 00 00 mov $0x2,%eax 12740: 83 fe 02 cmp $0x2,%esi 12743: 74 3c je 12781 12745: 83 ff 03 cmp $0x3,%edi 12748: b8 03 00 00 00 mov $0x3,%eax 1274d: 74 32 je 12781 1274f: 83 fe 03 cmp $0x3,%esi 12752: 74 2d je 12781 12754: 83 ff 05 cmp $0x5,%edi 12757: b8 05 00 00 00 mov $0x5,%eax 1275c: 74 23 je 12781 1275e: 83 fe 05 cmp $0x5,%esi 12761: 74 1e je 12781 12763: 83 ff 04 cmp $0x4,%edi 12766: 74 05 je 1276d 12768: 83 ff 02 cmp $0x2,%edi 1276b: 75 0f jne 1277c 1276d: b8 04 00 00 00 mov $0x4,%eax 12772: 83 fe 02 cmp $0x2,%esi 12775: 74 0a je 12781 12777: 83 fe 04 cmp $0x4,%esi 1277a: 74 05 je 12781 1277c: b8 01 00 00 00 mov $0x1,%eax 12781: c3 retq 12782: 31 c0 xor %eax,%eax 12784: c3 retq After, noting the short cut and the beginning of the function: 0000000000012730 : 12730: 39 f7 cmp %esi,%edi 12732: 75 03 jne 12737 12734: 89 f8 mov %edi,%eax 12736: c3 retq 12737: 83 ff 03 cmp $0x3,%edi 1273a: b8 03 00 00 00 mov $0x3,%eax 1273f: 74 32 je 12773 12741: 83 fe 03 cmp $0x3,%esi 12744: 74 2d je 12773 12746: 83 ff 05 cmp $0x5,%edi 12749: b8 05 00 00 00 mov $0x5,%eax 1274e: 74 23 je 12773 12750: 83 fe 05 cmp $0x5,%esi 12753: 74 1e je 12773 12755: 83 ff 04 cmp $0x4,%edi 12758: 74 05 je 1275f 1275a: 83 ff 02 cmp $0x2,%edi 1275d: 75 0f jne 1276e 1275f: b8 04 00 00 00 mov $0x4,%eax 12764: 83 fe 02 cmp $0x2,%esi 12767: 74 0a je 12773 12769: 83 fe 04 cmp $0x4,%esi 1276c: 74 05 je 12773 1276e: b8 01 00 00 00 mov $0x1,%eax 12773: c3 retq Signed-off-by: Daniel Black --- sql/item.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 0cf4864326f..745cbf31f0c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8719,13 +8719,11 @@ void Item_trigger_field::cleanup() Item_result item_cmp_type(Item_result a,Item_result b) { - if (a == STRING_RESULT && b == STRING_RESULT) - return STRING_RESULT; - if (a == INT_RESULT && b == INT_RESULT) - return INT_RESULT; - else if (a == ROW_RESULT || b == ROW_RESULT) + if (a == b) + return a; + if (a == ROW_RESULT || b == ROW_RESULT) return ROW_RESULT; - else if (a == TIME_RESULT || b == TIME_RESULT) + if (a == TIME_RESULT || b == TIME_RESULT) return TIME_RESULT; if ((a == INT_RESULT || a == DECIMAL_RESULT) && (b == INT_RESULT || b == DECIMAL_RESULT)) From 42f09adab68f80fb99d6da0413cd4983ec13f5ab Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 30 Aug 2018 13:45:27 +0300 Subject: [PATCH 3/5] MDEV-16682 Assertion `(buff[7] & 7) == HEAD_PAGE' failed Problem was that SQL level tried to read a record with rnd_pos() that was already deleted by the same statement. In the case where the page for the record had been deleted, this caused an assert. Fixed by extending the assert to also handle empty pages and return HA_ERR_RECORD_DELETED for reads to deleted pages. --- mysql-test/suite/maria/maria.result | 4 ++++ mysql-test/suite/maria/maria.test | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/suite/maria/maria.result b/mysql-test/suite/maria/maria.result index 2aca47538cb..1cf48b0628d 100644 --- a/mysql-test/suite/maria/maria.result +++ b/mysql-test/suite/maria/maria.result @@ -2723,6 +2723,10 @@ id name -1 dog 2 cat DROP TABLE t1; +CREATE TABLE t1 (pk int, i2 int) ENGINE=Aria; +INSERT INTO t1 VALUES (1,2), (2,3),(3,4); +DELETE FROM tt.*, t1.* USING t1 AS tt LEFT JOIN t1 ON (tt.i2 = t1.pk); +DROP TABLE t1; # # End of 5.5 tests # diff --git a/mysql-test/suite/maria/maria.test b/mysql-test/suite/maria/maria.test index ab8e72dc321..954bd15744e 100644 --- a/mysql-test/suite/maria/maria.test +++ b/mysql-test/suite/maria/maria.test @@ -2012,6 +2012,16 @@ INSERT INTO t1 (name) VALUES ('cat'); SELECT * FROM t1; DROP TABLE t1; +# +# MDEV-16682 +# Assertion `(buff[7] & 7) == HEAD_PAGE' failed. +# + +CREATE TABLE t1 (pk int, i2 int) ENGINE=Aria; +INSERT INTO t1 VALUES (1,2), (2,3),(3,4); +DELETE FROM tt.*, t1.* USING t1 AS tt LEFT JOIN t1 ON (tt.i2 = t1.pk); +DROP TABLE t1; + --echo # --echo # End of 5.5 tests --echo # From 796d54df115a0e5485a7df0835088a51dd0f9e77 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 30 Aug 2018 15:18:35 +0200 Subject: [PATCH 4/5] MDEV-16957: Server crashes in Field_iterator_natural_join::next upon 2nd execution of SP The problem was that join_columns creation was not finished due to error of notfound column in USING, but next execution tried to use join_columns lists. Solution is cleanup the lists on error. It can eat memory in statement MEM_ROOT but it is an error and error will be fixed or statement/procedure removed/altered. --- mysql-test/r/join.result | 6 ++++-- mysql-test/r/sp.result | 17 +++++++++++++++++ mysql-test/t/join.test | 3 ++- mysql-test/t/sp.test | 21 +++++++++++++++++++++ sql/sql_base.cc | 14 +++++++++++++- sql/table.h | 10 ++++++++++ 6 files changed, 67 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 7b0e7807e39..2e5ee30b54e 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1514,11 +1514,13 @@ ERROR 42S22: Unknown column 'f' in 'from clause' DROP TABLE t; CREATE TABLE t (f INT); CALL p; -ERROR 42S22: Unknown column 'f' in 'from clause' +f DROP TABLE t; CREATE TABLE t (i INT); CALL p; -ERROR 42S22: Unknown column 'f' in 'from clause' +ERROR 42S22: Unknown column 't1.f' in 'field list' +CALL p; +ERROR 42S22: Unknown column 't1.f' in 'field list' DROP PROCEDURE p; DROP TABLE t; CREATE TABLE t1 (a INT, b INT); diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 823c6f78cee..4535056242a 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8055,4 +8055,21 @@ SET S.CLOSE_YN = '' where 1=1; drop function if exists f1; drop table t1,t2; +# +# MDEV-16957: Server crashes in Field_iterator_natural_join::next +# upon 2nd execution of SP +# +CREATE TABLE t1 (a INT, b VARCHAR(32)); +CREATE PROCEDURE sp() SELECT * FROM t1 AS t1x JOIN t1 AS t1y USING (c); +CALL sp; +ERROR 42S22: Unknown column 'c' in 'from clause' +CALL sp; +ERROR 42S22: Unknown column 'c' in 'from clause' +CALL sp; +ERROR 42S22: Unknown column 'c' in 'from clause' +alter table t1 add column c int; +CALL sp; +c a b a b +DROP PROCEDURE sp; +DROP TABLE t1; # End of 5.5 test diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index feafac57a7e..5a29fe72049 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -1185,12 +1185,13 @@ CREATE TABLE t (f INT); # # The following shouldn't fail as the table is now matching the using # ---error ER_BAD_FIELD_ERROR CALL p; DROP TABLE t; CREATE TABLE t (i INT); --error ER_BAD_FIELD_ERROR CALL p; +--error ER_BAD_FIELD_ERROR +CALL p; DROP PROCEDURE p; DROP TABLE t; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 0e42bf3c831..cb93cd31442 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9353,4 +9353,25 @@ where 1=1; drop function if exists f1; drop table t1,t2; +--echo # +--echo # MDEV-16957: Server crashes in Field_iterator_natural_join::next +--echo # upon 2nd execution of SP +--echo # + +CREATE TABLE t1 (a INT, b VARCHAR(32)); +CREATE PROCEDURE sp() SELECT * FROM t1 AS t1x JOIN t1 AS t1y USING (c); +--error ER_BAD_FIELD_ERROR +CALL sp; +--error ER_BAD_FIELD_ERROR +CALL sp; +--error ER_BAD_FIELD_ERROR +CALL sp; +alter table t1 add column c int; +CALL sp; + +# Cleanup +DROP PROCEDURE sp; +DROP TABLE t1; + + --echo # End of 5.5 test diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8ffb7bc118b..272aa11977d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7764,10 +7764,22 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, result= FALSE; -err: if (arena) thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); + +err: + /* + Actually we failed to build join columns list, so we have to + clear it to avoid problems with half-build join on next run. + The list was created in mark_common_columns(). + */ + table_ref_1->remove_join_columns(); + table_ref_2->remove_join_columns(); + + if (arena) + thd->restore_active_arena(arena, &backup); + DBUG_RETURN(TRUE); } diff --git a/sql/table.h b/sql/table.h index 1d4a1d9a2d2..4725eb96432 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2184,6 +2184,16 @@ struct TABLE_LIST } void set_lock_type(THD* thd, enum thr_lock_type lock); + void remove_join_columns() + { + if (join_columns) + { + join_columns->empty(); + join_columns= NULL; + is_join_columns_complete= FALSE; + } + } + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); From 43c393ff4732e9ea8719864abeb73cefd5b528a9 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 3 Sep 2018 11:10:30 +0300 Subject: [PATCH 5/5] MDEV-16682 Assertion `(buff[7] & 7) == HEAD_PAGE' failed Missed one file in last push... --- storage/maria/ma_blockrec.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 58791418998..31026d99b68 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -53,10 +53,10 @@ Page header: LSN 7 bytes Log position for last page change - PAGE_TYPE 1 uchar 1 for head / 2 for tail / 3 for blob + PAGE_TYPE 1 uchar 0 unalloced / 1 for head / 2 for tail / 3 for blob DIR_COUNT 1 uchar Number of row/tail entries on page FREE_DIR_LINK 1 uchar Pointer to first free director entry or 255 if no - empty space 2 bytes Empty space on page + empty space 2 bytes Bytes of empty space on page The most significant bit in PAGE_TYPE is set to 1 if the data on the page can be compacted to get more space. (PAGE_CAN_BE_COMPACTED) @@ -5122,11 +5122,19 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record, info->buff, share->page_type, PAGECACHE_LOCK_LEFT_UNLOCKED, 0))) DBUG_RETURN(my_errno); - DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == HEAD_PAGE); - if (!(data= get_record_position(buff, block_size, offset, &end_of_data))) + + /* + Unallocated page access can happen if this is an access to a page where + all rows where deleted as part of this statement. + */ + DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == HEAD_PAGE || + (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == UNALLOCATED_PAGE); + + if (((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == UNALLOCATED_PAGE) || + !(data= get_record_position(buff, block_size, offset, &end_of_data))) { DBUG_ASSERT(!maria_assert_if_crashed_table); - DBUG_PRINT("error", ("Wrong directory entry in data block")); + DBUG_PRINT("warning", ("Wrong directory entry in data block")); my_errno= HA_ERR_RECORD_DELETED; /* File crashed */ DBUG_RETURN(HA_ERR_RECORD_DELETED); }