From 45db1c24b06517b8ead23af9b455daf9db5ebe44 Mon Sep 17 00:00:00 2001 From: "gvb@phoenix.(none)" <> Date: Fri, 13 Jan 2006 14:42:46 +0100 Subject: [PATCH 01/20] fix for bug#15828 problem was not checking 2nd parameter of str_to_date against NULL --- mysql-test/r/date_formats.result | 6 ++++++ mysql-test/t/date_formats.test | 7 +++++++ sql/item_timefunc.cc | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index 34a2dedd976..b2dc1f7a67b 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -464,3 +464,9 @@ d1 d2 02 February 01 January drop table t1; +select str_to_date( 1, NULL ); +str_to_date( 1, NULL ) +NULL +select str_to_date( NULL, 1 ); +str_to_date( NULL, 1 ) +NULL diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index 6d501865d2c..dd31f1509c0 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -268,4 +268,11 @@ insert into t1 (f1) values ("2005-01-01"); insert into t1 (f1) values ("2005-02-01"); select date_format(f1, "%m") as d1, date_format(f1, "%M") as d2 from t1 order by date_format(f1, "%M"); drop table t1; + +# +# Bug #15828 +# +select str_to_date( 1, NULL ); +select str_to_date( NULL, 1 ); + # End of 4.1 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index eb58b180ed7..d060612c9f6 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2750,7 +2750,7 @@ void Item_func_str_to_date::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - if ((const_item= args[1]->const_item())) + if ((const_item= args[1]->const_item()) && !args[1]->null_value) { format= args[1]->val_str(&format_str); cached_format_type= get_date_time_result_type(format->ptr(), From 421eededd316ef07b14f06a9bfd36e1f19b35d5b Mon Sep 17 00:00:00 2001 From: "gvb@phoenix.(none)" <> Date: Sat, 14 Jan 2006 09:53:12 +0100 Subject: [PATCH 02/20] item_timefunc.cc: fix for bug#15828 after review --- sql/item_timefunc.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d060612c9f6..be8c5d2ad15 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2750,7 +2750,8 @@ void Item_func_str_to_date::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - if ((const_item= args[1]->const_item()) && !args[1]->null_value) + if (!args[1]->null_value && (const_item= args[1]->const_item())) + //if ((const_item= args[1]->const_item()) && !args[1]->null_value) { format= args[1]->val_str(&format_str); cached_format_type= get_date_time_result_type(format->ptr(), From 8885c80da2cf5d8ac852ecbc289c62f8a5c3ff69 Mon Sep 17 00:00:00 2001 From: "gvb@phoenix.(none)" <> Date: Sat, 14 Jan 2006 16:06:51 +0100 Subject: [PATCH 03/20] item_timefunc.cc: fix for bug #15828 after review --- sql/item_timefunc.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index be8c5d2ad15..b5a9064c960 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2751,7 +2751,6 @@ void Item_func_str_to_date::fix_length_and_dec() max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; if (!args[1]->null_value && (const_item= args[1]->const_item())) - //if ((const_item= args[1]->const_item()) && !args[1]->null_value) { format= args[1]->val_str(&format_str); cached_format_type= get_date_time_result_type(format->ptr(), From 8c69d6abaf9eaf731e7e589b2c3c498543003101 Mon Sep 17 00:00:00 2001 From: "gvb@phoenix.(none)" <> Date: Mon, 16 Jan 2006 15:46:37 +0100 Subject: [PATCH 04/20] date_formats.test: fix for bug #15828 after review doing val_str now before testing of null value secures the function for null values returned by dynamic functions - the fix before was incomplete andy covered constant null values --- mysql-test/r/date_formats.result | 3 +++ mysql-test/t/date_formats.test | 2 +- sql/item_timefunc.cc | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index b2dc1f7a67b..014eeed27e7 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -470,3 +470,6 @@ NULL select str_to_date( NULL, 1 ); str_to_date( NULL, 1 ) NULL +select str_to_date( 1, IF(1=1,NULL,NULL) ); +str_to_date( 1, IF(1=1,NULL,NULL) ) +NULL diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index dd31f1509c0..78b4482a94a 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -274,5 +274,5 @@ drop table t1; # select str_to_date( 1, NULL ); select str_to_date( NULL, 1 ); - +select str_to_date( 1, IF(1=1,NULL,NULL) ); # End of 4.1 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b5a9064c960..d6b57464d59 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2750,9 +2750,9 @@ void Item_func_str_to_date::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; + format= args[1]->val_str(&format_str); if (!args[1]->null_value && (const_item= args[1]->const_item())) { - format= args[1]->val_str(&format_str); cached_format_type= get_date_time_result_type(format->ptr(), format->length()); switch (cached_format_type) { From f60a763208713ce4d7a932d7ca19fee2351aed5c Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Wed, 25 Jan 2006 15:11:49 +0100 Subject: [PATCH 05/20] Fixed BUG#15737: Stored procedure optimizer bug with LEAVE Second version. The problem was that the optimizer didn't work correctly with forwards jumps to "no-op" hpop and cpop instructions. Don't generate "no-op" instructions (hpop 0 and cpop 0), it isn't actually necessary. --- mysql-test/r/sp-code.result | 139 +++++++++++++++++++++++++++++++++++ mysql-test/t/sp-code.test | 143 ++++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 21 +++--- sql/sp_head.h | 40 +++++----- sql/sql_yacc.yy | 17 ++--- 5 files changed, 321 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index 943471c2261..c9fe170dda6 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -1,3 +1,5 @@ +drop procedure if exists empty; +drop procedure if exists code_sample; create procedure empty() begin end; @@ -60,3 +62,140 @@ Pos Instruction 20 cpop 1 21 stmt 0 "select t.name, t.idx from t2 t order ..." drop procedure code_sample; +drop procedure if exists sudoku_solve; +create procedure sudoku_solve(p_naive boolean, p_all boolean) +deterministic +modifies sql data +begin +drop temporary table if exists sudoku_work, sudoku_schedule; +create temporary table sudoku_work +( +row smallint not null, +col smallint not null, +dig smallint not null, +cnt smallint, +key using btree (cnt), +key using btree (row), +key using btree (col), +unique key using hash (row,col) +); +create temporary table sudoku_schedule +( +idx int not null auto_increment primary key, +row smallint not null, +col smallint not null +); +call sudoku_init(); +if p_naive then +update sudoku_work set cnt = 0 where dig = 0; +else +call sudoku_count(); +end if; +insert into sudoku_schedule (row,col) +select row,col from sudoku_work where cnt is not null order by cnt desc; +begin +declare v_scounter bigint default 0; +declare v_i smallint default 1; +declare v_dig smallint; +declare v_schedmax smallint; +select count(*) into v_schedmax from sudoku_schedule; +more: +loop +begin +declare v_tcounter bigint default 0; +sched: +while v_i <= v_schedmax do +begin +declare v_row, v_col smallint; +select row,col into v_row,v_col from sudoku_schedule where v_i = idx; +select dig into v_dig from sudoku_work +where v_row = row and v_col = col; +case v_dig +when 0 then +set v_dig = 1; +update sudoku_work set dig = 1 +where v_row = row and v_col = col; +when 9 then +if v_i > 0 then +update sudoku_work set dig = 0 +where v_row = row and v_col = col; +set v_i = v_i - 1; +iterate sched; +else +select v_scounter as 'Solutions'; +leave more; +end if; +else +set v_dig = v_dig + 1; +update sudoku_work set dig = v_dig +where v_row = row and v_col = col; +end case; +set v_tcounter = v_tcounter + 1; +if not sudoku_digit_ok(v_row, v_col, v_dig) then +iterate sched; +end if; +set v_i = v_i + 1; +end; +end while sched; +select dig from sudoku_work; +select v_tcounter as 'Tests'; +set v_scounter = v_scounter + 1; +if p_all and v_i > 0 then +set v_i = v_i - 1; +else +leave more; +end if; +end; +end loop more; +end; +drop temporary table sudoku_work, sudoku_schedule; +end// +show procedure code sudoku_solve; +Pos Instruction +0 stmt 9 "drop temporary table if exists sudoku..." +1 stmt 1 "create temporary table sudoku_work ( ..." +2 stmt 1 "create temporary table sudoku_schedul..." +3 stmt 95 "call sudoku_init(" +4 jump_if_not 7(8) p_naive@0 +5 stmt 4 "update sudoku_work set cnt = 0 where ..." +6 jump 8 +7 stmt 95 "call sudoku_count(" +8 stmt 6 "insert into sudoku_schedule (row,col)..." +9 set v_scounter@2 0 +10 set v_i@3 1 +11 set v_dig@4 NULL +12 set v_schedmax@5 NULL +13 stmt 0 "select count(*) into v_schedmax from ..." +14 set v_tcounter@6 0 +15 jump_if_not 39(39) (v_i@3 <= v_schedmax@5) +16 set v_row@7 NULL +17 set v_col@8 NULL +18 stmt 0 "select row,col into v_row,v_col from ..." +19 stmt 0 "select dig into v_dig from sudoku_wor..." +20 set_case_expr 0 v_dig@4 +21 jump_if_not 25(34) (case_expr@0 = 0) +22 set v_dig@4 1 +23 stmt 4 "update sudoku_work set dig = 1 where ..." +24 jump 34 +25 jump_if_not 32(34) (case_expr@0 = 9) +26 jump_if_not 30(34) (v_i@3 > 0) +27 stmt 4 "update sudoku_work set dig = 0 where ..." +28 set v_i@3 (v_i@3 - 1) +29 jump 15 +30 stmt 0 "select v_scounter as 'Solutions'" +31 jump 45 +32 set v_dig@4 (v_dig@4 + 1) +33 stmt 4 "update sudoku_work set dig = v_dig wh..." +34 set v_tcounter@6 (v_tcounter@6 + 1) +35 jump_if_not 37(37) not(`test`.`sudoku_digit_ok`(v_row@7,v_col@8,v_dig@4)) +36 jump 15 +37 set v_i@3 (v_i@3 + 1) +38 jump 15 +39 stmt 0 "select dig from sudoku_work" +40 stmt 0 "select v_tcounter as 'Tests'" +41 set v_scounter@2 (v_scounter@2 + 1) +42 jump_if_not 45(14) (p_all@1 and (v_i@3 > 0)) +43 set v_i@3 (v_i@3 - 1) +44 jump 14 +45 stmt 9 "drop temporary table sudoku_work, sud..." +drop procedure sudoku_solve; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index 6644bc3ab43..b7b1fdbbb20 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -4,6 +4,11 @@ -- source include/is_debug_build.inc +--disable_warnings +drop procedure if exists empty; +drop procedure if exists code_sample; +--enable_warnings + create procedure empty() begin end; @@ -47,3 +52,141 @@ end// delimiter ;// show procedure code code_sample; drop procedure code_sample; + + +# +# BUG#15737: Stored procedure optimizer bug with LEAVE +# +# This is a much more extensive test case than is strictly needed, +# but it was kept as is for two reasons: +# - The bug occurs under some quite special circumstances, so it +# wasn't trivial to create a smaller test, +# - There's some value in having another more complex code sample +# in this test file. This might catch future code generation bugs +# that doesn't not show in behaviour in any obvious way. + +--disable_warnings +drop procedure if exists sudoku_solve; +--enable_warnings + +delimiter //; +create procedure sudoku_solve(p_naive boolean, p_all boolean) + deterministic + modifies sql data +begin + drop temporary table if exists sudoku_work, sudoku_schedule; + + create temporary table sudoku_work + ( + row smallint not null, + col smallint not null, + dig smallint not null, + cnt smallint, + key using btree (cnt), + key using btree (row), + key using btree (col), + unique key using hash (row,col) + ); + + create temporary table sudoku_schedule + ( + idx int not null auto_increment primary key, + row smallint not null, + col smallint not null + ); + + call sudoku_init(); + + if p_naive then + update sudoku_work set cnt = 0 where dig = 0; + else + call sudoku_count(); + end if; + insert into sudoku_schedule (row,col) + select row,col from sudoku_work where cnt is not null order by cnt desc; + + begin + declare v_scounter bigint default 0; + declare v_i smallint default 1; + declare v_dig smallint; + declare v_schedmax smallint; + + select count(*) into v_schedmax from sudoku_schedule; + + more: + loop + begin + declare v_tcounter bigint default 0; + + sched: + while v_i <= v_schedmax do + begin + declare v_row, v_col smallint; + + select row,col into v_row,v_col from sudoku_schedule where v_i = idx; + + select dig into v_dig from sudoku_work + where v_row = row and v_col = col; + + case v_dig + when 0 then + set v_dig = 1; + update sudoku_work set dig = 1 + where v_row = row and v_col = col; + when 9 then + if v_i > 0 then + update sudoku_work set dig = 0 + where v_row = row and v_col = col; + set v_i = v_i - 1; + iterate sched; + else + select v_scounter as 'Solutions'; + leave more; + end if; + else + set v_dig = v_dig + 1; + update sudoku_work set dig = v_dig + where v_row = row and v_col = col; + end case; + + set v_tcounter = v_tcounter + 1; + if not sudoku_digit_ok(v_row, v_col, v_dig) then + iterate sched; + end if; + set v_i = v_i + 1; + end; + end while sched; + + select dig from sudoku_work; + select v_tcounter as 'Tests'; + set v_scounter = v_scounter + 1; + + if p_all and v_i > 0 then + set v_i = v_i - 1; + else + leave more; + end if; + end; + end loop more; + end; + + drop temporary table sudoku_work, sudoku_schedule; +end// +delimiter ;// + +# The interestings parts are where the code for the two "leave" are: +# ... +#| 26 | jump_if_not 30 (v_i@3 > 0) | +# ... +#| 30 | stmt 0 "select v_scounter as 'Solutions'" | +#| 31 | jump 45 | +# ... +#| 42 | jump_if_not 45 (p_all@1 and (v_i@3 > 0)) | +#| 43 | set v_i@3 (v_i@3 - 1) | +#| 44 | jump 14 | +#| 45 | stmt 9 "drop temporary table sudoku_work, sud..." | +#+-----+-----------------------------------------------------------------------+ +# The bug appeared at position 42 (with the wrong destination). +show procedure code sudoku_solve; + +drop procedure sudoku_solve; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ae27b910304..173c35328b1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2011,6 +2011,15 @@ sp_head::show_create_function(THD *thd) 1) Mark used instructions 1.1) While doing this, shortcut jumps to jump instructions 2) Compact the code, removing unused instructions + + This is the main mark and move loop; it relies on the following methods + in sp_instr and its subclasses: + + opt_mark() Mark instruction as reachable (will recurse for jumps) + opt_shortcut_jump() Shortcut jumps to the final destination; + used by opt_mark(). + opt_move() Update moved instruction + set_destination() Set the new destination (jump instructions only) */ void sp_head::optimize() @@ -2703,12 +2712,6 @@ sp_instr_hpop::print(String *str) str->qs_append(m_count); } -void -sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx) -{ - m_count= m_ctx->diff_handlers(dst_ctx); -} - /* sp_instr_hreturn class functions @@ -2830,12 +2833,6 @@ sp_instr_cpop::print(String *str) str->qs_append(m_count); } -void -sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx) -{ - m_count= m_ctx->diff_cursors(dst_ctx); -} - /* sp_instr_copen class functions diff --git a/sql/sp_head.h b/sql/sp_head.h index 858bf523a07..89e86badc09 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -461,17 +461,34 @@ public: virtual void backpatch(uint dest, sp_pcontext *dst_ctx) {} + /* + Mark this instruction as reachable during optimization and return the + index to the next instruction. Jump instruction will mark their + destination too recursively. + */ virtual uint opt_mark(sp_head *sp) { marked= 1; return m_ip+1; } + /* + Short-cut jumps to jumps during optimization. This is used by the + jump instructions' opt_mark() methods. 'start' is the starting point, + used to prevent the mark sweep from looping for ever. Return the + end destination. + */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; } + /* + Inform the instruction that it has been moved during optimization. + Most instructions will simply update its index, but jump instructions + must also take care of their destination pointers. Forward jumps get + pushed to the backpatch list 'ibp'. + */ virtual void opt_move(uint dst, List *ibp) { m_ip= dst; @@ -696,6 +713,9 @@ public: m_dest= dest; } + /* + Update the destination; used by the optimizer. + */ virtual void set_destination(uint old_dest, uint new_dest) { if (m_dest == old_dest) @@ -739,6 +759,7 @@ public: virtual uint opt_mark(sp_head *sp); + /* Override sp_instr_jump's shortcut; we stop here */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; @@ -822,6 +843,7 @@ public: virtual uint opt_mark(sp_head *sp); + /* Override sp_instr_jump's shortcut; we stop here. */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; @@ -859,15 +881,6 @@ public: virtual void print(String *str); - virtual void backpatch(uint dest, sp_pcontext *dst_ctx); - - virtual uint opt_mark(sp_head *sp) - { - if (m_count) - marked= 1; - return m_ip+1; - } - private: uint m_count; @@ -953,15 +966,6 @@ public: virtual void print(String *str); - virtual void backpatch(uint dest, sp_pcontext *dst_ctx); - - virtual uint opt_mark(sp_head *sp) - { - if (m_count) - marked= 1; - return m_ip+1; - } - private: uint m_count; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0ef389950fc..f41a8b7e979 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2064,17 +2064,16 @@ sp_proc_stmt: } else { - uint ip= sp->instructions(); sp_instr_jump *i; - sp_instr_hpop *ih; - sp_instr_cpop *ic; + uint ip= sp->instructions(); + uint n; - ih= new sp_instr_hpop(ip++, ctx, 0); - sp->push_backpatch(ih, lab); - sp->add_instr(ih); - ic= new sp_instr_cpop(ip++, ctx, 0); - sp->push_backpatch(ic, lab); - sp->add_instr(ic); + n= ctx->diff_handlers(lab->ctx); + if (n) + sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); + n= ctx->diff_cursors(lab->ctx); + if (n) + sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); i= new sp_instr_jump(ip, ctx); sp->push_backpatch(i, lab); /* Jumping forward */ sp->add_instr(i); From 998f0c0aa32116bf094d4e4ac407ee6c6a3a1629 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Wed, 25 Jan 2006 17:19:54 +0100 Subject: [PATCH 06/20] Fixed BUGS#15011: error handler for mysql errno in nested block not activated For nested sql errno handlers (unlike sqlexception and other), we didn't stop searching when the innermost handler was found - now make sure we do. --- mysql-test/r/sp.result | 19 +++++++++++++++++++ mysql-test/t/sp.test | 31 +++++++++++++++++++++++++++++++ sql/sp_rcontext.cc | 3 ++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 904cd7d8642..90020573df3 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4497,4 +4497,23 @@ drop procedure if exists bug15231_1| drop procedure if exists bug15231_2| drop procedure if exists bug15231_3| drop procedure if exists bug15231_4| +drop procedure if exists bug15011| +create table t3 (c1 int primary key)| +insert into t3 values (1)| +create procedure bug15011() +deterministic +begin +declare continue handler for 1062 +select 'Outer' as 'Handler'; +begin +declare continue handler for 1062 +select 'Inner' as 'Handler'; +insert into t3 values (1); +end; +end| +call bug15011()| +Handler +Inner +drop procedure bug15011| +drop table t3| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 8235686a74a..32299ad7e0b 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5283,6 +5283,37 @@ drop procedure if exists bug15231_3| drop procedure if exists bug15231_4| +# +# BUG#15011: error handler in nested block not activated +# +--disable_warnings +drop procedure if exists bug15011| +--enable_warnings + +create table t3 (c1 int primary key)| + +insert into t3 values (1)| + +create procedure bug15011() + deterministic +begin + declare continue handler for 1062 + select 'Outer' as 'Handler'; + + begin + declare continue handler for 1062 + select 'Inner' as 'Handler'; + + insert into t3 values (1); + end; +end| + +call bug15011()| + +drop procedure bug15011| +drop table t3| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 215de01e657..4818ffbbe31 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -188,7 +188,8 @@ sp_rcontext::find_handler(uint sql_errno, switch (cond->type) { case sp_cond_type_t::number: - if (sql_errno == cond->mysqlerr) + if (sql_errno == cond->mysqlerr && + (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number)) found= i; // Always the most specific break; case sp_cond_type_t::state: From 737084b22915b7ccc22064d8734fd142a6b4f1a2 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Sat, 28 Jan 2006 12:50:16 +0300 Subject: [PATCH 07/20] Fix for bug #16829 "Firing trigger with RETURN crashes the server" We should disallow usage of RETURN statement in triggers and emit error at parsing time (instead of crashing when trigger is fired). --- mysql-test/r/trigger.result | 5 +++++ mysql-test/t/trigger.test | 9 +++++++++ sql/sql_yacc.yy | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 9cfecde7610..ec63757df3a 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -785,3 +785,8 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0; ERROR 3D000: No database selected drop trigger t1_bi; ERROR 3D000: No database selected +create table t1 (i int); +create trigger t1_bi before insert on t1 for each row return 0; +ERROR 42000: RETURN is only allowed in a FUNCTION +insert into t1 values (1); +drop table t1; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index f2d9bb6c856..679698db4c0 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -958,3 +958,12 @@ create trigger test.t1_bi before insert on t1 for each row set @a:=0; --error ER_NO_DB_ERROR drop trigger t1_bi; connection default; + +# Test for bug #16829 "Firing trigger with RETURN crashes the server" +# RETURN is not supposed to be used anywhere except functions, so error +# should be returned when one attempts to create trigger with RETURN. +create table t1 (i int); +--error ER_SP_BADRETURN +create trigger t1_bi before insert on t1 for each row return 0; +insert into t1 values (1); +drop table t1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0ef389950fc..055e5a9e908 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1981,7 +1981,7 @@ sp_proc_stmt: LEX *lex= Lex; sp_head *sp= lex->sphead; - if (sp->m_type == TYPE_ENUM_PROCEDURE) + if (sp->m_type != TYPE_ENUM_FUNCTION) { my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0)); YYABORT; From 67f34be9612566466b7ada3f56307a29512cb447 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 30 Jan 2006 15:04:00 +0100 Subject: [PATCH 08/20] Post-review fix for BUG#15737 (corrected typo in sp-code.test comment) --- mysql-test/t/sp-code.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index b7b1fdbbb20..0a26ea644f6 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -63,7 +63,7 @@ drop procedure code_sample; # wasn't trivial to create a smaller test, # - There's some value in having another more complex code sample # in this test file. This might catch future code generation bugs -# that doesn't not show in behaviour in any obvious way. +# that doesn't show in behaviour in any obvious way. --disable_warnings drop procedure if exists sudoku_solve; From b7c3d5ef865b06641758eba0750d51e9ba11fdcc Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 31 Jan 2006 08:51:21 +0100 Subject: [PATCH 09/20] Update trigger-grant-test to use MYSQLTEST_VARDIR --- mysql-test/t/trigger-grant.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test index e28bf44a2cc..297aa445322 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger-grant.test @@ -232,9 +232,9 @@ CREATE TRIGGER trg5 BEFORE DELETE ON t1 FOR EACH ROW SET @a = 5; ---exec egrep -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG ---exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQL_TEST_DIR/var/tmp/t1.TRG ---exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG +--exec egrep -v '^definers=' $MYSQLTEST_VARDIR/master-data/mysqltest_db1/t1.TRG > $MYSQLTEST_VARDIR/tmp/t1.TRG +--exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQLTEST_VARDIR/tmp/t1.TRG +--exec mv $MYSQLTEST_VARDIR/tmp/t1.TRG $MYSQLTEST_VARDIR/master-data/mysqltest_db1/t1.TRG --echo From a002d316edf6822203ae9fc2d8ca9a2cb8d9414b Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Tue, 31 Jan 2006 09:15:28 +0100 Subject: [PATCH 10/20] Fix missing --replace_result on $SLAVE_MYPORT in federated. --- mysql-test/r/federated.result | 2 +- mysql-test/t/federated.test | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 4391889fec9..c1e7533bcee 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -1530,7 +1530,7 @@ CREATE TABLE federated.t1 ( PRIMARY KEY (`id`) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 -CONNECTION='mysql://root@127.0.0.1:9308/federated/t1'; +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES (); SELECT LAST_INSERT_ID(); LAST_INSERT_ID() diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index e550c5d3ac0..d1e03f8a05a 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1235,6 +1235,7 @@ CREATE TABLE federated.t1 ( connection master; DROP TABLE IF EXISTS federated.t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT eval CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, PRIMARY KEY (`id`) From a71de6bfe2022eb1a0c93c6078b0de9ed48b5c88 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 31 Jan 2006 09:38:40 +0100 Subject: [PATCH 11/20] Bug #16919 some tests fail in 5.0 - Use "../tmp" as --slave-load-tmpdir. Same as in mysql-test-run.pl --- mysql-test/mysql-test-run.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 47253fec572..21eeb65943d 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -202,7 +202,14 @@ SYST=0 REALT=0 FAST_START="" MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp -SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging + +# Use a relative path for where the slave will find the dumps +# generated by "LOAD DATA" on the master. The path is relative +# since it must have fixed length to test logging +# i.e otherwise the output from "SHOW MASTER STATUS" will vary +# with the strlen() of MYSQL_TEST_DIR +SLAVE_LOAD_TMPDIR=../tmp + RES_SPACE=" " MYSQLD_SRC_DIRS="strings mysys include extra regex myisam \ myisammrg heap sql" From 10036d354c7aaa2b6d137081fb780fe351387702 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 31 Jan 2006 10:48:40 +0100 Subject: [PATCH 12/20] Check std_data_ln already created Add / to std_data in ln command --- mysql-test/mysql-test-run.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 21eeb65943d..ac5457beaa6 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -608,8 +608,10 @@ fi [ -d $MYSQL_TEST_DIR/var/tmp ] || mkdir $MYSQL_TEST_DIR/var/tmp [ -d $MYSQL_TEST_DIR/var/run ] || mkdir $MYSQL_TEST_DIR/var/run [ -d $MYSQL_TEST_DIR/var/log ] || mkdir $MYSQL_TEST_DIR/var/log -ln -s $MYSQL_TEST_DIR/std_data $MYSQL_TEST_DIR/var/std_data_ln - +if ! test -L $MYSQL_TEST_DIR/var/std_data_ln ; then + ln -s $MYSQL_TEST_DIR/std_data/ $MYSQL_TEST_DIR/var/std_data_ln +fi + if test ${COLUMNS:-0} -lt 80 ; then COLUMNS=80 ; fi E=`$EXPR $COLUMNS - 8` DASH72=`$ECHO '-------------------------------------------------------'|$CUT -c 1-$E` From af11dc3cbe84ded7f22ff78e00e881975c0cc340 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 31 Jan 2006 16:27:57 +0100 Subject: [PATCH 13/20] Added test case for BUG#14270: Stored procedures: crash if load index which was fixed by earlier changesets; LOAD INDEX is not allowed in functions. Also testing CACHE INDEX, while OPTIMIZE and CHECK were covered by existing tests already. --- mysql-test/r/sp-error.result | 16 ++++++++++++++++ mysql-test/t/sp-error.test | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 8483f6dc664..fb544ccd8de 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1147,3 +1147,19 @@ show procedure status; Db Name Type Definer Modified Created Security_type Comment test bug15658 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER drop procedure ` bug15658`; +drop function if exists bug14270; +drop table if exists t1; +create table t1 (s1 int primary key); +create function bug14270() returns int +begin +load index into cache t1; +return 1; +end| +ERROR 0A000: Not allowed to return a result set from a function +create function bug14270() returns int +begin +cache index t1 key (`primary`) in keycache1; +return 1; +end| +ERROR 0A000: Not allowed to return a result set from a function +drop table t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 25944144d21..22cc325f55e 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1643,6 +1643,35 @@ show procedure status; drop procedure ` bug15658`; +# +# BUG#14270: Stored procedures: crash if load index +# +--disable_warnings +drop function if exists bug14270; +drop table if exists t1; +--enable_warnings + +create table t1 (s1 int primary key); + +delimiter |; +--error ER_SP_NO_RETSET +create function bug14270() returns int +begin + load index into cache t1; + return 1; +end| + +--error ER_SP_NO_RETSET +create function bug14270() returns int +begin + cache index t1 key (`primary`) in keycache1; + return 1; +end| +delimiter ;| + +drop table t1; + + # # BUG#NNNN: New bug synopsis # From b3ebd755cc7925675b73b4f631e94b0a3e603276 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 31 Jan 2006 17:00:50 +0100 Subject: [PATCH 14/20] Added test case for BUG#15091: Sp Returns Unknown error in order clause....and there is no order by clause which was fixed by earlier changesets. The error message is now the more generic "Unknown table ... in field list". --- mysql-test/r/sp-error.result | 13 +++++++++++++ mysql-test/t/sp-error.test | 31 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index fb544ccd8de..2766dca5845 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1163,3 +1163,16 @@ return 1; end| ERROR 0A000: Not allowed to return a result set from a function drop table t1; +drop procedure if exists bug15091; +create procedure bug15091() +begin +declare selectstr varchar(6000) default ' '; +declare conditionstr varchar(5000) default ''; +set selectstr = concat(selectstr, +' and ', +c.operatorid, +'in (',conditionstr, ')'); +end| +call bug15091(); +ERROR 42S02: Unknown table 'c' in field list +drop procedure bug15091; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 22cc325f55e..e1839b4b98f 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1672,6 +1672,37 @@ delimiter ;| drop table t1; +# +# BUG#15091: Sp Returns Unknown error in order clause....and +# there is no order by clause +# +--disable_warnings +drop procedure if exists bug15091; +--enable_warnings + +delimiter |; +create procedure bug15091() +begin + declare selectstr varchar(6000) default ' '; + declare conditionstr varchar(5000) default ''; + + set selectstr = concat(selectstr, + ' and ', + c.operatorid, + 'in (',conditionstr, ')'); +end| +delimiter ;| + +# The error message used to be: +# ERROR 1109 (42S02): Unknown table 'c' in order clause +# but is now rephrased to something less misleading: +# ERROR 1109 (42S02): Unknown table 'c' in field list +--error ER_UNKNOWN_TABLE +call bug15091(); + +drop procedure bug15091; + + # # BUG#NNNN: New bug synopsis # From 9296fb241d50199a60df7d9a0e93ac730432b82c Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 31 Jan 2006 21:41:48 +0300 Subject: [PATCH 15/20] Fixed: BUG#15653, BUG#16157, BUG#16229, BUG#16298, BUG#16387, BUG#16582. Applied innodb-5.0-ss149/162 snapshots. --- innobase/btr/btr0sea.c | 44 ++++++++++++++-- innobase/dict/dict0dict.c | 3 +- innobase/dict/dict0load.c | 20 ++++++-- innobase/fil/fil0fil.c | 83 +++++++++++++++++++++++++++++- innobase/include/univ.i | 6 --- innobase/os/os0sync.c | 32 ++++++------ innobase/srv/srv0start.c | 14 +++++ mysql-test/r/innodb.result | 71 ++++++++++++++++++++++++++ mysql-test/t/innodb.test | 102 +++++++++++++++++++++++++++++++++++++ sql/ha_innodb.cc | 59 ++++++++++++--------- sql/ha_innodb.h | 13 +---- 11 files changed, 377 insertions(+), 70 deletions(-) diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 81f23cfa99c..32e22aa51bc 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -191,7 +191,7 @@ static void btr_search_info_update_hash( /*========================*/ - btr_search_t* info, /* in: search info */ + btr_search_t* info, /* in/out: search info */ btr_cur_t* cursor) /* in: cursor which was just positioned */ { dict_index_t* index; @@ -452,7 +452,7 @@ Updates the search info. */ void btr_search_info_update_slow( /*========================*/ - btr_search_t* info, /* in: search info */ + btr_search_t* info, /* in/out: search info */ btr_cur_t* cursor) /* in: cursor which was just positioned */ { buf_block_t* block; @@ -912,12 +912,12 @@ btr_search_drop_page_hash_index( ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - +retry: rw_lock_s_lock(&btr_search_latch); block = buf_block_align(page); - if (!block->is_hashed) { + if (UNIV_LIKELY(!block->is_hashed)) { rw_lock_s_unlock(&btr_search_latch); @@ -958,6 +958,8 @@ btr_search_drop_page_hash_index( tree_id = btr_page_get_index_id(page); + ut_a(0 == ut_dulint_cmp(tree_id, index->id)); + prev_fold = 0; heap = NULL; @@ -992,6 +994,26 @@ next_rec: rw_lock_x_lock(&btr_search_latch); + if (UNIV_UNLIKELY(!block->is_hashed)) { + /* Someone else has meanwhile dropped the hash index */ + + goto cleanup; + } + + ut_a(block->index == index); + + if (UNIV_UNLIKELY(block->curr_n_fields != n_fields) + || UNIV_UNLIKELY(block->curr_n_bytes != n_bytes)) { + + /* Someone else has meanwhile built a new hash index on the + page, with different parameters */ + + rw_lock_x_unlock(&btr_search_latch); + + mem_free(folds); + goto retry; + } + for (i = 0; i < n_cached; i++) { ha_remove_all_nodes_to_page(table, folds[i], page); @@ -999,8 +1021,20 @@ next_rec: block->is_hashed = FALSE; block->index = NULL; +cleanup: + if (UNIV_UNLIKELY(block->n_pointers)) { + /* Corruption */ + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Corruption of adaptive hash index. After dropping\n" +"InnoDB: the hash index to a page of %s, still %lu hash nodes remain.\n", + index->name, (ulong) block->n_pointers); + rw_lock_x_unlock(&btr_search_latch); - rw_lock_x_unlock(&btr_search_latch); + btr_search_validate(); + } else { + rw_lock_x_unlock(&btr_search_latch); + } mem_free(folds); } diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 8050eebddd8..58c4e3ed6a3 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2803,7 +2803,8 @@ dict_table_get_highest_foreign_id( if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len && 0 == ut_memcmp(foreign->id, table->name, len) && 0 == ut_memcmp(foreign->id + len, - dict_ibfk, (sizeof dict_ibfk) - 1)) { + dict_ibfk, (sizeof dict_ibfk) - 1) + && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') { /* It is of the >= 4.0.18 format */ id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1), diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 3281f9926f9..6415cc56b61 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -385,13 +385,23 @@ dict_load_columns( field = rec_get_nth_field_old(rec, 6, &len); prtype = mach_read_from_4(field); - if (dtype_is_non_binary_string_type(mtype, prtype) - && dtype_get_charset_coll(prtype) == 0) { - /* This is a non-binary string type, and the table - was created with < 4.1.2. Use the default charset. */ + if (dtype_get_charset_coll(prtype) == 0 + && dtype_is_string_type(mtype)) { + /* The table was created with < 4.1.2. */ - prtype = dtype_form_prtype(prtype, + if (dtype_is_binary_string_type(mtype, prtype)) { + /* Use the binary collation for + string columns of binary type. */ + + prtype = dtype_form_prtype(prtype, + DATA_MYSQL_BINARY_CHARSET_COLL); + } else { + /* Use the default charset for + other than binary columns. */ + + prtype = dtype_form_prtype(prtype, data_mysql_default_charset_coll); + } } field = rec_get_nth_field_old(rec, 7, &len); diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 20f522c1a60..69c076d78f3 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -181,6 +181,11 @@ struct fil_space_struct { hash_node_t name_hash;/* hash chain the name_hash table */ rw_lock_t latch; /* latch protecting the file space storage allocation */ + UT_LIST_NODE_T(fil_space_t) unflushed_spaces; + /* list of spaces with at least one unflushed + file we have written to */ + ibool is_in_unflushed_spaces; /* TRUE if this space is + currently in the list above */ UT_LIST_NODE_T(fil_space_t) space_list; /* list of all spaces */ ibuf_data_t* ibuf_data; @@ -213,6 +218,12 @@ struct fil_system_struct { not put to this list: they are opened after the startup, and kept open until shutdown */ + UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces; + /* base node for the list of those + tablespaces whose files contain + unflushed writes; those spaces have + at least one file node where + modification_counter > flush_counter */ ulint n_open; /* number of files currently open */ ulint max_n_open; /* n_open is not allowed to exceed this */ @@ -389,6 +400,36 @@ fil_space_get_ibuf_data( return(space->ibuf_data); } +/************************************************************************** +Checks if all the file nodes in a space are flushed. The caller must hold +the fil_system mutex. */ +static +ibool +fil_space_is_flushed( +/*=================*/ + /* out: TRUE if all are flushed */ + fil_space_t* space) /* in: space */ +{ + fil_node_t* node; + +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(fil_system->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + node = UT_LIST_GET_FIRST(space->chain); + + while (node) { + if (node->modification_counter > node->flush_counter) { + + return(FALSE); + } + + node = UT_LIST_GET_NEXT(chain, node); + } + + return(TRUE); +} + /*********************************************************************** Appends a new file to the chain of files of a space. File must be closed. */ @@ -841,6 +882,16 @@ fil_node_free( node->modification_counter = node->flush_counter; + if (space->is_in_unflushed_spaces + && fil_space_is_flushed(space)) { + + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, + system->unflushed_spaces, + space); + } + fil_node_close_file(node, system); } @@ -1004,6 +1055,8 @@ try_again: HASH_INSERT(fil_space_t, name_hash, system->name_hash, ut_fold_string(name), space); + space->is_in_unflushed_spaces = FALSE; + UT_LIST_ADD_LAST(space_list, system->space_list, space); mutex_exit(&(system->mutex)); @@ -1099,6 +1152,13 @@ fil_space_free( HASH_DELETE(fil_space_t, name_hash, system->name_hash, ut_fold_string(space->name), space); + if (space->is_in_unflushed_spaces) { + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, system->unflushed_spaces, + space); + } + UT_LIST_REMOVE(space_list, system->space_list, space); ut_a(space->magic_n == FIL_SPACE_MAGIC_N); @@ -1250,6 +1310,7 @@ fil_system_create( system->tablespace_version = 0; + UT_LIST_INIT(system->unflushed_spaces); UT_LIST_INIT(system->space_list); return(system); @@ -3742,6 +3803,14 @@ fil_node_complete_io( if (type == OS_FILE_WRITE) { system->modification_counter++; node->modification_counter = system->modification_counter; + + if (!node->space->is_in_unflushed_spaces) { + + node->space->is_in_unflushed_spaces = TRUE; + UT_LIST_ADD_FIRST(unflushed_spaces, + system->unflushed_spaces, + node->space); + } } if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE @@ -4162,6 +4231,16 @@ retry: skip_flush: if (node->flush_counter < old_mod_counter) { node->flush_counter = old_mod_counter; + + if (space->is_in_unflushed_spaces + && fil_space_is_flushed(space)) { + + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, + system->unflushed_spaces, + space); + } } if (space->purpose == FIL_TABLESPACE) { @@ -4193,7 +4272,7 @@ fil_flush_file_spaces( mutex_enter(&(system->mutex)); - space = UT_LIST_GET_FIRST(system->space_list); + space = UT_LIST_GET_FIRST(system->unflushed_spaces); while (space) { if (space->purpose == purpose && !space->is_being_deleted) { @@ -4209,7 +4288,7 @@ fil_flush_file_spaces( space->n_pending_flushes--; } - space = UT_LIST_GET_NEXT(space_list, space); + space = UT_LIST_GET_NEXT(unflushed_spaces, space); } mutex_exit(&(system->mutex)); diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 15650f22ed8..dd4862b3808 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -126,14 +126,8 @@ by one. */ #ifdef __WIN__ #define UNIV_INLINE __inline #else -/* config.h contains the right def for 'inline' for the current compiler */ -#if (__GNUC__ == 2) -#define UNIV_INLINE extern inline -#else -/* extern inline doesn't work with gcc 3.0.2 */ #define UNIV_INLINE static inline #endif -#endif #else /* If we want to compile a noninlined version we use the following macro diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 487e8f40a39..8bafb73baf8 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -317,28 +317,28 @@ os_event_wait( os_fast_mutex_lock(&(event->os_mutex)); old_signal_count = event->signal_count; -loop: - if (event->is_set == TRUE - || event->signal_count != old_signal_count) { - os_fast_mutex_unlock(&(event->os_mutex)); + for (;;) { + if (event->is_set == TRUE + || event->signal_count != old_signal_count) { - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_fast_mutex_unlock(&(event->os_mutex)); - os_thread_exit(NULL); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + + os_thread_exit(NULL); + } + /* Ok, we may return */ + + return; } - /* Ok, we may return */ - return; + pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); + + /* Solaris manual said that spurious wakeups may occur: we + have to check if the event really has been signaled after + we came here to wait */ } - - pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); - - /* Solaris manual said that spurious wakeups may occur: we have to - check if the event really has been signaled after we came here to - wait */ - - goto loop; #endif } diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 4f99f340e1c..b345a27af20 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -233,6 +233,13 @@ srv_parse_data_file_paths_and_sizes( } } + if (i == 0) { + /* If innodb_data_file_path was defined it must contain + at least one data file definition */ + + return(FALSE); + } + *data_file_names = (char**)ut_malloc(i * sizeof(void*)); *data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint)); *data_file_is_raw_partition = (ulint*)ut_malloc(i * sizeof(ulint)); @@ -379,6 +386,13 @@ srv_parse_log_group_home_dirs( } } + if (i != 1) { + /* If innodb_log_group_home_dir was defined it must + contain exactly one path definition under current MySQL */ + + return(FALSE); + } + *log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*)); /* Then store the actual values to our array */ diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 0816d0de43c..163b9302b5c 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3180,3 +3180,74 @@ a hex(b) 7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 update t1 set b = 'three' where a = 6; drop table t1; +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) default NULL, + KEY `t2_ibfk_0` (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t2,t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +set autocommit = 0; +update t1 set b = 5 where a = 2; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +set autocommit = 0; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +commit; +commit; +drop trigger t1t; +drop table t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); +create trigger t1t before insert on t1 for each row begin +INSERT INTO t2 SET a = NEW.a; +end | +create trigger t2t before insert on t2 for each row begin +DELETE FROM t3 WHERE a = NEW.a; +end | +create trigger t3t before delete on t3 for each row begin +UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | +create trigger t4t before update on t4 for each row begin +UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 8d2f18e2362..a47e635cf74 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2047,3 +2047,105 @@ insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 select a,hex(b) from t1 order by b; update t1 set b = 'three' where a = 6; drop table t1; + +# Ensure that _ibfk_0 is not mistreated as a +# generated foreign key identifier. (Bug #16387) + +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +DROP TABLE t2,t1; + +# +# Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +connection b; +set autocommit = 0; +update t1 set b = 5 where a = 2; +connection a; +delimiter |; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +delimiter ;| +set autocommit = 0; +connection a; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +connection b; +commit; +connection a; +commit; +drop trigger t1t; +drop table t1; +disconnect a; +disconnect b; +# +# Another trigger test +# +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); + +delimiter |; +create trigger t1t before insert on t1 for each row begin + INSERT INTO t2 SET a = NEW.a; +end | + +create trigger t2t before insert on t2 for each row begin + DELETE FROM t3 WHERE a = NEW.a; +end | + +create trigger t3t before delete on t3 for each row begin + UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | + +create trigger t4t before update on t4 for each row begin + UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +delimiter ;| +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +connection b; +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; +disconnect a; +disconnect b; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b33d2dfbd97..1b1326920ad 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -138,8 +138,6 @@ extern "C" { #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ #define HA_INNOBASE_RANGE_COUNT 100 -uint innobase_init_flags = 0; -ulong innobase_cache_size = 0; ulong innobase_large_page_size = 0; /* The default values for the following, type long or longlong, start-up @@ -187,8 +185,6 @@ it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 ulong innobase_active_counter = 0; -char* innobase_home = NULL; - static HASH innobase_open_tables; #ifdef __NETWARE__ /* some special cleanup for NetWare */ @@ -814,7 +810,6 @@ ha_innobase::ha_innobase(TABLE *table_arg) HA_PRIMARY_KEY_IN_READ_INDEX | HA_CAN_GEOMETRY | HA_TABLE_SCAN_ON_INDEX), - last_dup_key((uint) -1), start_of_scan(0), num_write_row(0) {} @@ -983,6 +978,11 @@ innobase_query_caching_of_table_permitted( sql_print_error("The calling thread is holding the adaptive " "search, latch though calling " "innobase_query_caching_of_table_permitted."); + + mutex_enter_noninline(&kernel_mutex); + trx_print(stderr, trx, 1024); + mutex_exit_noninline(&kernel_mutex); + ut_error; } innobase_release_stat_resources(trx); @@ -6329,14 +6329,17 @@ ha_innobase::external_lock( TABLES if AUTOCOMMIT=1. It does not make much sense to acquire an InnoDB table lock if it is released immediately at the end of LOCK TABLES, and InnoDB's table locks in that case cause - VERY easily deadlocks. We do not set InnoDB table locks when - MySQL sets them at the start of a stored procedure call - (MySQL does have thd->in_lock_tables TRUE there). */ + VERY easily deadlocks. + + We do not set InnoDB table locks if user has not explicitly + requested a table lock. Note that thd->in_lock_tables + can be TRUE on some cases e.g. at the start of a stored + procedure call (SQLCOM_CALL). */ if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && - thd->lex->sql_command != SQLCOM_CALL && + thd->lex->sql_command == SQLCOM_LOCK_TABLES && thd->variables.innodb_table_locks && (thd->options & OPTION_NOT_AUTOCOMMIT)) { @@ -6838,7 +6841,7 @@ ha_innobase::store_lock( } else if (lock_type != TL_IGNORE) { - /* We set possible LOCK_X value in external_lock, not yet + /* We set possible LOCK_X value in external_lock, not yet here even if this would be SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_NONE; @@ -6847,7 +6850,7 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { - /* Starting from 5.0.7, we weaken also the table locks + /* Starting from 5.0.7, we weaken also the table locks set at the start of a MySQL stored procedure call, just like we weaken the locks set at the start of an SQL statement. MySQL does set thd->in_lock_tables TRUE there, but in reality @@ -6870,26 +6873,36 @@ ha_innobase::store_lock( lock_type = TL_READ_NO_INSERT; } - /* If we are not doing a LOCK TABLE or DISCARD/IMPORT - TABLESPACE or TRUNCATE TABLE, then allow multiple writers */ + /* If we are not doing a LOCK TABLE, DISCARD/IMPORT + TABLESPACE or TRUNCATE TABLE then allow multiple + writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ + < TL_WRITE_CONCURRENT_INSERT. - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) + We especially allow multiple writers if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) + (MySQL does have thd->in_lock_tables TRUE there). */ + + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT + && lock_type <= TL_WRITE) && (!thd->in_lock_tables - || thd->lex->sql_command == SQLCOM_CALL) + || thd->lex->sql_command == SQLCOM_CALL) && !thd->tablespace_op && thd->lex->sql_command != SQLCOM_TRUNCATE - && thd->lex->sql_command != SQLCOM_OPTIMIZE - && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { + && thd->lex->sql_command != SQLCOM_OPTIMIZE + && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { - lock_type = TL_WRITE_ALLOW_WRITE; + lock_type = TL_WRITE_ALLOW_WRITE; } /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... MySQL would use the lock TL_READ_NO_INSERT on t2, and that would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts to t2. Convert the lock to a normal read lock to allow - concurrent inserts to t2. */ + concurrent inserts to t2. + + We especially allow concurrent inserts if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) + (MySQL does have thd->in_lock_tables TRUE there). */ if (lock_type == TL_READ_NO_INSERT && (!thd->in_lock_tables @@ -6898,10 +6911,10 @@ ha_innobase::store_lock( lock_type = TL_READ; } - lock.type = lock_type; - } + lock.type = lock_type; + } - *to++= &lock; + *to++= &lock; return(to); } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index aa8506abe6d..fb93b2abb0e 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -52,7 +52,6 @@ class ha_innobase: public handler THR_LOCK_DATA lock; INNOBASE_SHARE *share; - gptr alloc_ptr; byte* upd_buff; /* buffer used in updates */ byte* key_val_buff; /* buffer used in converting search key values from MySQL format @@ -62,7 +61,6 @@ class ha_innobase: public handler two buffers */ ulong int_table_flags; uint primary_key; - uint last_dup_key; ulong start_of_scan; /* this is set to 1 when we are starting a table scan but have not yet fetched any row, else 0 */ @@ -70,7 +68,6 @@ class ha_innobase: public handler ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, or undefined */ uint num_write_row; /* number of write_row() calls */ - ulong max_supported_row_length(const byte *buf); uint store_key_val_for_row(uint keynr, char* buff, uint buff_len, const byte* record); @@ -199,11 +196,8 @@ class ha_innobase: public handler }; extern struct show_var_st innodb_status_variables[]; -extern uint innobase_init_flags, innobase_lock_type; -extern ulong innobase_cache_size, innobase_fast_shutdown; +extern ulong innobase_fast_shutdown; extern ulong innobase_large_page_size; -extern char *innobase_home, *innobase_tmpdir, *innobase_logdir; -extern long innobase_lock_scan_time; extern long innobase_mirrored_log_groups, innobase_log_files_in_group; extern longlong innobase_buffer_pool_size, innobase_log_file_size; extern long innobase_log_buffer_size; @@ -240,8 +234,6 @@ extern ulong srv_commit_concurrency; extern ulong srv_flush_log_at_trx_commit; } -extern TYPELIB innobase_lock_typelib; - bool innobase_init(void); bool innobase_end(void); bool innobase_flush_logs(void); @@ -311,9 +303,6 @@ int innobase_rollback_by_xid( XID *xid); /* in : X/Open XA Transaction Identification */ -int innobase_xa_end(THD *thd); - - int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, my_off_t end_offset); From a84c7e1c295eeea89a232409d66596df085ef01b Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Wed, 1 Feb 2006 14:46:30 +0100 Subject: [PATCH 16/20] Added new test case for BUG#14533: 'desc tbl' in stored procedure causes error 1142 which is no longer repeatable. (Unclear when this was fixed.) --- mysql-test/r/sp-security.result | 23 ++++++++++++++++++++ mysql-test/t/sp-security.test | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index b223c0cd487..ff729e87f97 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -291,3 +291,26 @@ drop user user1_bug14834@localhost; drop user user2_bug14834@localhost; drop user user3_bug14834@localhost; drop database db_bug14834; +create database db_bug14533; +use db_bug14533; +create table t1 (id int); +create user user_bug14533@localhost identified by ''; +create procedure bug14533_1() +sql security definer +desc db_bug14533.t1; +create procedure bug14533_2() +sql security definer +select * from db_bug14533.t1; +grant execute on procedure db_bug14533.bug14533_1 to user_bug14533@localhost; +grant execute on procedure db_bug14533.bug14533_2 to user_bug14533@localhost; +call db_bug14533.bug14533_1(); +Field Type Null Key Default Extra +id int(11) YES NULL +call db_bug14533.bug14533_2(); +id +desc db_bug14533.t1; +ERROR 42000: SELECT command denied to user 'user_bug14533'@'localhost' for table 't1' +select * from db_bug14533.t1; +ERROR 42000: SELECT command denied to user 'user_bug14533'@'localhost' for table 't1' +drop user user_bug14533@localhost; +drop database db_bug14533; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 223bc09b9fc..90160780618 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -487,4 +487,42 @@ drop user user2_bug14834@localhost; drop user user3_bug14834@localhost; drop database db_bug14834; + +# +# BUG#14533: 'desc tbl' in stored procedure causes error 1142 +# +create database db_bug14533; +use db_bug14533; +create table t1 (id int); +create user user_bug14533@localhost identified by ''; + +create procedure bug14533_1() + sql security definer + desc db_bug14533.t1; + +create procedure bug14533_2() + sql security definer + select * from db_bug14533.t1; + +grant execute on procedure db_bug14533.bug14533_1 to user_bug14533@localhost; +grant execute on procedure db_bug14533.bug14533_2 to user_bug14533@localhost; + +connect (user_bug14533,localhost,user_bug14533,,test); + +# These should work +call db_bug14533.bug14533_1(); +call db_bug14533.bug14533_2(); + +# For reference, these should not work +--error ER_TABLEACCESS_DENIED_ERROR +desc db_bug14533.t1; +--error ER_TABLEACCESS_DENIED_ERROR +select * from db_bug14533.t1; + +# Cleanup +connection default; +disconnect user_bug14533; +drop user user_bug14533@localhost; +drop database db_bug14533; + # End of 5.0 bugs. From 30d14266754a51c36fac2fb403e482bf1f64667d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Wed, 1 Feb 2006 16:00:11 +0100 Subject: [PATCH 17/20] Post-review fix for BUG#15011. Added comments. --- sql/sp_rcontext.cc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 4818ffbbe31..af4e41c29be 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -164,6 +164,33 @@ sp_rcontext::set_return_value(THD *thd, Item *return_value_item) #define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2') #define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2') +/* + Find a handler for the given errno. + This is called from all error message functions (e.g. push_warning, + net_send_error, et al) when a sp_rcontext is in effect. If a handler + is found, no error is sent, and the the SP execution loop will instead + invoke the found handler. + This might be called several times before we get back to the execution + loop, so m_hfound can be >= 0 if a handler has already been found. + (In which case we don't search again - the first found handler will + be used.) + Handlers are pushed on the stack m_handler, with the latest/innermost + one on the top; we then search for matching handlers from the top and + down. + We search through all the handlers, looking for the most specific one + (sql_errno more specific than sqlstate more specific than the rest). + Note that mysql error code handlers is a MySQL extension, not part of + the standard. + + SYNOPSIS + sql_errno The error code + level Warning level + + RETURN + 1 if a handler was found, m_hfound is set to its index (>= 0) + 0 if not found, m_hfound is -1 +*/ + bool sp_rcontext::find_handler(uint sql_errno, MYSQL_ERROR::enum_warning_level level) @@ -174,11 +201,13 @@ sp_rcontext::find_handler(uint sql_errno, const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); int i= m_hcount, found= -1; + /* Search handlers from the latest (innermost) to the oldest (outermost) */ while (i--) { sp_cond_type_t *cond= m_handler[i].cond; int j= m_ihsp; + /* Check active handlers, to avoid invoking one recursively */ while (j--) if (m_in_handler[j] == m_handler[i].handler) break; From 17fe2512016311e03d65a3003259b7952040ef4d Mon Sep 17 00:00:00 2001 From: "gunnar@mysql.com." <> Date: Thu, 2 Feb 2006 21:27:23 +0100 Subject: [PATCH 18/20] item_timefunc.cc: manual adding the fix for bug#15828 which did not automerge --- sql/item_timefunc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 61449d3c671..17f25b49bcc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3023,9 +3023,9 @@ void Item_func_str_to_date::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - if ((const_item= args[1]->const_item())) + format= args[1]->val_str(&format_str); + if (!args[1]->null_value && (const_item= args[1]->const_item())) { - format= args[1]->val_str(&format_str); cached_format_type= get_date_time_result_type(format->ptr(), format->length()); switch (cached_format_type) { From 790c9a05f4de3d6af5898983efd1760660c11aef Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 8 Feb 2006 15:03:09 +0300 Subject: [PATCH 19/20] Post merge-fixes. Apply a patch by Jonas for NDB diskdata. --- mysql-test/r/sp-code.result | 4 ++-- storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index c9fe170dda6..bb0adae6bab 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -155,11 +155,11 @@ Pos Instruction 0 stmt 9 "drop temporary table if exists sudoku..." 1 stmt 1 "create temporary table sudoku_work ( ..." 2 stmt 1 "create temporary table sudoku_schedul..." -3 stmt 95 "call sudoku_init(" +3 stmt 94 "call sudoku_init(" 4 jump_if_not 7(8) p_naive@0 5 stmt 4 "update sudoku_work set cnt = 0 where ..." 6 jump 8 -7 stmt 95 "call sudoku_count(" +7 stmt 94 "call sudoku_count(" 8 stmt 6 "insert into sudoku_schedule (row,col)..." 9 set v_scounter@2 0 10 set v_i@3 1 diff --git a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index 41a705fea2d..e0324c2c8ea 100644 --- a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -431,6 +431,7 @@ void AsyncFile::openReq(Request* request) m_fs.EXECUTE_DIRECT(block, GSN_FSWRITEREQ, signal, FsReadWriteReq::FixedLength + 1); + retry: Uint32 size = request->par.open.page_size; char* buf = (char*)m_page_ptr.p; while(size > 0){ @@ -457,7 +458,7 @@ void AsyncFile::openReq(Request* request) close(theFd); theFd = ::open(theFileName.c_str(), new_flags, mode); if (theFd != -1) - continue; + goto retry; } #endif close(theFd); From 60af944d39b2d2800505c6e02f53f45743d202d5 Mon Sep 17 00:00:00 2001 From: "reggie@big_geek." <> Date: Wed, 8 Feb 2006 11:18:17 -0600 Subject: [PATCH 20/20] cmakefiles cleanup --- win/cmakefiles/base | 7 ++++++ win/cmakefiles/client | 10 +++++---- win/cmakefiles/extra | 12 ++++++++++ win/cmakefiles/sql | 51 ++++++++++++++++++++++++------------------- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/win/cmakefiles/base b/win/cmakefiles/base index 6cc11a1e174..f8ac9969a26 100644 --- a/win/cmakefiles/base +++ b/win/cmakefiles/base @@ -6,6 +6,13 @@ EXEC_PROGRAM(cscript.exe win ARGS config-version.js OUT_VARIABLE out) SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -D DBUG_OFF") SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D DBUG_OFF") +IF(CMAKE_GENERATOR MATCHES "Visual Studio 8") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /wd4996") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /wd4996") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /wd4996") + SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /wd4996") +ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 8") + IF(CMAKE_GENERATOR MATCHES "Visual Studio 7" OR CMAKE_GENERATOR MATCHES "Visual Studio 8") # replace /MDd with /MTd STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG_INIT ${CMAKE_CXX_FLAGS_DEBUG_INIT}) diff --git a/win/cmakefiles/client b/win/cmakefiles/client index 711a5bf499b..7c0c6f2400b 100644 --- a/win/cmakefiles/client +++ b/win/cmakefiles/client @@ -2,7 +2,10 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") ADD_DEFINITIONS(-DUSE_TLS -DMYSQL_CLIENT) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib ${CMAKE_SOURCE_DIR}/extra/yassl/include ${CMAKE_SOURCE_DIR}/libmysql) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/extra/yassl/include + ${CMAKE_SOURCE_DIR}/libmysql) ADD_LIBRARY(mysqlclient ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../strings/bmove_upp.c ../mysys/charset-def.c ../mysys/charset.c @@ -38,10 +41,9 @@ ADD_LIBRARY(mysqlclient ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c - ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c - ${PROJECT_SOURCE_DIR}/include/mysql_version.h) + ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c) -ADD_DEPENDENCIES(mysqlclient comp_err) +ADD_DEPENDENCIES(mysqlclient GenError) ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc) LINK_DIRECTORIES(${MYSQL_BINARY_DIR}/mysys ${MYSQL_BINARY_DIR}/zlib) TARGET_LINK_LIBRARIES(mysql mysqlclient mysys yassl zlib dbug yassl taocrypt wsock32) diff --git a/win/cmakefiles/extra b/win/cmakefiles/extra index 5fedfcac2b9..40327eac0ad 100644 --- a/win/cmakefiles/extra +++ b/win/cmakefiles/extra @@ -6,4 +6,16 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_EXECUTABLE(comp_err comp_err.c) TARGET_LINK_LIBRARIES(comp_err dbug mysys strings wsock32) +GET_TARGET_PROPERTY(COMP_ERR_EXE comp_err LOCATION) + +ADD_CUSTOM_TARGET(GenError + ${COMP_ERR_EXE} --charset=${PROJECT_SOURCE_DIR}/sql/share/charsets + --out-dir=${PROJECT_SOURCE_DIR}/sql/share/ + --header_file=${PROJECT_SOURCE_DIR}/include/mysqld_error.h + --name_file=${PROJECT_SOURCE_DIR}/include/mysqld_ername.h + --state_file=${PROJECT_SOURCE_DIR}/include/sql_state.h + --in_file=${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt + DEPENDS comp_err ${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt) + + diff --git a/win/cmakefiles/sql b/win/cmakefiles/sql index 8361038bf4f..ee53436a1a6 100644 --- a/win/cmakefiles/sql +++ b/win/cmakefiles/sql @@ -1,7 +1,11 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR") -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/extra/yassl/include ${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex ${CMAKE_SOURCE_DIR}/zlib) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/extra/yassl/include + ${CMAKE_SOURCE_DIR}/sql + ${CMAKE_SOURCE_DIR}/regex + ${CMAKE_SOURCE_DIR}/zlib) SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/sql/message.rc ${CMAKE_SOURCE_DIR}/sql/message.h @@ -46,6 +50,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc discover. ${PROJECT_SOURCE_DIR}/sql/handlerton.cc ${PROJECT_SOURCE_DIR}/sql/lex_hash.h) TARGET_LINK_LIBRARIES(mysqld heap myisam myisammrg innobase mysys yassl zlib dbug yassl taocrypt strings vio regex wsock32) +ADD_DEPENDENCIES(mysqld GenError) # Sql Parser custom command ADD_CUSTOM_COMMAND( @@ -82,30 +87,30 @@ ADD_CUSTOM_COMMAND( DEPENDS ${PROJECT_SOURCE_DIR}/sql/handlerton.cc.in) # Error file -GET_TARGET_PROPERTY(COMP_ERR_EXE comp_err LOCATION) -ADD_CUSTOM_COMMAND( - SOURCE ${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt - OUTPUT ${PROJECT_SOURCE_DIR}/include/mysqld_error.h - COMMAND ${COMP_ERR_EXE} - ARGS --charset=${PROJECT_SOURCE_DIR}/sql/share/charsets - --out-dir=${PROJECT_SOURCE_DIR}/sql/share/ - --header_file=${PROJECT_SOURCE_DIR}/include/mysqld_error.h - --name_file=${PROJECT_SOURCE_DIR}/include/mysqld_ername.h - --state_file=${PROJECT_SOURCE_DIR}/include/sql_state.h - --in_file=${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt - DEPENDS ${COMP_ERR_EXE} share/errmsg.txt) +#GET_TARGET_PROPERTY(COMP_ERR_EXE comp_err LOCATION) +#ADD_CUSTOM_COMMAND( + #SOURCE ${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt + #OUTPUT ${PROJECT_SOURCE_DIR}/include/mysqld_error.h + #COMMAND ${COMP_ERR_EXE} + #ARGS --charset=${PROJECT_SOURCE_DIR}/sql/share/charsets + # --out-dir=${PROJECT_SOURCE_DIR}/sql/share/ +## --header_file=${PROJECT_SOURCE_DIR}/include/mysqld_error.h +# --name_file=${PROJECT_SOURCE_DIR}/include/mysqld_ername.h +# --state_file=${PROJECT_SOURCE_DIR}/include/sql_state.h + # --in_file=${PROJECT_SOURCE_DIR}/sql/share/errmsg.txt + # DEPENDS ${COMP_ERR_EXE} share/errmsg.txt) -ADD_CUSTOM_COMMAND( - OUTPUT ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h - COMMAND echo - DEPENDS ${PROJECT_SOURCE_DIR}/include/mysqld_error.h -) +#ADD_CUSTOM_COMMAND( +# OUTPUT ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h +# COMMAND echo +# DEPENDS ${PROJECT_SOURCE_DIR}/include/mysqld_error.h +#) -ADD_CUSTOM_COMMAND( - OUTPUT ${PROJECT_SOURCE_DIR}/include/sql_state.h - COMMAND echo - DEPENDS ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h -) +#ADD_CUSTOM_COMMAND( +# OUTPUT ${PROJECT_SOURCE_DIR}/include/sql_state.h +# COMMAND echo +# DEPENDS ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h +#) # Gen_lex_hash