From 910284e6e6203b8d2d2f454823b1ae7ecd759651 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 27 Dec 2008 04:05:16 +0200 Subject: [PATCH] Fixed bugs found by pushbuild Added code to detect and give error when doing an insert into a view where we accessed fields in a not yet read table Disabled test in subselect.test as the CHECK_OPTION for views doesn't work for insert. This needs to be fixed properly later. The problem with views are described in Bug #41760 Inserting into multiple-table views is not working mysql-test/r/insert.result: Fixed wrong usage of insert into view. mysql-test/r/subselect.result: Disabled wrong test (temporary) mysql-test/suite/maria/r/maria.result: Added test of size of table mysql-test/suite/maria/t/maria.test: Added test of size of table mysql-test/t/insert.test: Fixed wrong usage of insert into view The bug is that during insert/update we currently don't read any of the referenced tables of the view. This means that we can't get a value from another table to use as part of the update. mysql-test/t/subselect.test: Disabled not working test until someone has time to fix insert into view properly Here we where refering to last used value in t2, which is wrong. sql/sql_insert.cc: Detect if we are trying to update one table in a view based on value in another, not yet read, table. This fixes the problem discovered in insert.test storage/maria/ma_blockrec.c: Don't ignore not critical changes to the last page in the table. We need to write the last page as otherwise we can during aborting of a row with a duplicate key get state.data_file_length and the real length of file out of sync storage/maria/ma_check.c: Flush the page cache even if we got an error during zerofill. (This fixes a call to assert() in case of a too short data file) storage/maria/ma_pagecache.c: Mark page as read when we do a write of a full page. This fixes a bug when we got an error during read and then used direct write to page to update it storage/maria/ma_state.c: Restore info->lock.type after call to maria_versioning. Fixed crash in maria_recover.test storage/maria/maria_read_log.c: Don't write thread id in debug log. (Not needed as maria_read_log is a single treaded program) --- mysql-test/r/insert.result | 4 ++-- mysql-test/r/subselect.result | 3 --- mysql-test/suite/maria/r/maria.result | 3 +++ mysql-test/suite/maria/t/maria.test | 1 + mysql-test/t/insert.test | 2 ++ mysql-test/t/subselect.test | 4 ++++ sql/sql_insert.cc | 24 ++++++++++++++++-------- storage/maria/ma_blockrec.c | 13 ++++++++++++- storage/maria/ma_check.c | 15 +++++++++++---- storage/maria/ma_pagecache.c | 6 +++++- storage/maria/ma_state.c | 4 ++++ storage/maria/maria_read_log.c | 4 ++-- 12 files changed, 62 insertions(+), 21 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 919aff4bfb7..8036a346b3a 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -355,17 +355,17 @@ insert into t2 values (1,12), (2,24); insert into v1 (f1) values (3) on duplicate key update f3= f3 + 10; ERROR HY000: Can not modify more than one base table through a join view 'test.v1' insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10; +ERROR HY000: Can not modify more than one base table through a join view 'test.v1' select * from t1; f1 f2 1 11 2 22 -3 NULL insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10; +ERROR HY000: Can not modify more than one base table through a join view 'test.v1' select * from t1; f1 f2 1 11 2 22 -12 NULL drop view v1; drop table t1,t2; create table t1 (id int primary key auto_increment, data int, unique(data)); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f54374166b4..f91147ea0a6 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4463,15 +4463,12 @@ SELECT t2.id, t2.c AS c FROM t1, t2 WHERE t1.id=t2.id AND 1 IN (SELECT id FROM t1) WITH CHECK OPTION; INSERT INTO v2(a,b) VALUES (2,2); ERROR HY000: CHECK OPTION failed 'test.v2' -INSERT INTO v2(a,b) VALUES (1,2); SELECT * FROM v1; c 1 1 1 1 -2 -2 CREATE VIEW v3 AS SELECT t2.c AS c FROM t2 WHERE 1 IN (SELECT id FROM t1) WITH CHECK OPTION; diff --git a/mysql-test/suite/maria/r/maria.result b/mysql-test/suite/maria/r/maria.result index be72dbadfc7..cbda2313c73 100644 --- a/mysql-test/suite/maria/r/maria.result +++ b/mysql-test/suite/maria/r/maria.result @@ -2589,4 +2589,7 @@ Warnings: Warning 1265 Data truncated for column 'c' at row 1 insert into t1 values(1,repeat('a',100), repeat('b',657860)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK drop table t1; diff --git a/mysql-test/suite/maria/t/maria.test b/mysql-test/suite/maria/t/maria.test index 9ac8580788b..637b4c82db9 100644 --- a/mysql-test/suite/maria/t/maria.test +++ b/mysql-test/suite/maria/t/maria.test @@ -1855,6 +1855,7 @@ create table t1(a int primary key, b blob, c blob) engine=maria; insert into t1 values(1,repeat('a',100), repeat('b',657860)); --error ER_DUP_ENTRY insert into t1 values(1,repeat('a',100), repeat('b',657860)); +check table t1; drop table t1; # Set defaults back diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index c58fb61ad30..a5eb31496b1 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -235,8 +235,10 @@ insert into t1 values (1,11), (2,22); insert into t2 values (1,12), (2,24); --error 1393 insert into v1 (f1) values (3) on duplicate key update f3= f3 + 10; +--error 1393 insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10; select * from t1; +--error 1393 insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10; select * from t1; drop view v1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index f27aa22533d..1960af371e1 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3379,7 +3379,11 @@ CREATE VIEW v2 (a,b) AS --error 1369 INSERT INTO v2(a,b) VALUES (2,2); + +# disabled for now as this refers to old content of t2 +--disable_parsing INSERT INTO v2(a,b) VALUES (1,2); +--enable_parsing SELECT * FROM v1; CREATE VIEW v3 AS diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 16aa59d992e..b3a74b15652 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -107,8 +107,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); 1 Error */ -bool check_view_single_update(List &fields, TABLE_LIST *view, - table_map *map) +bool check_view_single_update(List &fields, List &values, + TABLE_LIST *view, table_map *map) { /* it is join view => we need to find the table for update */ List_iterator_fast it(fields); @@ -116,6 +116,10 @@ bool check_view_single_update(List &fields, TABLE_LIST *view, TABLE_LIST *tbl= 0; // reset for call to check_single_table() table_map tables= 0; + while ((item= it++)) + tables|= item->used_tables(); + + it.init(values); while ((item= it++)) tables|= item->used_tables(); @@ -238,7 +242,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) { - if (check_view_single_update(fields, table_list, map)) + if (check_view_single_update(fields, values, table_list, map)) return -1; table= table_list->table; } @@ -298,7 +302,8 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, */ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, - List &update_fields, table_map *map) + List &update_fields, + List &update_values, table_map *map) { TABLE *table= insert_table_list->table; my_bool timestamp_mark; @@ -320,7 +325,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, return -1; if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && - check_view_single_update(update_fields, insert_table_list, map)) + check_view_single_update(update_fields, update_values, insert_table_list, + map)) return -1; if (table->timestamp_field) @@ -1246,7 +1252,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!res && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; - res= check_update_fields(thd, context->table_list, update_fields, &map); + res= check_update_fields(thd, context->table_list, update_fields, + update_values, &map); select_lex->no_wrap_view_item= FALSE; } @@ -2912,7 +2919,8 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) lex->select_lex.no_wrap_view_item= TRUE; res= res || check_update_fields(thd, context->table_list, - *info.update_fields, &map); + *info.update_fields, *info.update_values, + &map); lex->select_lex.no_wrap_view_item= FALSE; /* When we are not using GROUP BY and there are no ungrouped aggregate functions @@ -3580,7 +3588,7 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) DBUG_RETURN(-1); } - /* First field to copy */ + /* First field to copy */ field= table->field+table->s->fields - values.elements; /* Mark all fields that are given values */ diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 6eae40d57b9..54c05b4ae9c 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -2408,11 +2408,22 @@ static my_bool free_full_page_range(MARIA_HA *info, pgcache_page_no_t page, uint count) { my_bool res= 0; + uint delete_count; MARIA_SHARE *share= info->s; DBUG_ENTER("free_full_page_range"); + delete_count= count; + if (share->state.state.data_file_length == + (page + count) * share->block_size) + { + /* + Don't delete last page from pagecache as this will make the file + shorter than expected if the last operation extended the file + */ + delete_count--; + } if (pagecache_delete_pages(share->pagecache, &info->dfile, - page, count, PAGECACHE_LOCK_WRITE, 0)) + page, delete_count, PAGECACHE_LOCK_WRITE, 0)) res= 1; if (share->now_transactional) diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index bc177a942c9..38cfeb89f33 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -3249,7 +3249,7 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info, pgcache_page_no_t page; uint block_size= share->block_size; MARIA_FILE_BITMAP *bitmap= &share->bitmap; - my_bool zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN); + my_bool zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN), error; DBUG_ENTER("maria_zerofill_data"); /* This works only with BLOCK_RECORD files */ @@ -3344,15 +3344,22 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info, PAGECACHE_UNPIN, LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, 1, FALSE); } - DBUG_RETURN(_ma_bitmap_flush(share) || - flush_pagecache_blocks(share->pagecache, &info->dfile, - FLUSH_FORCE_WRITE)); + error= _ma_bitmap_flush(share); + if (flush_pagecache_blocks(share->pagecache, &info->dfile, + FLUSH_FORCE_WRITE)) + error= 1; + DBUG_RETURN(error); err: pagecache_unlock_by_link(share->pagecache, page_link.link, PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN, LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, 0, FALSE); + /* flush what was changed so far */ + (void) _ma_bitmap_flush(share); + (void) flush_pagecache_blocks(share->pagecache, &info->dfile, + FLUSH_FORCE_WRITE); + DBUG_RETURN(1); } diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 05cb5555cdf..0a5cea8a541 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -2974,7 +2974,11 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache, } if (lsn != LSN_IMPOSSIBLE) check_and_set_lsn(pagecache, lsn, block); - block->status&= ~PCBLOCK_ERROR; + /* + Reset error flag. Mark also that page is active; This may not have + been the case if there was an error reading the page + */ + block->status= (block->status & ~PCBLOCK_ERROR) | PCBLOCK_READ; } /* if we lock for write we must link the block to changed blocks */ diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c index cf48470ec98..a7e3b49e284 100644 --- a/storage/maria/ma_state.c +++ b/storage/maria/ma_state.c @@ -616,10 +616,14 @@ void maria_versioning(MARIA_HA *info, my_bool versioning) /* For now, this is a hack */ if (info->s->have_versioning) { + enum thr_lock_type save_lock_type; /* Assume is a non threaded application (for now) */ info->s->lock_key_trees= 0; + /* Set up info->lock.type temporary for _ma_block_get_status() */ + save_lock_type= info->lock.type; info->lock.type= versioning ? TL_WRITE_CONCURRENT_INSERT : TL_WRITE; _ma_block_get_status((void*) info, versioning); + info->lock.type= save_lock_type; } } diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 54806ccc852..2b2fa692f24 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -23,9 +23,9 @@ static const char *load_default_groups[]= { "maria_read_log",0 }; static void get_options(int *argc,char * * *argv); #ifndef DBUG_OFF #if defined(__WIN__) -const char *default_dbug_option= "d:t:i:O,\\maria_read_log.trace"; +const char *default_dbug_option= "d:t:O,\\maria_read_log.trace"; #else -const char *default_dbug_option= "d:t:i:o,/tmp/maria_read_log.trace"; +const char *default_dbug_option= "d:t:o,/tmp/maria_read_log.trace"; #endif #endif /* DBUG_OFF */ static my_bool opt_display_only, opt_apply, opt_apply_undo, opt_silent;