From ce5a3fcca888bc9233f908da878710d3b81c8a70 Mon Sep 17 00:00:00 2001 From: "malff/marcsql@weblab.(none)" <> Date: Fri, 17 Nov 2006 12:14:29 -0700 Subject: [PATCH 01/27] Bug#19194 (Right recursion in parser for CASE causes excessive stack usage, limitation) Note to the reviewer ==================== Warning: reviewing this patch is somewhat involved. Due to the nature of several issues all affecting the same area, fixing separately each issue is not practical, since each fix can not be implemented and tested independently. In particular, the issues with - rule recursion - nested case statements - forward jump resolution (backpatch list) are tightly coupled (see below). Definitions =========== The expression CASE expr WHEN expr THEN expr WHEN expr THEN expr ... END is a "Simple Case Expression". The expression CASE WHEN expr THEN expr WHEN expr THEN expr ... END is a "Searched Case Expression". The statement CASE expr WHEN expr THEN stmts WHEN expr THEN stmts ... END CASE is a "Simple Case Statement". The statement CASE WHEN expr THEN stmts WHEN expr THEN stmts ... END CASE is a "Searched Case Statement". A "Left Recursive" rule is like list: element | list element ; A "Right Recursive" rule is like list: element | element list ; Left and right recursion produces the same language, the difference only affects the *order* in which the text is parsed. In a descendant parser (usually written manually), right recursion works very well, and is typically implemented with a while loop. In an ascendant parser (yacc/bison) left recursion works very well, and is implemented naturally by the parser stack. In both cases, using the wrong type or recursion is very bad and should be avoided, as it causes technical issues with the parser implementation. Before this change ================== The "Simple Case Expression" and "Searched Case Expression" were both implemented by the "when_list" and "when_list2" rules, which are left recursive (ok). These rules, however, used lex->when_list instead of using the parser stack, which is more complex that necessary, and potentially dangerous because of other rules using THD::reset_lex. The "Simple Case Statement" and "Searched Case Statements" were implemented by the "sp_case", "sp_whens" and in part by "sp_proc_stmt" rules. Both cases were right recursive (bad). The grammar involved was convoluted, and is assumed to be the results of tweaks to get the code generation to work, but is not what someone would naturally write. In addition, using a common rule for both "Simple" and "Searched" case statements was implemented with sp_head::m_flags |= IN_SIMPLE_CASE, which is a flag and not a stack, and therefore does not take into account *nested* case statements. This leads to incorrect generated code, and either a server crash or an incorrect result. With regards to the backpatch mechanism, a *different* backpatch list was created for each jump from "WHEN expr THEN stmt" to "END CASE", which relied on the grammar to be right recursive. This is a mis-use of the backpatch list, since this list can resolve multiple references to the same target at once. The optimizer algorithm used to detect dead code in the "assembly" SQL instructions, implemented by sp_head::opt_mark(uint ip), was recursive in some cases (a conditional jump pointing forward to another conditional jump). In case of specially crafted code, like - a long list of "IF expr THEN stmt END IF" - a long CASE statement this would actually cause a server crash with a stack overflow. In general, having a stack that grows proportionally with user data (the SQL code given by the client in a CREATE PROCEDURE) is to be avoided. In debug builds only, creating a SP / SF / Trigger which had a significant amount of code would spend --literally-- several minutes in sp_head::create, because of the debug code involved with DBUG_PRINT("info", ("Code %s ... There are several issues with this code: - in a CASE with 5 000 WHEN, there are 15 000 instructions generated, which create a sting representation of the code which is 500 000 bytes long, - using a String instead of an io stream causes performances to degrade to a total server freeze, as time is spent doing realloc of a buffer always too short, - Printing a 500 000 long string in the debug log is too verbose, - Generating this string even when DBUG_PRINT is off is useless, - Having code that potentially can affect the server behavior, used with #ifdef / #endif is useful in some cases, but is also a bad practice. After this change ================= "Case Expressions" (both simple and searched) have been simplified to not use LEX::when_list, which has been removed. Considering all the issues affecting case statements, the grammar for these has been totally re written. The existing actions, used to generate "assembly" sp_inst* code, have been preserved but moved in the new grammar, with the following changes: a) Bison rules are no longer shared between "Simple" and "Searched" case statements, because a stack instead of a flag is required to handle them. Nested statements are handled naturally by the parser stack, which by definition uses the correct rule in the correct context. Nested statements of the opposite type (simple vs searched) works correctly. The flag sp_head::IN_SIMPLE_CASE is no longer used. This is a step towards resolution of WL#2999, which correctly identified that temporary parsing flags do not belong to sp_head. The code in the action is shared by mean of the case_stmt_action_xxx() helpers. b) The backpatch mechanism, used to resolve forward jumps in the generated code, has been changed to: - create a label for the instruction following 'END CASE', - register each jump at the end of a "WHEN expr THEN stmt" in a *unique* backpatch list associated with the 'END CASE' label - resolve all the forward jumps for this label at once. In addition, the code involving backpatch has been commented, so that a reader can now understand by reading matching "Registering" and "Resolving" comments how the forward jumps are resolved and what target they resolve to, as this is far from evident when reading the code alone. The implementation of sp_head::opt_mark() has been revised to avoid recursive calls from jump instructions, and instead add the jump location to the list of paths to explore during the flow analysis of the instruction graph, with a call to sp_head::add_mark_lead(). In addition, the flow analysis will stop if an instruction has already been marked as reachable, which the previous code failed to do in the recursive case. sp_head::opt_mark() is now private, to prevent new calls to this method from being introduced. The debug code present in sp_head::create() has been removed. Considering that SHOW PROCEDURE CODE is also available in debug builds, and can be used anytime regardless of the trace level, as opposed to "CREATE PROCEDURE" time and only if the trace was on, removing the code actually makes debugging easier (usable trace). Tests have been written to cover the parser overflow (big CASE), and to cover nested CASE statements. --- mysql-test/r/sp-code.result | 415 +++++++++++++++++++++++++++++ mysql-test/r/sp_stress_case.result | 42 +++ mysql-test/t/sp-code.test | 235 ++++++++++++++++ mysql-test/t/sp_stress_case.sh | 68 +++++ mysql-test/t/sp_stress_case.test | 35 +++ sql/sp_head.cc | 100 ++++--- sql/sp_head.h | 39 ++- sql/sql_lex.cc | 1 - sql/sql_lex.h | 1 - sql/sql_yacc.yy | 373 ++++++++++++++++++-------- 10 files changed, 1138 insertions(+), 171 deletions(-) create mode 100644 mysql-test/r/sp_stress_case.result create mode 100755 mysql-test/t/sp_stress_case.sh create mode 100644 mysql-test/t/sp_stress_case.test diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index 4ae38861d29..0b0ad802b54 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -199,6 +199,421 @@ Pos Instruction 44 jump 14 45 stmt 9 "drop temporary table sudoku_work, sud..." drop procedure sudoku_solve; +DROP PROCEDURE IF EXISTS proc_19194_simple; +DROP PROCEDURE IF EXISTS proc_19194_searched; +DROP PROCEDURE IF EXISTS proc_19194_nested_1; +DROP PROCEDURE IF EXISTS proc_19194_nested_2; +DROP PROCEDURE IF EXISTS proc_19194_nested_3; +DROP PROCEDURE IF EXISTS proc_19194_nested_4; +CREATE PROCEDURE proc_19194_simple(i int) +BEGIN +DECLARE str CHAR(10); +CASE i +WHEN 1 THEN SET str="1"; +WHEN 2 THEN SET str="2"; +WHEN 3 THEN SET str="3"; +ELSE SET str="unknown"; +END CASE; +SELECT str; +END| +CREATE PROCEDURE proc_19194_searched(i int) +BEGIN +DECLARE str CHAR(10); +CASE +WHEN i=1 THEN SET str="1"; +WHEN i=2 THEN SET str="2"; +WHEN i=3 THEN SET str="3"; +ELSE SET str="unknown"; +END CASE; +SELECT str; +END| +CREATE PROCEDURE proc_19194_nested_1(i int, j int) +BEGIN +DECLARE str_i CHAR(10); +DECLARE str_j CHAR(10); +CASE i +WHEN 10 THEN SET str_i="10"; +WHEN 20 THEN +BEGIN +set str_i="20"; +CASE +WHEN j=1 THEN SET str_j="1"; +WHEN j=2 THEN SET str_j="2"; +WHEN j=3 THEN SET str_j="3"; +ELSE SET str_j="unknown"; +END CASE; +select "i was 20"; +END; +WHEN 30 THEN SET str_i="30"; +WHEN 40 THEN SET str_i="40"; +ELSE SET str_i="unknown"; +END CASE; +SELECT str_i, str_j; +END| +CREATE PROCEDURE proc_19194_nested_2(i int, j int) +BEGIN +DECLARE str_i CHAR(10); +DECLARE str_j CHAR(10); +CASE +WHEN i=10 THEN SET str_i="10"; +WHEN i=20 THEN +BEGIN +set str_i="20"; +CASE j +WHEN 1 THEN SET str_j="1"; +WHEN 2 THEN SET str_j="2"; +WHEN 3 THEN SET str_j="3"; +ELSE SET str_j="unknown"; +END CASE; +select "i was 20"; +END; +WHEN i=30 THEN SET str_i="30"; +WHEN i=40 THEN SET str_i="40"; +ELSE SET str_i="unknown"; +END CASE; +SELECT str_i, str_j; +END| +CREATE PROCEDURE proc_19194_nested_3(i int, j int) +BEGIN +DECLARE str_i CHAR(10); +DECLARE str_j CHAR(10); +CASE i +WHEN 10 THEN SET str_i="10"; +WHEN 20 THEN +BEGIN +set str_i="20"; +CASE j +WHEN 1 THEN SET str_j="1"; +WHEN 2 THEN SET str_j="2"; +WHEN 3 THEN SET str_j="3"; +ELSE SET str_j="unknown"; +END CASE; +select "i was 20"; +END; +WHEN 30 THEN SET str_i="30"; +WHEN 40 THEN SET str_i="40"; +ELSE SET str_i="unknown"; +END CASE; +SELECT str_i, str_j; +END| +CREATE PROCEDURE proc_19194_nested_4(i int, j int) +BEGIN +DECLARE str_i CHAR(10); +DECLARE str_j CHAR(10); +CASE +WHEN i=10 THEN SET str_i="10"; +WHEN i=20 THEN +BEGIN +set str_i="20"; +CASE +WHEN j=1 THEN SET str_j="1"; +WHEN j=2 THEN SET str_j="2"; +WHEN j=3 THEN SET str_j="3"; +ELSE SET str_j="unknown"; +END CASE; +select "i was 20"; +END; +WHEN i=30 THEN SET str_i="30"; +WHEN i=40 THEN SET str_i="40"; +ELSE SET str_i="unknown"; +END CASE; +SELECT str_i, str_j; +END| +SHOW PROCEDURE CODE proc_19194_simple; +Pos Instruction +0 set str@1 NULL +1 set_case_expr (12) 0 i@0 +2 jump_if_not 5(12) (case_expr@0 = 1) +3 set str@1 _latin1'1' +4 jump 12 +5 jump_if_not 8(12) (case_expr@0 = 2) +6 set str@1 _latin1'2' +7 jump 12 +8 jump_if_not 11(12) (case_expr@0 = 3) +9 set str@1 _latin1'3' +10 jump 12 +11 set str@1 _latin1'unknown' +12 stmt 0 "SELECT str" +SHOW PROCEDURE CODE proc_19194_searched; +Pos Instruction +0 set str@1 NULL +1 jump_if_not 4(11) (i@0 = 1) +2 set str@1 _latin1'1' +3 jump 11 +4 jump_if_not 7(11) (i@0 = 2) +5 set str@1 _latin1'2' +6 jump 11 +7 jump_if_not 10(11) (i@0 = 3) +8 set str@1 _latin1'3' +9 jump 11 +10 set str@1 _latin1'unknown' +11 stmt 0 "SELECT str" +SHOW PROCEDURE CODE proc_19194_nested_1; +Pos Instruction +0 set str_i@2 NULL +1 set str_j@3 NULL +2 set_case_expr (27) 0 i@0 +3 jump_if_not 6(27) (case_expr@0 = 10) +4 set str_i@2 _latin1'10' +5 jump 27 +6 jump_if_not 20(27) (case_expr@0 = 20) +7 set str_i@2 _latin1'20' +8 jump_if_not 11(18) (j@1 = 1) +9 set str_j@3 _latin1'1' +10 jump 18 +11 jump_if_not 14(18) (j@1 = 2) +12 set str_j@3 _latin1'2' +13 jump 18 +14 jump_if_not 17(18) (j@1 = 3) +15 set str_j@3 _latin1'3' +16 jump 18 +17 set str_j@3 _latin1'unknown' +18 stmt 0 "select "i was 20"" +19 jump 27 +20 jump_if_not 23(27) (case_expr@0 = 30) +21 set str_i@2 _latin1'30' +22 jump 27 +23 jump_if_not 26(27) (case_expr@0 = 40) +24 set str_i@2 _latin1'40' +25 jump 27 +26 set str_i@2 _latin1'unknown' +27 stmt 0 "SELECT str_i, str_j" +SHOW PROCEDURE CODE proc_19194_nested_2; +Pos Instruction +0 set str_i@2 NULL +1 set str_j@3 NULL +2 jump_if_not 5(27) (i@0 = 10) +3 set str_i@2 _latin1'10' +4 jump 27 +5 jump_if_not 20(27) (i@0 = 20) +6 set str_i@2 _latin1'20' +7 set_case_expr (18) 0 j@1 +8 jump_if_not 11(18) (case_expr@0 = 1) +9 set str_j@3 _latin1'1' +10 jump 18 +11 jump_if_not 14(18) (case_expr@0 = 2) +12 set str_j@3 _latin1'2' +13 jump 18 +14 jump_if_not 17(18) (case_expr@0 = 3) +15 set str_j@3 _latin1'3' +16 jump 18 +17 set str_j@3 _latin1'unknown' +18 stmt 0 "select "i was 20"" +19 jump 27 +20 jump_if_not 23(27) (i@0 = 30) +21 set str_i@2 _latin1'30' +22 jump 27 +23 jump_if_not 26(27) (i@0 = 40) +24 set str_i@2 _latin1'40' +25 jump 27 +26 set str_i@2 _latin1'unknown' +27 stmt 0 "SELECT str_i, str_j" +SHOW PROCEDURE CODE proc_19194_nested_3; +Pos Instruction +0 set str_i@2 NULL +1 set str_j@3 NULL +2 set_case_expr (28) 0 i@0 +3 jump_if_not 6(28) (case_expr@0 = 10) +4 set str_i@2 _latin1'10' +5 jump 28 +6 jump_if_not 21(28) (case_expr@0 = 20) +7 set str_i@2 _latin1'20' +8 set_case_expr (19) 1 j@1 +9 jump_if_not 12(19) (case_expr@1 = 1) +10 set str_j@3 _latin1'1' +11 jump 19 +12 jump_if_not 15(19) (case_expr@1 = 2) +13 set str_j@3 _latin1'2' +14 jump 19 +15 jump_if_not 18(19) (case_expr@1 = 3) +16 set str_j@3 _latin1'3' +17 jump 19 +18 set str_j@3 _latin1'unknown' +19 stmt 0 "select "i was 20"" +20 jump 28 +21 jump_if_not 24(28) (case_expr@0 = 30) +22 set str_i@2 _latin1'30' +23 jump 28 +24 jump_if_not 27(28) (case_expr@0 = 40) +25 set str_i@2 _latin1'40' +26 jump 28 +27 set str_i@2 _latin1'unknown' +28 stmt 0 "SELECT str_i, str_j" +SHOW PROCEDURE CODE proc_19194_nested_4; +Pos Instruction +0 set str_i@2 NULL +1 set str_j@3 NULL +2 jump_if_not 5(26) (i@0 = 10) +3 set str_i@2 _latin1'10' +4 jump 26 +5 jump_if_not 19(26) (i@0 = 20) +6 set str_i@2 _latin1'20' +7 jump_if_not 10(17) (j@1 = 1) +8 set str_j@3 _latin1'1' +9 jump 17 +10 jump_if_not 13(17) (j@1 = 2) +11 set str_j@3 _latin1'2' +12 jump 17 +13 jump_if_not 16(17) (j@1 = 3) +14 set str_j@3 _latin1'3' +15 jump 17 +16 set str_j@3 _latin1'unknown' +17 stmt 0 "select "i was 20"" +18 jump 26 +19 jump_if_not 22(26) (i@0 = 30) +20 set str_i@2 _latin1'30' +21 jump 26 +22 jump_if_not 25(26) (i@0 = 40) +23 set str_i@2 _latin1'40' +24 jump 26 +25 set str_i@2 _latin1'unknown' +26 stmt 0 "SELECT str_i, str_j" +CALL proc_19194_nested_1(10, 1); +str_i str_j +10 NULL +CALL proc_19194_nested_1(25, 1); +str_i str_j +unknown NULL +CALL proc_19194_nested_1(20, 1); +i was 20 +i was 20 +str_i str_j +20 1 +CALL proc_19194_nested_1(20, 2); +i was 20 +i was 20 +str_i str_j +20 2 +CALL proc_19194_nested_1(20, 3); +i was 20 +i was 20 +str_i str_j +20 3 +CALL proc_19194_nested_1(20, 4); +i was 20 +i was 20 +str_i str_j +20 unknown +CALL proc_19194_nested_1(30, 1); +str_i str_j +30 NULL +CALL proc_19194_nested_1(40, 1); +str_i str_j +40 NULL +CALL proc_19194_nested_1(0, 0); +str_i str_j +unknown NULL +CALL proc_19194_nested_2(10, 1); +str_i str_j +10 NULL +CALL proc_19194_nested_2(25, 1); +str_i str_j +unknown NULL +CALL proc_19194_nested_2(20, 1); +i was 20 +i was 20 +str_i str_j +20 1 +CALL proc_19194_nested_2(20, 2); +i was 20 +i was 20 +str_i str_j +20 2 +CALL proc_19194_nested_2(20, 3); +i was 20 +i was 20 +str_i str_j +20 3 +CALL proc_19194_nested_2(20, 4); +i was 20 +i was 20 +str_i str_j +20 unknown +CALL proc_19194_nested_2(30, 1); +str_i str_j +30 NULL +CALL proc_19194_nested_2(40, 1); +str_i str_j +40 NULL +CALL proc_19194_nested_2(0, 0); +str_i str_j +unknown NULL +CALL proc_19194_nested_3(10, 1); +str_i str_j +10 NULL +CALL proc_19194_nested_3(25, 1); +str_i str_j +unknown NULL +CALL proc_19194_nested_3(20, 1); +i was 20 +i was 20 +str_i str_j +20 1 +CALL proc_19194_nested_3(20, 2); +i was 20 +i was 20 +str_i str_j +20 2 +CALL proc_19194_nested_3(20, 3); +i was 20 +i was 20 +str_i str_j +20 3 +CALL proc_19194_nested_3(20, 4); +i was 20 +i was 20 +str_i str_j +20 unknown +CALL proc_19194_nested_3(30, 1); +str_i str_j +30 NULL +CALL proc_19194_nested_3(40, 1); +str_i str_j +40 NULL +CALL proc_19194_nested_3(0, 0); +str_i str_j +unknown NULL +CALL proc_19194_nested_4(10, 1); +str_i str_j +10 NULL +CALL proc_19194_nested_4(25, 1); +str_i str_j +unknown NULL +CALL proc_19194_nested_4(20, 1); +i was 20 +i was 20 +str_i str_j +20 1 +CALL proc_19194_nested_4(20, 2); +i was 20 +i was 20 +str_i str_j +20 2 +CALL proc_19194_nested_4(20, 3); +i was 20 +i was 20 +str_i str_j +20 3 +CALL proc_19194_nested_4(20, 4); +i was 20 +i was 20 +str_i str_j +20 unknown +CALL proc_19194_nested_4(30, 1); +str_i str_j +30 NULL +CALL proc_19194_nested_4(40, 1); +str_i str_j +40 NULL +CALL proc_19194_nested_4(0, 0); +str_i str_j +unknown NULL +DROP PROCEDURE proc_19194_simple; +DROP PROCEDURE proc_19194_searched; +DROP PROCEDURE proc_19194_nested_1; +DROP PROCEDURE proc_19194_nested_2; +DROP PROCEDURE proc_19194_nested_3; +DROP PROCEDURE proc_19194_nested_4; DROP PROCEDURE IF EXISTS p1; CREATE PROCEDURE p1() CREATE INDEX idx ON t1 (c1); SHOW PROCEDURE CODE p1; diff --git a/mysql-test/r/sp_stress_case.result b/mysql-test/r/sp_stress_case.result new file mode 100644 index 00000000000..b85fb41d0bf --- /dev/null +++ b/mysql-test/r/sp_stress_case.result @@ -0,0 +1,42 @@ +DROP PROCEDURE IF EXISTS bug_19194_a; +DROP PROCEDURE IF EXISTS bug_19194_b; +'Silently creating PROCEDURE bug_19194_a' +'Silently creating PROCEDURE bug_19194_b' +CALL bug_19194_a(1); +str +1 +CALL bug_19194_a(2); +str +2 +CALL bug_19194_a(1000); +str +1000 +CALL bug_19194_a(4998); +str +4998 +CALL bug_19194_a(4999); +str +4999 +CALL bug_19194_a(9999); +str +unknown +CALL bug_19194_b(1); +str +1 +CALL bug_19194_b(2); +str +2 +CALL bug_19194_b(1000); +str +1000 +CALL bug_19194_b(4998); +str +4998 +CALL bug_19194_b(4999); +str +4999 +CALL bug_19194_b(9999); +str +unknown +DROP PROCEDURE bug_19194_a; +DROP PROCEDURE bug_19194_b; diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index 72efa831059..97bc29fcad2 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -191,6 +191,241 @@ show procedure code sudoku_solve; drop procedure sudoku_solve; +# +# Bug#19194 (Right recursion in parser for CASE causes excessive stack +# usage, limitation) +# This bug also exposed a flaw in the generated code with nested case +# statements +# + +--disable_warnings +DROP PROCEDURE IF EXISTS proc_19194_simple; +DROP PROCEDURE IF EXISTS proc_19194_searched; +DROP PROCEDURE IF EXISTS proc_19194_nested_1; +DROP PROCEDURE IF EXISTS proc_19194_nested_2; +DROP PROCEDURE IF EXISTS proc_19194_nested_3; +DROP PROCEDURE IF EXISTS proc_19194_nested_4; +--enable_warnings + +delimiter |; + +CREATE PROCEDURE proc_19194_simple(i int) +BEGIN + DECLARE str CHAR(10); + + CASE i + WHEN 1 THEN SET str="1"; + WHEN 2 THEN SET str="2"; + WHEN 3 THEN SET str="3"; + ELSE SET str="unknown"; + END CASE; + + SELECT str; +END| + +CREATE PROCEDURE proc_19194_searched(i int) +BEGIN + DECLARE str CHAR(10); + + CASE + WHEN i=1 THEN SET str="1"; + WHEN i=2 THEN SET str="2"; + WHEN i=3 THEN SET str="3"; + ELSE SET str="unknown"; + END CASE; + + SELECT str; +END| + +# Outer SIMPLE case, inner SEARCHED case +CREATE PROCEDURE proc_19194_nested_1(i int, j int) +BEGIN + DECLARE str_i CHAR(10); + DECLARE str_j CHAR(10); + + CASE i + WHEN 10 THEN SET str_i="10"; + WHEN 20 THEN + BEGIN + set str_i="20"; + CASE + WHEN j=1 THEN SET str_j="1"; + WHEN j=2 THEN SET str_j="2"; + WHEN j=3 THEN SET str_j="3"; + ELSE SET str_j="unknown"; + END CASE; + select "i was 20"; + END; + WHEN 30 THEN SET str_i="30"; + WHEN 40 THEN SET str_i="40"; + ELSE SET str_i="unknown"; + END CASE; + + SELECT str_i, str_j; +END| + +# Outer SEARCHED case, inner SIMPLE case +CREATE PROCEDURE proc_19194_nested_2(i int, j int) +BEGIN + DECLARE str_i CHAR(10); + DECLARE str_j CHAR(10); + + CASE + WHEN i=10 THEN SET str_i="10"; + WHEN i=20 THEN + BEGIN + set str_i="20"; + CASE j + WHEN 1 THEN SET str_j="1"; + WHEN 2 THEN SET str_j="2"; + WHEN 3 THEN SET str_j="3"; + ELSE SET str_j="unknown"; + END CASE; + select "i was 20"; + END; + WHEN i=30 THEN SET str_i="30"; + WHEN i=40 THEN SET str_i="40"; + ELSE SET str_i="unknown"; + END CASE; + + SELECT str_i, str_j; +END| + +# Outer SIMPLE case, inner SIMPLE case +CREATE PROCEDURE proc_19194_nested_3(i int, j int) +BEGIN + DECLARE str_i CHAR(10); + DECLARE str_j CHAR(10); + + CASE i + WHEN 10 THEN SET str_i="10"; + WHEN 20 THEN + BEGIN + set str_i="20"; + CASE j + WHEN 1 THEN SET str_j="1"; + WHEN 2 THEN SET str_j="2"; + WHEN 3 THEN SET str_j="3"; + ELSE SET str_j="unknown"; + END CASE; + select "i was 20"; + END; + WHEN 30 THEN SET str_i="30"; + WHEN 40 THEN SET str_i="40"; + ELSE SET str_i="unknown"; + END CASE; + + SELECT str_i, str_j; +END| + +# Outer SEARCHED case, inner SEARCHED case +CREATE PROCEDURE proc_19194_nested_4(i int, j int) +BEGIN + DECLARE str_i CHAR(10); + DECLARE str_j CHAR(10); + + CASE + WHEN i=10 THEN SET str_i="10"; + WHEN i=20 THEN + BEGIN + set str_i="20"; + CASE + WHEN j=1 THEN SET str_j="1"; + WHEN j=2 THEN SET str_j="2"; + WHEN j=3 THEN SET str_j="3"; + ELSE SET str_j="unknown"; + END CASE; + select "i was 20"; + END; + WHEN i=30 THEN SET str_i="30"; + WHEN i=40 THEN SET str_i="40"; + ELSE SET str_i="unknown"; + END CASE; + + SELECT str_i, str_j; +END| + +delimiter ;| + +SHOW PROCEDURE CODE proc_19194_simple; +SHOW PROCEDURE CODE proc_19194_searched; +SHOW PROCEDURE CODE proc_19194_nested_1; +SHOW PROCEDURE CODE proc_19194_nested_2; +SHOW PROCEDURE CODE proc_19194_nested_3; +SHOW PROCEDURE CODE proc_19194_nested_4; + +CALL proc_19194_nested_1(10, 1); + +# +# Before 19194, the generated code was: +# 20 jump_if_not 23(27) 30 +# 21 set str_i@2 _latin1'30' +# As opposed to the expected: +# 20 jump_if_not 23(27) (case_expr@0 = 30) +# 21 set str_i@2 _latin1'30' +# +# and as a result, this call returned "30", +# because the expression 30 is always true, +# masking the case 40, case 0 and the else. +# +CALL proc_19194_nested_1(25, 1); + +CALL proc_19194_nested_1(20, 1); +CALL proc_19194_nested_1(20, 2); +CALL proc_19194_nested_1(20, 3); +CALL proc_19194_nested_1(20, 4); +CALL proc_19194_nested_1(30, 1); +CALL proc_19194_nested_1(40, 1); +CALL proc_19194_nested_1(0, 0); + +CALL proc_19194_nested_2(10, 1); + +# +# Before 19194, the generated code was: +# 20 jump_if_not 23(27) (case_expr@0 = (i@0 = 30)) +# 21 set str_i@2 _latin1'30' +# As opposed to the expected: +# 20 jump_if_not 23(27) (i@0 = 30) +# 21 set str_i@2 _latin1'30' +# and as a result, this call crashed the server, because there is no +# such variable as "case_expr@0". +# +CALL proc_19194_nested_2(25, 1); + +CALL proc_19194_nested_2(20, 1); +CALL proc_19194_nested_2(20, 2); +CALL proc_19194_nested_2(20, 3); +CALL proc_19194_nested_2(20, 4); +CALL proc_19194_nested_2(30, 1); +CALL proc_19194_nested_2(40, 1); +CALL proc_19194_nested_2(0, 0); + +CALL proc_19194_nested_3(10, 1); +CALL proc_19194_nested_3(25, 1); +CALL proc_19194_nested_3(20, 1); +CALL proc_19194_nested_3(20, 2); +CALL proc_19194_nested_3(20, 3); +CALL proc_19194_nested_3(20, 4); +CALL proc_19194_nested_3(30, 1); +CALL proc_19194_nested_3(40, 1); +CALL proc_19194_nested_3(0, 0); + +CALL proc_19194_nested_4(10, 1); +CALL proc_19194_nested_4(25, 1); +CALL proc_19194_nested_4(20, 1); +CALL proc_19194_nested_4(20, 2); +CALL proc_19194_nested_4(20, 3); +CALL proc_19194_nested_4(20, 4); +CALL proc_19194_nested_4(30, 1); +CALL proc_19194_nested_4(40, 1); +CALL proc_19194_nested_4(0, 0); + +DROP PROCEDURE proc_19194_simple; +DROP PROCEDURE proc_19194_searched; +DROP PROCEDURE proc_19194_nested_1; +DROP PROCEDURE proc_19194_nested_2; +DROP PROCEDURE proc_19194_nested_3; +DROP PROCEDURE proc_19194_nested_4; # # Bug#19207: Final parenthesis omitted for CREATE INDEX in Stored diff --git a/mysql-test/t/sp_stress_case.sh b/mysql-test/t/sp_stress_case.sh new file mode 100755 index 00000000000..a2ac948e110 --- /dev/null +++ b/mysql-test/t/sp_stress_case.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +# +# Bug#19194 (Right recursion in parser for CASE causes excessive stack +# usage, limitation) +# +# Because the code for the CASE statement is so massive, +# checking in an already generated .test is not practical, +# due to it's size (10 000 lines or 356 000 bytes). +# +# Patches are sent by email, which introduce size limitations. +# +# As a result, code is generated dynamically here. +# This script takes no argument, and generates code in stdout. +# + +cat <&1 + +CALL bug_19194_a(1); +CALL bug_19194_a(2); +CALL bug_19194_a(1000); +CALL bug_19194_a(4998); +CALL bug_19194_a(4999); +CALL bug_19194_a(9999); + +CALL bug_19194_b(1); +CALL bug_19194_b(2); +CALL bug_19194_b(1000); +CALL bug_19194_b(4998); +CALL bug_19194_b(4999); +CALL bug_19194_b(9999); + +DROP PROCEDURE bug_19194_a; +DROP PROCEDURE bug_19194_b; + diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9761de625be..689922cfa37 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -603,27 +603,6 @@ sp_head::create(THD *thd) DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s", m_type, m_name.str, m_params.str, m_body.str)); -#ifndef DBUG_OFF - optimize(); - { - String s; - sp_instr *i; - uint ip= 0; - while ((i = get_instr(ip))) - { - char buf[8]; - - sprintf(buf, "%4u: ", ip); - s.append(buf); - i->print(&s); - s.append('\n'); - ip+= 1; - } - s.append('\0'); - DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr())); - } -#endif - if (m_type == TYPE_ENUM_FUNCTION) ret= sp_create_function(thd, this); else @@ -2172,7 +2151,7 @@ sp_head::show_create_function(THD *thd) 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_mark() Mark instruction as reachable opt_shortcut_jump() Shortcut jumps to the final destination; used by opt_mark(). opt_move() Update moved instruction @@ -2185,7 +2164,7 @@ void sp_head::optimize() sp_instr *i; uint src, dst; - opt_mark(0); + opt_mark(); bp.empty(); src= dst= 0; @@ -2219,13 +2198,50 @@ void sp_head::optimize() bp.empty(); } -void -sp_head::opt_mark(uint ip) +void sp_head::add_mark_lead(uint ip, List *leads) { - sp_instr *i; + sp_instr *i= get_instr(ip); - while ((i= get_instr(ip)) && !i->marked) - ip= i->opt_mark(this); + if (i && ! i->marked) + leads->push_front(i); +} + +void +sp_head::opt_mark() +{ + uint ip; + sp_instr *i; + List leads; + + /* + Forward flow analysis algorithm in the instruction graph: + - first, add the entry point in the graph (the first instruction) to the + 'leads' list of paths to explore. + - while there are still leads to explore: + - pick one lead, and follow the path forward. Mark instruction reached. + Stop only if the end of the routine is reached, or the path converge + to code already explored (marked). + - while following a path, collect in the 'leads' list any fork to + another path (caused by conditional jumps instructions), so that these + paths can be explored as well. + */ + + /* Add the entry point */ + i= get_instr(0); + leads.push_front(i); + + /* For each path of code ... */ + while (leads.elements != 0) + { + i= leads.pop(); + + /* Mark the entire path, collecting new leads. */ + while (i && ! i->marked) + { + ip= i->opt_mark(this, & leads); + i= get_instr(ip); + } + } } @@ -2618,7 +2634,7 @@ sp_instr_jump::print(String *str) } uint -sp_instr_jump::opt_mark(sp_head *sp) +sp_instr_jump::opt_mark(sp_head *sp, List *leads) { m_dest= opt_shortcut_jump(sp, this); if (m_dest != m_ip+1) /* Jumping to following instruction? */ @@ -2712,7 +2728,7 @@ sp_instr_jump_if_not::print(String *str) uint -sp_instr_jump_if_not::opt_mark(sp_head *sp) +sp_instr_jump_if_not::opt_mark(sp_head *sp, List *leads) { sp_instr *i; @@ -2722,13 +2738,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } - sp->opt_mark(m_dest); + sp->add_mark_lead(m_dest, leads); if ((i= sp->get_instr(m_cont_dest))) { m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } - sp->opt_mark(m_cont_dest); + sp->add_mark_lead(m_cont_dest, leads); return m_ip+1; } @@ -2849,7 +2865,7 @@ sp_instr_hpush_jump::print(String *str) uint -sp_instr_hpush_jump::opt_mark(sp_head *sp) +sp_instr_hpush_jump::opt_mark(sp_head *sp, List *leads) { sp_instr *i; @@ -2859,7 +2875,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp) m_dest= i->opt_shortcut_jump(sp, this); m_optdest= sp->get_instr(m_dest); } - sp->opt_mark(m_dest); + sp->add_mark_lead(m_dest, leads); return m_ip+1; } @@ -2924,15 +2940,13 @@ sp_instr_hreturn::print(String *str) uint -sp_instr_hreturn::opt_mark(sp_head *sp) +sp_instr_hreturn::opt_mark(sp_head *sp, List *leads) { if (m_dest) - return sp_instr_jump::opt_mark(sp); - else - { - marked= 1; - return UINT_MAX; - } + return sp_instr_jump::opt_mark(sp, leads); + + marked= 1; + return UINT_MAX; } @@ -3275,7 +3289,7 @@ sp_instr_set_case_expr::print(String *str) } uint -sp_instr_set_case_expr::opt_mark(sp_head *sp) +sp_instr_set_case_expr::opt_mark(sp_head *sp, List *leads) { sp_instr *i; @@ -3285,7 +3299,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp) m_cont_dest= i->opt_shortcut_jump(sp, this); m_cont_optdest= sp->get_instr(m_cont_dest); } - sp->opt_mark(m_cont_dest); + sp->add_mark_lead(m_cont_dest, leads); return m_ip+1; } diff --git a/sql/sp_head.h b/sql/sp_head.h index 7f2da69aa0c..6a377e6f188 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -302,8 +302,19 @@ public: void restore_thd_mem_root(THD *thd); + /** + Optimize the code. + */ void optimize(); - void opt_mark(uint ip); + + /** + Helper used during flow analysis during code optimization. + See the implementation of opt_mark(). + @param ip the instruction to add to the leads list + @param leads the list of remaining paths to explore in the graph that + represents the code, during flow analysis. + */ + void add_mark_lead(uint ip, List *leads); void recursion_level_error(THD *thd); @@ -393,6 +404,12 @@ private: bool execute(THD *thd); + /** + Perform a forward flow analysis in the generated code. + Mark reachable instructions, for the optimizer. + */ + void opt_mark(); + /* Merge the list of tables used by query into the multi-set of tables used by routine. @@ -460,10 +477,10 @@ public: /* Mark this instruction as reachable during optimization and return the - index to the next instruction. Jump instruction will mark their - destination too recursively. + index to the next instruction. Jump instruction will add their + destination to the leads list. */ - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List *leads) { marked= 1; return m_ip+1; @@ -735,7 +752,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List *leads); virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start); @@ -785,7 +802,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List *leads); /* Override sp_instr_jump's shortcut; we stop here */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) @@ -831,7 +848,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List *leads) { marked= 1; return UINT_MAX; @@ -868,7 +885,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List *leads); /* Override sp_instr_jump's shortcut; we stop here. */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) @@ -933,7 +950,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List *leads); private: @@ -1103,7 +1120,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp) + virtual uint opt_mark(sp_head *sp, List *leads) { marked= 1; return UINT_MAX; @@ -1136,7 +1153,7 @@ public: virtual void print(String *str); - virtual uint opt_mark(sp_head *sp); + virtual uint opt_mark(sp_head *sp, List *leads); virtual void opt_move(uint dst, List *ibp); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 405f576ac04..71e7d1cf86f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1163,7 +1163,6 @@ void st_select_lex::init_select() options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; braces= 0; - when_list.empty(); expr_list.empty(); interval_list.empty(); use_index.empty(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 378f968118e..8f4b021ca00 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -518,7 +518,6 @@ public: SQL_LIST order_list; /* ORDER clause */ List expr_list; - List when_list; /* WHEN clause (expression) */ SQL_LIST *gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ // Arrays of pointers to top elements of all_fields list diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6f24a42c07c..57b6201d4a9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -96,6 +96,146 @@ void turn_parser_debug_on() } #endif + +/** + Helper action for a case statement (entering the CASE). + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context +*/ + +void case_stmt_action_case(LEX *lex) +{ + lex->sphead->new_cont_backpatch(NULL); + + /* + BACKPATCH: Creating target label for the jump to + "case_stmt_action_end_case" + */ + + lex->spcont->push_label((char *)"", lex->sphead->instructions()); +} + +/** + Helper action for a case expression statement (the expr in 'CASE expr'). + This helper is used for 'searched' cases only. + @param lex the parser lex context + @param expr the parsed expression + @return 0 on success +*/ + +int case_stmt_action_expr(LEX *lex, Item* expr) +{ + sp_head *sp= lex->sphead; + sp_pcontext *parsing_ctx= lex->spcont; + int case_expr_id= parsing_ctx->register_case_expr(); + sp_instr_set_case_expr *i; + + if (parsing_ctx->push_case_expr_id(case_expr_id)) + return 1; + + i= new sp_instr_set_case_expr(sp->instructions(), + parsing_ctx, case_expr_id, expr, lex); + + sp->add_cont_backpatch(i); + sp->add_instr(i); + + return 0; +} + +/** + Helper action for a case when condition. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context + @param when the parsed expression for the WHEN clause + @param simple true for simple cases, false for searched cases +*/ + +void case_stmt_action_when(LEX *lex, Item *when, bool simple) +{ + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump_if_not *i; + Item_case_expr *var; + Item *expr; + + if (simple) + { + var= new Item_case_expr(ctx->get_current_case_expr_id()); + +#ifndef DBUG_OFF + if (var) + { + var->m_sp= sp; + } +#endif + + expr= new Item_func_eq(var, when); + i= new sp_instr_jump_if_not(ip, ctx, expr, lex); + } + else + i= new sp_instr_jump_if_not(ip, ctx, when, lex); + + /* + BACKPATCH: Registering forward jump from + "case_stmt_action_when" to "case_stmt_action_then" + */ + + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); + sp->add_instr(i); +} + +/** + Helper action for a case then statements. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context +*/ + +void case_stmt_action_then(LEX *lex) +{ + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump *i = new sp_instr_jump(ip, ctx); + sp->add_instr(i); + + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_when" to "case_stmt_action_then" + */ + + sp->backpatch(ctx->pop_label()); + + /* + BACKPATCH: Registering forward jump from + "case_stmt_action_when" to "case_stmt_action_end_case" + */ + + sp->push_backpatch(i, ctx->last_label()); +} + +/** + Helper action for an end case. + This helper is used for both 'simple' and 'searched' cases. + @param lex the parser lex context + @param simple true for simple cases, false for searched cases +*/ + +void case_stmt_action_end_case(LEX *lex, bool simple) +{ + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_then" to "case_stmt_action_end_case" + */ + lex->sphead->backpatch(lex->spcont->pop_label()); + + if (simple) + lex->spcont->pop_case_expr_id(); + + lex->sphead->do_cont_backpatch(); +} + %} %union { int num; @@ -832,7 +972,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - when_list2 expr_list2 udf_expr_list3 handler + expr_list2 udf_expr_list3 handler opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option field_opt_list opt_binary table_lock_list table_lock @@ -860,6 +1000,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail view_suid view_tail view_list_opt view_list view_select view_check_option trigger_tail sp_tail + case_stmt_specification simple_case_stmt searched_case_stmt END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -1995,43 +2136,7 @@ sp_proc_stmt: { Lex->sphead->new_cont_backpatch(NULL); } sp_if END IF { Lex->sphead->do_cont_backpatch(); } - | CASE_SYM WHEN_SYM - { - Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE; - Lex->sphead->new_cont_backpatch(NULL); - } - sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); } - | CASE_SYM - { - Lex->sphead->reset_lex(YYTHD); - Lex->sphead->new_cont_backpatch(NULL); - } - expr WHEN_SYM - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *parsing_ctx= lex->spcont; - int case_expr_id= parsing_ctx->register_case_expr(); - sp_instr_set_case_expr *i; - - if (parsing_ctx->push_case_expr_id(case_expr_id)) - YYABORT; - - i= new sp_instr_set_case_expr(sp->instructions(), - parsing_ctx, - case_expr_id, - $3, - lex); - sp->add_cont_backpatch(i); - sp->add_instr(i); - sp->m_flags|= sp_head::IN_SIMPLE_CASE; - sp->restore_lex(YYTHD); - } - sp_case END CASE_SYM - { - Lex->spcont->pop_case_expr_id(); - Lex->sphead->do_cont_backpatch(); - } + | case_stmt_specification | sp_labeled_control {} | { /* Unlabeled controls get a secret label. */ @@ -2242,72 +2347,114 @@ sp_elseifs: | ELSE sp_proc_stmts1 ; -sp_case: - { Lex->sphead->reset_lex(YYTHD); } - expr THEN_SYM - { +case_stmt_specification: + simple_case_stmt + | searched_case_stmt + ; + +simple_case_stmt: + CASE_SYM + { LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *ctx= Lex->spcont; - uint ip= sp->instructions(); - sp_instr_jump_if_not *i; + case_stmt_action_case(lex); + lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + LEX *lex= Lex; + if (case_stmt_action_expr(lex, $3)) + YYABORT; - if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE)) - i= new sp_instr_jump_if_not(ip, ctx, $2, lex); - else - { /* Simple case: = */ + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + simple_when_clause_list + else_clause_opt + END + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_end_case(lex, true); + } + ; - Item_case_expr *var; - Item *expr; +searched_case_stmt: + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_case(lex); + } + searched_when_clause_list + else_clause_opt + END + CASE_SYM + { + LEX *lex= Lex; + case_stmt_action_end_case(lex, false); + } + ; - var= new Item_case_expr(ctx->get_current_case_expr_id()); +simple_when_clause_list: + simple_when_clause + | simple_when_clause_list simple_when_clause + ; -#ifndef DBUG_OFF - if (var) - var->m_sp= sp; -#endif +searched_when_clause_list: + searched_when_clause + | searched_when_clause_list searched_when_clause + ; - expr= new Item_func_eq(var, $2); +simple_when_clause: + WHEN_SYM + { + Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + /* Simple case: = */ - i= new sp_instr_jump_if_not(ip, ctx, expr, lex); - } - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - sp->add_cont_backpatch(i); + LEX *lex= Lex; + case_stmt_action_when(lex, $3, true); + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + THEN_SYM + sp_proc_stmts1 + { + LEX *lex= Lex; + case_stmt_action_then(lex); + } + ; + +searched_when_clause: + WHEN_SYM + { + Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + } + expr + { + LEX *lex= Lex; + case_stmt_action_when(lex, $3, false); + lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + } + THEN_SYM + sp_proc_stmts1 + { + LEX *lex= Lex; + case_stmt_action_then(lex); + } + ; + +else_clause_opt: + /* empty */ + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint ip= sp->instructions(); + sp_instr_error *i= new sp_instr_error(ip, lex->spcont, + ER_SP_CASE_NOT_FOUND); sp->add_instr(i); - sp->restore_lex(YYTHD); - } - sp_proc_stmts1 - { - sp_head *sp= Lex->sphead; - sp_pcontext *ctx= Lex->spcont; - uint ip= sp->instructions(); - sp_instr_jump *i = new sp_instr_jump(ip, ctx); - - sp->add_instr(i); - sp->backpatch(ctx->pop_label()); - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - } - sp_whens - { - LEX *lex= Lex; - - lex->sphead->backpatch(lex->spcont->pop_label()); - } - ; - -sp_whens: - /* Empty */ - { - sp_head *sp= Lex->sphead; - uint ip= sp->instructions(); - sp_instr_error *i= new sp_instr_error(ip, Lex->spcont, - ER_SP_CASE_NOT_FOUND); - - sp->add_instr(i); - } - | ELSE sp_proc_stmts1 {} - | WHEN_SYM sp_case {} - ; + } + | ELSE sp_proc_stmts1 + ; sp_labeled_control: label_ident ':' @@ -4374,8 +4521,8 @@ simple_expr: if (!$$) YYABORT; } - | CASE_SYM opt_expr WHEN_SYM when_list opt_else END - { $$= new Item_func_case(* $4, $2, $5 ); } + | CASE_SYM opt_expr when_list opt_else END + { $$= new Item_func_case(* $3, $2, $4 ); } | CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5, @@ -5162,23 +5309,19 @@ opt_else: | ELSE expr { $$= $2; }; when_list: - { Select->when_list.push_front(new List); } - when_list2 - { $$= Select->when_list.pop(); }; - -when_list2: - expr THEN_SYM expr - { - SELECT_LEX *sel=Select; - sel->when_list.head()->push_back($1); - sel->when_list.head()->push_back($3); - } - | when_list2 WHEN_SYM expr THEN_SYM expr - { - SELECT_LEX *sel=Select; - sel->when_list.head()->push_back($3); - sel->when_list.head()->push_back($5); - }; + WHEN_SYM expr THEN_SYM expr + { + $$= new List; + $$->push_back($2); + $$->push_back($4); + } + | when_list WHEN_SYM expr THEN_SYM expr + { + $1->push_back($3); + $1->push_back($5); + $$= $1; + } + ; /* Warning - may return NULL in case of incomplete SELECT */ table_ref: From 87a87bc04b0314908933e3f644e04dc2d2733ba4 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.local" <> Date: Fri, 1 Dec 2006 13:25:06 +0300 Subject: [PATCH 02/27] A fix and a test case for Bug#24179 "select b into $var" fails with --cursor_protocol": fix a misleading error message in case of SELECT .. INTO. --- sql/sql_class.cc | 14 ++++++++++++++ sql/sql_class.h | 12 ++++++++++-- sql/sql_prepare.cc | 3 +-- tests/mysql_client_test.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d2f1e9ed0d9..f46cd2353eb 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -885,6 +885,13 @@ void select_result::cleanup() /* do nothing */ } +bool select_result::check_simple_select() const +{ + my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); + return TRUE; +} + + static String default_line_term("\n",default_charset_info); static String default_escaped("\\",default_charset_info); static String default_field_term("\t",default_charset_info); @@ -1553,6 +1560,13 @@ int select_dumpvar::prepare(List &list, SELECT_LEX_UNIT *u) } +bool select_dumpvar::check_simple_select() const +{ + my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0)); + return TRUE; +} + + void select_dumpvar::cleanup() { vars.empty(); diff --git a/sql/sql_class.h b/sql/sql_class.h index 41845dc5c76..ec03b9cb4a6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1724,7 +1724,14 @@ public: virtual bool initialize_tables (JOIN *join=0) { return 0; } virtual void send_error(uint errcode,const char *err); virtual bool send_eof()=0; - virtual bool simple_select() { return 0; } + /** + Check if this query returns a result set and therefore is allowed in + cursors and set an error message if it is not the case. + + @retval FALSE success + @retval TRUE error, an error message is set + */ + virtual bool check_simple_select() const; virtual void abort() {} /* Cleanup instance of this class for next execution of a prepared @@ -1762,7 +1769,7 @@ public: bool send_fields(List &list, uint flags); bool send_data(List &items); bool send_eof(); - bool simple_select() { return 1; } + virtual bool check_simple_select() const { return FALSE; } void abort(); }; @@ -2202,6 +2209,7 @@ public: int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); bool send_eof(); + virtual bool check_simple_select() const; void cleanup(); }; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1e7601c0951..8b2c2cd3674 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2906,10 +2906,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) in INSERT ... SELECT and similar commands. */ - if (open_cursor && lex->result && !lex->result->simple_select()) + if (open_cursor && lex->result && lex->result->check_simple_select()) { DBUG_PRINT("info",("Cursor asked for not SELECT stmt")); - my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0)); return TRUE; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index c596a589d55..0b8d4d81558 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15456,6 +15456,33 @@ static void test_bug21635() DBUG_VOID_RETURN; } +/* + Bug#24179 "select b into $var" fails with --cursor_protocol" + The failure is correct, check that the returned message is meaningful. +*/ + +static void test_bug24179() +{ + int rc; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug24179"); + myheader("test_bug24179"); + + stmt= open_cursor("select 1 into @a"); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc); + if (!opt_silent) + { + printf("Got error (as expected): %d %s\n", + mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + DIE_UNLESS(mysql_stmt_errno(stmt) == 1323); + + DBUG_VOID_RETURN; +} + /* Read and parse arguments and MySQL options from my.cnf @@ -15735,6 +15762,7 @@ static struct my_tests_st my_tests[]= { { "test_bug21726", test_bug21726 }, { "test_bug23383", test_bug23383 }, { "test_bug21635", test_bug21635 }, + { "test_bug24179", test_bug24179 }, { 0, 0 } }; From a9e1563fa44e631e1466f4c7044b2624f30f5240 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@booka." <> Date: Mon, 4 Dec 2006 14:05:27 +0300 Subject: [PATCH 03/27] Use standard shell instead of BASH. --- mysql-test/t/log.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/log.sh b/mysql-test/t/log.sh index 20b265087cc..29cf8d3e1a3 100755 --- a/mysql-test/t/log.sh +++ b/mysql-test/t/log.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh ########################################################################### From 2bc1898bc6e0943bde5a2d4211a716b28ff364f4 Mon Sep 17 00:00:00 2001 From: "petr/cps@outpost.site" <> Date: Mon, 4 Dec 2006 19:48:49 +0300 Subject: [PATCH 04/27] Fix Bug #19044 IM aborts on exit On windows IM aborted on assert once one stoppped it. The reason is that we didn't close the sockets on windows and therefore, the listener thread wasn't able to finish. This happened because we used close() call for it. While on windows one should use closesocket(). On other platfroms we have appropriate defines for closesocket(), so this is the function which should be used. --- server-tools/instance-manager/listener.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc index 3f60c2cc74a..70cd7360f0d 100644 --- a/server-tools/instance-manager/listener.cc +++ b/server-tools/instance-manager/listener.cc @@ -188,7 +188,7 @@ void Listener_thread::run() else { shutdown(client_fd, SHUT_RDWR); - close(client_fd); + closesocket(client_fd); } } } @@ -200,7 +200,7 @@ void Listener_thread::run() log_info("Listener_thread::run(): shutdown requested, exiting..."); for (i= 0; i < num_sockets; i++) - close(sockets[i]); + closesocket(sockets[i]); #ifndef __WIN__ unlink(unix_socket_address.sun_path); @@ -213,7 +213,7 @@ void Listener_thread::run() err: // we have to close the ip sockets in case of error for (i= 0; i < num_sockets; i++) - close(sockets[i]); + closesocket(sockets[i]); thread_registry.unregister_thread(&thread_info); thread_registry.request_shutdown(); @@ -260,7 +260,7 @@ int Listener_thread::create_tcp_socket() { log_error("Listener_thread::run(): bind(ip socket) failed, '%s'", strerror(errno)); - close(ip_socket); + closesocket(ip_socket); return -1; } @@ -268,7 +268,7 @@ int Listener_thread::create_tcp_socket() { log_error("Listener_thread::run(): listen(ip socket) failed, %s", strerror(errno)); - close(ip_socket); + closesocket(ip_socket); return -1; } From 506c2a722fd2078c2005df71b52145633454559c Mon Sep 17 00:00:00 2001 From: "malff/marcsql@weblab.(none)" <> Date: Mon, 11 Dec 2006 16:59:02 -0700 Subject: [PATCH 05/27] Bug#19194 (Right recursion in parser for CASE causes excessive stack usage, limitation) Bug#24854 (Mixing Searched Case with Simple Case inside Stored Procedure crashes Mysqld) Implemented code review (19194) comments --- mysql-test/r/sp_stress_case.result | 114 ++++++++++++++++++++++++----- mysql-test/t/sp_stress_case.sh | 68 ----------------- mysql-test/t/sp_stress_case.test | 105 ++++++++++++++++++++------ sql/sql_yacc.yy | 43 ++++++++++- 4 files changed, 220 insertions(+), 110 deletions(-) delete mode 100755 mysql-test/t/sp_stress_case.sh diff --git a/mysql-test/r/sp_stress_case.result b/mysql-test/r/sp_stress_case.result index b85fb41d0bf..8ec68363c8d 100644 --- a/mysql-test/r/sp_stress_case.result +++ b/mysql-test/r/sp_stress_case.result @@ -1,42 +1,120 @@ -DROP PROCEDURE IF EXISTS bug_19194_a; -DROP PROCEDURE IF EXISTS bug_19194_b; -'Silently creating PROCEDURE bug_19194_a' -'Silently creating PROCEDURE bug_19194_b' -CALL bug_19194_a(1); +DROP PROCEDURE IF EXISTS proc_19194_codegen; +DROP PROCEDURE IF EXISTS bug_19194_simple; +DROP PROCEDURE IF EXISTS bug_19194_searched; +CREATE PROCEDURE proc_19194_codegen( +IN proc_name VARCHAR(50), +IN count INTEGER, +IN simple INTEGER, +OUT body MEDIUMTEXT) +BEGIN +DECLARE code MEDIUMTEXT; +DECLARE i INT DEFAULT 1; +SET code = concat("CREATE PROCEDURE ", proc_name, "(i INT)\n"); +SET code = concat(code, "BEGIN\n"); +SET code = concat(code, " DECLARE str CHAR(10);\n"); +IF (simple) +THEN +SET code = concat(code, " CASE i\n"); +ELSE +SET code = concat(code, " CASE\n"); +END IF; +WHILE (i <= count) +DO +IF (simple) +THEN +SET code = concat(code, " WHEN ", i, " THEN SET str=\"", i, "\";\n"); +ELSE +SET code = concat(code, " WHEN i=", i, " THEN SET str=\"", i, "\";\n"); +END IF; +SET i = i + 1; +END WHILE; +SET code = concat(code, " ELSE SET str=\"unknown\";\n"); +SET code = concat(code, " END CASE;\n"); +SET code = concat(code, " SELECT str;\n"); +SET code = concat(code, "END\n"); +SET body = code; +END| +set @body=""; +call proc_19194_codegen("test_simple", 10, 1, @body); +select @body; +@body +CREATE PROCEDURE test_simple(i INT) +BEGIN + DECLARE str CHAR(10); + CASE i + WHEN 1 THEN SET str="1"; + WHEN 2 THEN SET str="2"; + WHEN 3 THEN SET str="3"; + WHEN 4 THEN SET str="4"; + WHEN 5 THEN SET str="5"; + WHEN 6 THEN SET str="6"; + WHEN 7 THEN SET str="7"; + WHEN 8 THEN SET str="8"; + WHEN 9 THEN SET str="9"; + WHEN 10 THEN SET str="10"; + ELSE SET str="unknown"; + END CASE; + SELECT str; +END + +call proc_19194_codegen("test_searched", 10, 0, @body); +select @body; +@body +CREATE PROCEDURE test_searched(i INT) +BEGIN + DECLARE str CHAR(10); + CASE + WHEN i=1 THEN SET str="1"; + WHEN i=2 THEN SET str="2"; + WHEN i=3 THEN SET str="3"; + WHEN i=4 THEN SET str="4"; + WHEN i=5 THEN SET str="5"; + WHEN i=6 THEN SET str="6"; + WHEN i=7 THEN SET str="7"; + WHEN i=8 THEN SET str="8"; + WHEN i=9 THEN SET str="9"; + WHEN i=10 THEN SET str="10"; + ELSE SET str="unknown"; + END CASE; + SELECT str; +END + +CALL bug_19194_simple(1); str 1 -CALL bug_19194_a(2); +CALL bug_19194_simple(2); str 2 -CALL bug_19194_a(1000); +CALL bug_19194_simple(1000); str 1000 -CALL bug_19194_a(4998); +CALL bug_19194_simple(4998); str 4998 -CALL bug_19194_a(4999); +CALL bug_19194_simple(4999); str 4999 -CALL bug_19194_a(9999); +CALL bug_19194_simple(9999); str unknown -CALL bug_19194_b(1); +CALL bug_19194_searched(1); str 1 -CALL bug_19194_b(2); +CALL bug_19194_searched(2); str 2 -CALL bug_19194_b(1000); +CALL bug_19194_searched(1000); str 1000 -CALL bug_19194_b(4998); +CALL bug_19194_searched(4998); str 4998 -CALL bug_19194_b(4999); +CALL bug_19194_searched(4999); str 4999 -CALL bug_19194_b(9999); +CALL bug_19194_searched(9999); str unknown -DROP PROCEDURE bug_19194_a; -DROP PROCEDURE bug_19194_b; +DROP PROCEDURE proc_19194_codegen; +DROP PROCEDURE bug_19194_simple; +DROP PROCEDURE bug_19194_searched; diff --git a/mysql-test/t/sp_stress_case.sh b/mysql-test/t/sp_stress_case.sh deleted file mode 100755 index a2ac948e110..00000000000 --- a/mysql-test/t/sp_stress_case.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh - -# -# Bug#19194 (Right recursion in parser for CASE causes excessive stack -# usage, limitation) -# -# Because the code for the CASE statement is so massive, -# checking in an already generated .test is not practical, -# due to it's size (10 000 lines or 356 000 bytes). -# -# Patches are sent by email, which introduce size limitations. -# -# As a result, code is generated dynamically here. -# This script takes no argument, and generates code in stdout. -# - -cat <&1 +delimiter |; -CALL bug_19194_a(1); -CALL bug_19194_a(2); -CALL bug_19194_a(1000); -CALL bug_19194_a(4998); -CALL bug_19194_a(4999); -CALL bug_19194_a(9999); +CREATE PROCEDURE proc_19194_codegen( + IN proc_name VARCHAR(50), + IN count INTEGER, + IN simple INTEGER, + OUT body MEDIUMTEXT) +BEGIN + DECLARE code MEDIUMTEXT; + DECLARE i INT DEFAULT 1; -CALL bug_19194_b(1); -CALL bug_19194_b(2); -CALL bug_19194_b(1000); -CALL bug_19194_b(4998); -CALL bug_19194_b(4999); -CALL bug_19194_b(9999); + SET code = concat("CREATE PROCEDURE ", proc_name, "(i INT)\n"); + SET code = concat(code, "BEGIN\n"); + SET code = concat(code, " DECLARE str CHAR(10);\n"); -DROP PROCEDURE bug_19194_a; -DROP PROCEDURE bug_19194_b; + IF (simple) + THEN + SET code = concat(code, " CASE i\n"); + ELSE + SET code = concat(code, " CASE\n"); + END IF; + + WHILE (i <= count) + DO + IF (simple) + THEN + SET code = concat(code, " WHEN ", i, " THEN SET str=\"", i, "\";\n"); + ELSE + SET code = concat(code, " WHEN i=", i, " THEN SET str=\"", i, "\";\n"); + END IF; + + SET i = i + 1; + END WHILE; + + SET code = concat(code, " ELSE SET str=\"unknown\";\n"); + SET code = concat(code, " END CASE;\n"); + SET code = concat(code, " SELECT str;\n"); + + SET code = concat(code, "END\n"); + + SET body = code; +END| + +delimiter ;| + +set @body=""; +call proc_19194_codegen("test_simple", 10, 1, @body); +select @body; +call proc_19194_codegen("test_searched", 10, 0, @body); +select @body; + +--disable_query_log +call proc_19194_codegen("bug_19194_simple", 5000, 1, @body); +let $proc_body = `select @body`; +eval $proc_body; +call proc_19194_codegen("bug_19194_searched", 5000, 1, @body); +let $proc_body = `select @body`; +eval $proc_body; +--enable_query_log + +CALL bug_19194_simple(1); +CALL bug_19194_simple(2); +CALL bug_19194_simple(1000); +CALL bug_19194_simple(4998); +CALL bug_19194_simple(4999); +CALL bug_19194_simple(9999); + +CALL bug_19194_searched(1); +CALL bug_19194_searched(2); +CALL bug_19194_searched(1000); +CALL bug_19194_searched(4998); +CALL bug_19194_searched(4999); +CALL bug_19194_searched(9999); + +DROP PROCEDURE proc_19194_codegen; +DROP PROCEDURE bug_19194_simple; +DROP PROCEDURE bug_19194_searched; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 57b6201d4a9..014be54eef6 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -100,6 +100,42 @@ void turn_parser_debug_on() /** Helper action for a case statement (entering the CASE). This helper is used for both 'simple' and 'searched' cases. + This helper, with the other case_stmt_action_..., is executed when + the following SQL code is parsed: +
+CREATE PROCEDURE proc_19194_simple(i int)
+BEGIN
+  DECLARE str CHAR(10);
+
+  CASE i
+    WHEN 1 THEN SET str="1";
+    WHEN 2 THEN SET str="2";
+    WHEN 3 THEN SET str="3";
+    ELSE SET str="unknown";
+  END CASE;
+
+  SELECT str;
+END
+
+ The actions are used to generate the following code: +
+SHOW PROCEDURE CODE proc_19194_simple;
+Pos     Instruction
+0       set str@1 NULL
+1       set_case_expr (12) 0 i@0
+2       jump_if_not 5(12) (case_expr@0 = 1)
+3       set str@1 _latin1'1'
+4       jump 12
+5       jump_if_not 8(12) (case_expr@0 = 2)
+6       set str@1 _latin1'2'
+7       jump 12
+8       jump_if_not 11(12) (case_expr@0 = 3)
+9       set str@1 _latin1'3'
+10      jump 12
+11      set str@1 _latin1'unknown'
+12      stmt 0 "SELECT str"
+
+ @param lex the parser lex context */ @@ -110,6 +146,7 @@ void case_stmt_action_case(LEX *lex) /* BACKPATCH: Creating target label for the jump to "case_stmt_action_end_case" + (Instruction 12 in the example) */ lex->spcont->push_label((char *)"", lex->sphead->instructions()); @@ -179,6 +216,7 @@ void case_stmt_action_when(LEX *lex, Item *when, bool simple) /* BACKPATCH: Registering forward jump from "case_stmt_action_when" to "case_stmt_action_then" + (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) */ sp->push_backpatch(i, ctx->push_label((char *)"", 0)); @@ -203,13 +241,15 @@ void case_stmt_action_then(LEX *lex) /* BACKPATCH: Resolving forward jump from "case_stmt_action_when" to "case_stmt_action_then" + (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) */ sp->backpatch(ctx->pop_label()); /* BACKPATCH: Registering forward jump from - "case_stmt_action_when" to "case_stmt_action_end_case" + "case_stmt_action_then" to "case_stmt_action_end_case" + (jump from instruction 4 to 12, 7 to 12 ... in the example) */ sp->push_backpatch(i, ctx->last_label()); @@ -227,6 +267,7 @@ void case_stmt_action_end_case(LEX *lex, bool simple) /* BACKPATCH: Resolving forward jump from "case_stmt_action_then" to "case_stmt_action_end_case" + (jump from instruction 4 to 12, 7 to 12 ... in the example) */ lex->sphead->backpatch(lex->spcont->pop_label()); From 7696592b091740c2dac49704c5d9e1574f12bf30 Mon Sep 17 00:00:00 2001 From: "malff/marcsql@weblab.(none)" <> Date: Mon, 11 Dec 2006 18:52:24 -0700 Subject: [PATCH 06/27] minor cleanup --- mysql-test/t/sp_stress_case.test | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mysql-test/t/sp_stress_case.test b/mysql-test/t/sp_stress_case.test index 5b278802e26..1b5bd8991a9 100644 --- a/mysql-test/t/sp_stress_case.test +++ b/mysql-test/t/sp_stress_case.test @@ -3,11 +3,6 @@ # usage, limitation) # -# This test takes some time (8 min) in debug builds -# It's provided as a separate file so that the next line can be uncommented -# later if needed: -# -- source include/big_test.inc - --disable_warnings DROP PROCEDURE IF EXISTS proc_19194_codegen; DROP PROCEDURE IF EXISTS bug_19194_simple; From 53d97a7d721463fd8004c1472b3e10ac352daec1 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Mon, 11 Dec 2006 18:57:23 -0800 Subject: [PATCH 07/27] Fixed bug #24670: optimizations that are legal only for subqueries without tables and no WHERE condition were applied for any subquery without tables. --- mysql-test/r/subselect.result | 13 +++++++++++++ mysql-test/t/subselect.test | 12 ++++++++++++ sql/item_subselect.cc | 19 +++++++++++++++++-- sql/item_subselect.h | 3 ++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 89315342f5e..a4ea8e21d61 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3013,3 +3013,16 @@ t3 CREATE TABLE `t3` ( `a` datetime default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) > 0; +a +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +a +1 +2 +EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +DROP TABLE t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 804cc2274c9..f816551e51f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1981,4 +1981,16 @@ SHOW CREATE TABLE t3; DROP TABLE t1,t2,t3; +# +# Bug 24670: subquery witout tables but with a WHERE clause +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); + +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) > 0; +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; + +DROP TABLE t1; # End of 4.1 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index cd1f8f83821..20a092d7607 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -350,6 +350,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ !(select_lex->item_list.head()->type() == FIELD_ITEM || select_lex->item_list.head()->type() == REF_ITEM) && + !join->conds && !join->having && /* switch off this optimisation for prepare statement, because we do not rollback this changes @@ -374,8 +375,6 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ substitution->walk(&Item::remove_dependence_processor, (byte *) select_lex->outer_select()); - /* SELECT without FROM clause can't have WHERE or HAVING clause */ - DBUG_ASSERT(join->conds == 0 && join->having == 0); return RES_REDUCE; } return RES_OK; @@ -1795,6 +1794,22 @@ bool subselect_single_select_engine::no_tables() } +/* + Check statically whether the subquery can return NULL + + SINOPSYS + subselect_single_select_engine::may_be_null() + + RETURN + FALSE can guarantee that the subquery never return NULL + TRUE otherwise +*/ +bool subselect_single_select_engine::may_be_null() +{ + return ((no_tables() && !join->conds && !join->having) ? maybe_null : 1); +} + + /* Report about presence of tables in subquery diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 7b064bfe92c..539dcc5676a 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -301,7 +301,7 @@ public: enum Item_result type() { return res_type; } enum_field_types field_type() { return res_field_type; } virtual void exclude()= 0; - bool may_be_null() { return maybe_null; }; + virtual bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); virtual void print(String *str)= 0; @@ -335,6 +335,7 @@ public: void print (String *str); int change_item(Item_subselect *si, select_subselect *result); bool no_tables(); + bool may_be_null(); }; From 026196c4ef3217491d22959bafde1cea40f9667b Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Wed, 13 Dec 2006 00:39:13 -0800 Subject: [PATCH 08/27] Fixed bug #25027. Removed an assertion that was not valid for the cases where the query in a prepared statement contained a single-row non-correlated subquery that was used as an argument of the IS NULL predicate. --- mysql-test/r/ps.result | 15 +++++++++++++++ mysql-test/t/ps.test | 18 ++++++++++++++++++ sql/sql_lex.cc | 1 - 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 234c12955d9..b5a9367c985 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1514,4 +1514,19 @@ Variable_name Value Slow_queries 1 deallocate prepare no_index; deallocate prepare sq; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (NULL); +SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL; +a +1 +2 +PREPARE stmt FROM 'SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL'; +EXECUTE stmt; +a +1 +2 +DEALLOCATE PREPARE stmt; +DROP TABLE t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 547f9a766d1..9386436a1fd 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1563,4 +1563,22 @@ execute sq; deallocate prepare no_index; deallocate prepare sq; +# +# Bug 25027: query with a single-row non-correlated subquery +# and IS NULL predicate +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES (NULL); + +SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL; +PREPARE stmt FROM 'SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL'; + +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; +DROP TABLE t1,t2; + --echo End of 5.0 tests. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3de842c8551..f5ec0c1161d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1903,7 +1903,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) { ha_rows select_limit_val; - DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare()); select_limit_val= (ha_rows)(sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR); offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : From 8642d23b6a1ef75d9120ba0871de2c183feee7db Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Wed, 13 Dec 2006 21:08:25 -0800 Subject: [PATCH 09/27] Fixed bug #25027. Blocked evaluation of constant objects of the classes Item_func_is_null and Item_is_not_null_test at the prepare phase in the cases when the objects used subqueries. --- mysql-test/r/ps.result | 7 +++++++ mysql-test/t/ps.test | 7 ++++++- sql/item_cmpfunc.cc | 6 +++--- sql/item_cmpfunc.h | 3 ++- sql/sql_lex.cc | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index b5a9367c985..000a9317b8d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1528,5 +1528,12 @@ a 1 2 DEALLOCATE PREPARE stmt; +PREPARE stmt FROM 'SELECT a FROM t1 WHERE (SELECT b FROM t2 limit ?) IS NULL'; +SET @arg=1; +EXECUTE stmt USING @arg; +a +1 +2 +DEALLOCATE PREPARE stmt; DROP TABLE t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 9386436a1fd..f6de2a40efa 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1577,8 +1577,13 @@ SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL; PREPARE stmt FROM 'SELECT a FROM t1 WHERE (SELECT b FROM t2) IS NULL'; EXECUTE stmt; - DEALLOCATE PREPARE stmt; + +PREPARE stmt FROM 'SELECT a FROM t1 WHERE (SELECT b FROM t2 limit ?) IS NULL'; +SET @arg=1; +EXECUTE stmt USING @arg; +DEALLOCATE PREPARE stmt; + DROP TABLE t1,t2; --echo End of 5.0 tests. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 29fa049b6c4..0a7cbbb51cb 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2990,7 +2990,7 @@ longlong Item_func_isnull::val_int() Handle optimization if the argument can't be null This has to be here because of the test in update_used_tables(). */ - if (!used_tables_cache) + if (!used_tables_cache && !with_subselect) return cached_value; return args[0]->is_null() ? 1: 0; } @@ -2999,7 +2999,7 @@ longlong Item_is_not_null_test::val_int() { DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_is_not_null_test::val_int"); - if (!used_tables_cache) + if (!used_tables_cache && !with_subselect) { owner->was_null|= (!cached_value); DBUG_PRINT("info", ("cached :%ld", (long) cached_value)); @@ -3026,7 +3026,7 @@ void Item_is_not_null_test::update_used_tables() else { args[0]->update_used_tables(); - if (!(used_tables_cache=args[0]->used_tables())) + if (!(used_tables_cache=args[0]->used_tables()) && !with_subselect) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) !args[0]->is_null(); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index acad1e51bc9..faeee0d5567 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1028,7 +1028,8 @@ public: else { args[0]->update_used_tables(); - if ((const_item_cache= !(used_tables_cache= args[0]->used_tables()))) + if ((const_item_cache= !(used_tables_cache= args[0]->used_tables())) && + !with_subselect) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) args[0]->is_null(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f5ec0c1161d..3de842c8551 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1903,6 +1903,7 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) { ha_rows select_limit_val; + DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare()); select_limit_val= (ha_rows)(sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR); offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : From d56d3a697136fc4e80abb2da9d18aadffa201d7e Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 15 Dec 2006 11:38:30 +0200 Subject: [PATCH 10/27] Bug #15439: UDF name case handling forces DELETE FROM mysql.func to remove the UDF When deleting a user defined function MySQL must remove it from both the in-memory hash table and the mysql.proc system table. Finding (and removal therefore) from the internal hash table is case insensitive (or whatever the default charset is), whereas finding and removal from the system table is case sensitive. As a result if you supply a function name that is not in the same character case to DROP FUNCTION the server will remove the function only from the in-memory hash table and will keep the row in mysql.proc system table. This will cause inconsistency between the two structures (that is fixed only by restarting the server). Fixed by using the name in the precise case (from the in-memory hash table) to delete the row in the mysql.proc system table. --- mysql-test/r/udf.result | 11 +++++++++++ mysql-test/t/udf.test | 17 +++++++++++++++++ sql/sql_udf.cc | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index eb5d771bcfe..64b7111bbc8 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -194,6 +194,17 @@ DROP FUNCTION sequence; DROP FUNCTION lookup; DROP FUNCTION reverse_lookup; DROP FUNCTION avgcost; +select * from mysql.func; +name ret dl type +CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +select IS_const(3); +IS_const(3) +const +drop function IS_const; +select * from mysql.func; +name ret dl type +select is_const(3); +ERROR 42000: FUNCTION test.is_const does not exist CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; select is_const(3) as const, diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 52ae424e423..65cbc7ae3ae 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -187,6 +187,23 @@ DROP FUNCTION lookup; DROP FUNCTION reverse_lookup; DROP FUNCTION avgcost; +# +# Bug #15439: UDF name case handling forces DELETE FROM mysql.func to remove +# the UDF +# +select * from mysql.func; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION is_const RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +select IS_const(3); + +drop function IS_const; + +select * from mysql.func; + +--error 1305 +select is_const(3); + # # Bug#18761: constant expression as UDF parameters not passed in as constant # diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 163801e2f1e..5bbfa522d58 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -536,7 +536,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) tables.table_name= tables.alias= (char*) "func"; if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; - table->field[0]->store(udf_name->str, udf_name->length, system_charset_info); + table->field[0]->store(udf->name.str, udf->name.length, &my_charset_bin); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (!table->file->index_read_idx(table->record[0], 0, (byte*) table->field[0]->ptr, From ba7a03759bb4d70d951138fda64cab87d1f95e61 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@alik." <> Date: Tue, 19 Dec 2006 15:32:02 +0300 Subject: [PATCH 11/27] Fix for BUG#24293: '\Z' token is not handled correctly in views. If SELECT-part of CREATE VIEW statement contains '\Z', it is not handled correctly. The problem was in String::print(). Symbol with code 032 (26) is replaced with '\z', which is not supported by the lexer. The fix is to replace the symbol with '\Z'. --- mysql-test/r/view.result | 9 +++++++++ mysql-test/t/view.test | 15 +++++++++++++++ sql/sql_string.cc | 4 ++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 81711f95ae6..caa494c26b3 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3014,4 +3014,13 @@ i j 6 3 DROP VIEW v1, v2; DROP TABLE t1; +DROP VIEW IF EXISTS v1; +CREATE VIEW v1 AS SELECT 'The\ZEnd'; +SELECT * FROM v1; +TheEnd +TheEnd +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _latin1'The\ZEnd' AS `TheEnd` +DROP VIEW v1; End of 5.0 tests. diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 8473458ae15..a34a1ba117d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2960,4 +2960,19 @@ DROP VIEW v1, v2; DROP TABLE t1; +# +# BUG#24293: '\Z' token is not handled correctly in views +# + +--disable_warnings +DROP VIEW IF EXISTS v1; +--enable_warnings + +CREATE VIEW v1 AS SELECT 'The\ZEnd'; +SELECT * FROM v1; + +SHOW CREATE VIEW v1; + +DROP VIEW v1; + --echo End of 5.0 tests. diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 85ff1fddc45..10ce72e9b9f 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -1033,8 +1033,8 @@ void String::print(String *str) case '\r': str->append(STRING_WITH_LEN("\\r")); break; - case 26: //Ctrl-Z - str->append(STRING_WITH_LEN("\\z")); + case '\032': // Ctrl-Z + str->append(STRING_WITH_LEN("\\Z")); break; default: str->append(c); From 8e0367918c906047087b49a2273d512dba9c1eac Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Tue, 19 Dec 2006 15:04:26 +0200 Subject: [PATCH 12/27] Bug #23578: Corruption prevents Optimize table from working properly with a spatial index While executing OPTIMIZE TABLE on MyISAM tables the server re-creates the index file(s) in order to sort them physically by the key. This cannot be done for R-tree indexes as it makes no sense. The server was not checking the type of the index and was accessing an R-tree index as if it was a B-tree. Fixed by preventing sorting the index file if it contains an R-tree index. --- myisam/mi_check.c | 8 ++++++++ mysql-test/r/gis-rtree.result | 11 +++++++++++ mysql-test/t/gis-rtree.test | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 06fdd3bff4c..68e5860a6d1 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1758,6 +1758,12 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) MI_STATE_INFO old_state; DBUG_ENTER("mi_sort_index"); + /* cannot sort index files with R-tree indexes */ + for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ; + key++,keyinfo++) + if (keyinfo->key_alg == HA_KEY_ALG_RTREE) + return 0; + if (!(param->testflag & T_SILENT)) printf("- Sorting index for MyISAM-table '%s'\n",name); @@ -1850,6 +1856,8 @@ static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, char llbuff[22]; DBUG_ENTER("sort_one_index"); + /* cannot walk over R-tree indices */ + DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE); new_page_pos=param->new_file_pos; param->new_file_pos+=keyinfo->block_length; diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index e8134a50496..05d0d5634e6 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -881,3 +881,14 @@ ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field INSERT INTO t1(foo) VALUES (''); ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field DROP TABLE t1; +CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)); +INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)')); +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index e34dd14dbfc..1704fe7dc80 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -254,3 +254,20 @@ INSERT INTO t1() VALUES (); --error 1416 INSERT INTO t1(foo) VALUES (''); DROP TABLE t1; + +# +# Bug #23578: Corruption prevents Optimize table from working properly with a +# spatial index +# + +CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)); + +INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)')); +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; +INSERT INTO t1 (b) SELECT b FROM t1; + +OPTIMIZE TABLE t1; +DROP TABLE t1; From 770608cf267788e8a050894d221a29db1513cbd6 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@rakia.gmz" <> Date: Wed, 3 Jan 2007 18:26:39 +0200 Subject: [PATCH 13/27] sql_udf.cc: Addendum to the fix for bug#15439 : valgrind pb failed --- sql/sql_udf.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 5bbfa522d58..2ebfadb7ba9 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -510,6 +510,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) TABLE *table; TABLE_LIST tables; udf_func *udf; + char *exact_name_str; + uint exact_name_len; DBUG_ENTER("mysql_drop_function"); if (!initialized) { @@ -523,6 +525,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); goto err; } + exact_name_str= udf->name.str; + exact_name_len= udf->name.length; del_udf(udf); /* Close the handle if this was function that was found during boot or @@ -536,7 +540,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) tables.table_name= tables.alias= (char*) "func"; if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; - table->field[0]->store(udf->name.str, udf->name.length, &my_charset_bin); + table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (!table->file->index_read_idx(table->record[0], 0, (byte*) table->field[0]->ptr, From 08369f4bceb6e0288ae243126af27a179b62d694 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Wed, 3 Jan 2007 12:16:03 -0800 Subject: [PATCH 14/27] Fixed bug #24345. This bug appeared after the patch for bug 21390 that had added some code to handle outer joins with no matches after substitution of a const table in an efficient way. That code as it is cannot be applied to the case of nested outer join operations. Being applied to the queries with nested outer joins the code can cause crashes or wrong result sets. The fix blocks row substitution for const inner tables of an outer join if the inner operand is not a single table. --- mysql-test/r/join_nested.result | 43 +++++++++++++++++++++++++++ mysql-test/t/join_nested.test | 51 +++++++++++++++++++++++++++++++++ sql/sql_select.cc | 12 +++++++- 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 0747418111b..f5c98f383b7 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1562,3 +1562,46 @@ id ngroupbynsa 2 1 2 1 DROP TABLE t1,t2,t3,t4,t5; +CREATE TABLE t1 ( +id int NOT NULL PRIMARY KEY, +ct int DEFAULT NULL, +pc int DEFAULT NULL, +INDEX idx_ct (ct), +INDEX idx_pc (pc) +); +INSERT INTO t1 VALUES +(1,NULL,NULL),(2,NULL,NULL),(3,NULL,NULL),(4,NULL,NULL),(5,NULL,NULL); +CREATE TABLE t2 ( +id int NOT NULL PRIMARY KEY, +sr int NOT NULL, +nm varchar(255) NOT NULL, +INDEX idx_sr (sr) +); +INSERT INTO t2 VALUES +(2441905,4308,'LesAbymes'),(2441906,4308,'Anse-Bertrand'); +CREATE TABLE t3 ( +id int NOT NULL PRIMARY KEY, +ct int NOT NULL, +ln int NOT NULL, +INDEX idx_ct (ct), +INDEX idx_ln (ln) +); +CREATE TABLE t4 ( +id int NOT NULL PRIMARY KEY, +nm varchar(255) NOT NULL +); +INSERT INTO t4 VALUES (4308,'Guadeloupe'),(4309,'Martinique'); +SELECT t1.* +FROM t1 LEFT JOIN +(t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id +WHERE t1.id='5'; +id ct pc +5 NULL NULL +SELECT t1.*, t4.nm +FROM t1 LEFT JOIN +(t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id +LEFT JOIN t4 ON t2.sr=t4.id +WHERE t1.id='5'; +id ct pc nm +5 NULL NULL NULL +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 69886d035bf..e7405418be7 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -994,3 +994,54 @@ SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa DROP TABLE t1,t2,t3,t4,t5; +# +# Test for bug #24345: crash with nested left outer join when outer table is substituted +# for a row that happens to have a null value for the join attribute. +# + +CREATE TABLE t1 ( + id int NOT NULL PRIMARY KEY, + ct int DEFAULT NULL, + pc int DEFAULT NULL, + INDEX idx_ct (ct), + INDEX idx_pc (pc) +); +INSERT INTO t1 VALUES + (1,NULL,NULL),(2,NULL,NULL),(3,NULL,NULL),(4,NULL,NULL),(5,NULL,NULL); + +CREATE TABLE t2 ( + id int NOT NULL PRIMARY KEY, + sr int NOT NULL, + nm varchar(255) NOT NULL, + INDEX idx_sr (sr) +); +INSERT INTO t2 VALUES + (2441905,4308,'LesAbymes'),(2441906,4308,'Anse-Bertrand'); + +CREATE TABLE t3 ( + id int NOT NULL PRIMARY KEY, + ct int NOT NULL, + ln int NOT NULL, + INDEX idx_ct (ct), + INDEX idx_ln (ln) +); + +CREATE TABLE t4 ( + id int NOT NULL PRIMARY KEY, + nm varchar(255) NOT NULL +); + +INSERT INTO t4 VALUES (4308,'Guadeloupe'),(4309,'Martinique'); + +SELECT t1.* + FROM t1 LEFT JOIN + (t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id + WHERE t1.id='5'; + +SELECT t1.*, t4.nm + FROM t1 LEFT JOIN + (t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id + LEFT JOIN t4 ON t2.sr=t4.id + WHERE t1.id='5'; + +DROP TABLE t1,t2,t3,t4; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3d2f46a9982..f175f770b55 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2306,8 +2306,18 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, substitution of a const table the key value happens to be null then we can state that there are no matches for this equi-join. */ - if ((keyuse= s->keyuse) && *s->on_expr_ref) + if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map) { + /* + When performing an outer join operation if there are no matching rows + for the single row of the outer table all the inner tables are to be + null complemented and thus considered as constant tables. + Here we apply this consideration to the case of outer join operations + with a single inner table only because the case with nested tables + would require a more thorough analysis. + TODO. Apply single row substitution to null complemented inner tables + for nested outer join operations. + */ while (keyuse->table == table) { if (!(keyuse->val->used_tables() & ~join->const_table_map) && From a63df24a689e344e5a73ef0826daf80866505278 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 5 Jan 2007 14:02:50 +0200 Subject: [PATCH 15/27] Bug #15881: cast problems The optimizer removes expressions from GROUP BY/DISTINCT if they happen to participate in a = predicates of the WHERE clause (the idea being that if it's always equal to a constant it can't have multiple values). However for predicates where the expression and the constant item are of different result type this is not valid (e.g. a string column compared to 0). Fixed by additional check of the result types of the expression and the constant and if they differ the expression don't get removed from the group by list. --- mysql-test/r/distinct.result | 37 ++++++++++++++++++++++++++++++ mysql-test/t/distinct.test | 21 +++++++++++++++++ sql/sql_select.cc | 44 ++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 86ab2141e2d..32151305698 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -607,3 +607,40 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT DISTINCT a,a FROM t1 WHERE b < 12 ORDER BY a; a a DROP TABLE t1; +CREATE TABLE t1 (a CHAR(1)); +INSERT INTO t1 VALUES('A'), (0); +SELECT a FROM t1 WHERE a=0; +a +A +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DISTINCT a FROM t1 WHERE a=0; +a +A +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('1972-07-29'), ('1972-02-06'); +EXPLAIN SELECT (SELECT DISTINCT a FROM t1 WHERE a = '2002-08-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where +EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1 +WHERE ADDDATE(a,1) = '2002-08-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where; Using temporary +CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci); +INSERT INTO t2 VALUES (0xf6); +INSERT INTO t2 VALUES ('oe'); +SELECT COUNT(*) FROM (SELECT DISTINCT a FROM t2) dt; +COUNT(*) +2 +SELECT COUNT(*) FROM +(SELECT DISTINCT a FROM t2 WHERE a='oe' COLLATE latin1_german2_ci) dt; +COUNT(*) +2 +DROP TABLE t1, t2; diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index b2cc42cc0ff..8734b940241 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -504,3 +504,24 @@ DROP TABLE t1; #DROP TABLE t1; #DROP TABLE t2; +# +# Bug #15881: cast problems +# +CREATE TABLE t1 (a CHAR(1)); INSERT INTO t1 VALUES('A'), (0); +SELECT a FROM t1 WHERE a=0; +SELECT DISTINCT a FROM t1 WHERE a=0; +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('1972-07-29'), ('1972-02-06'); +EXPLAIN SELECT (SELECT DISTINCT a FROM t1 WHERE a = '2002-08-03'); +EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1 + WHERE ADDDATE(a,1) = '2002-08-03'); +CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci); +INSERT INTO t2 VALUES (0xf6); +INSERT INTO t2 VALUES ('oe'); + +SELECT COUNT(*) FROM (SELECT DISTINCT a FROM t2) dt; +SELECT COUNT(*) FROM + (SELECT DISTINCT a FROM t2 WHERE a='oe' COLLATE latin1_german2_ci) dt; + +DROP TABLE t1, t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 30514f09493..0765b97c4d0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8432,6 +8432,46 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) return cond; // Point at next and level } +/* + Check if equality can be used in removing components of GROUP BY/DISTINCT + + SYNOPSIS + test_if_equality_guarantees_uniqueness() + l the left comparison argument (a field if any) + r the right comparison argument (a const of any) + + DESCRIPTION + Checks if an equality predicate can be used to take away + DISTINCT/GROUP BY because it is known to be true for exactly one + distinct value (e.g. == ). + Arguments must be of the same type because e.g. + = may match more than 1 distinct value from + the column. + We must take into consideration and the optimization done for various + string constants when compared to dates etc (see Item_int_with_ref) as + well as the collation of the arguments. + + RETURN VALUE + TRUE can be used + FALSE cannot be used +*/ +static bool +test_if_equality_guarantees_uniqueness(Item *l, Item *r) +{ + return r->const_item() && + /* elements must be of the same result type */ + (r->result_type() == l->result_type() || + /* or dates compared to longs */ + (((l->type() == Item::FIELD_ITEM && + ((Item_field *)l)->field->can_be_compared_as_longlong()) || + (l->type() == Item::FUNC_ITEM && + ((Item_func *)l)->result_as_longlong())) && + r->result_type() == INT_RESULT)) + /* and must have the same collation if compared as strings */ + && (l->result_type() != STRING_RESULT || + l->collation.collation == r->collation.collation); +} + /* Return 1 if the item is a const value in all the WHERE clause */ @@ -8468,7 +8508,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) Item *right_item= ((Item_func*) cond)->arguments()[1]; if (left_item->eq(comp_item,1)) { - if (right_item->const_item()) + if (test_if_equality_guarantees_uniqueness (left_item, right_item)) { if (*const_item) return right_item->eq(*const_item, 1); @@ -8478,7 +8518,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) } else if (right_item->eq(comp_item,1)) { - if (left_item->const_item()) + if (test_if_equality_guarantees_uniqueness (right_item, left_item)) { if (*const_item) return left_item->eq(*const_item, 1); From 68d6f7ae52f5de3eaeeb6ee76de2f1d0066af19c Mon Sep 17 00:00:00 2001 From: "joerg@trift2." <> Date: Mon, 8 Jan 2007 18:33:55 +0100 Subject: [PATCH 16/27] Changes necessary to build version 4.0.28: - "make_binary_distribution" accepts a dummy "--platform=" argument. - "MySQL-shared-compat.spec" uses a "version40" define symbol internally. --- scripts/make_binary_distribution.sh | 1 + support-files/MySQL-shared-compat.spec.sh | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 5748c024387..cb9e8ecbb91 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -27,6 +27,7 @@ parse_arguments() { --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; --no-strip) STRIP=0 ;; --machine=*) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;; + --platform=*) echo "Ignoring argument '$arg', continuing" ;; --silent) SILENT=1 ;; *) echo "Unknown argument '$arg'" diff --git a/support-files/MySQL-shared-compat.spec.sh b/support-files/MySQL-shared-compat.spec.sh index 068daadab58..d851873e687 100644 --- a/support-files/MySQL-shared-compat.spec.sh +++ b/support-files/MySQL-shared-compat.spec.sh @@ -26,7 +26,7 @@ # # Change this to match the version of the shared libs you want to include # -%define version4 @MYSQL_NO_DASH_VERSION@ +%define version40 @MYSQL_NO_DASH_VERSION@ %define version3 3.23.58 Name: MySQL-shared-compat @@ -36,13 +36,13 @@ License: GPL Group: Applications/Databases URL: http://www.mysql.com/ Autoreqprov: on -Version: %{version4} +Version: %{version40} Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build Obsoletes: MySQL-shared, mysql-shared Provides: MySQL-shared -Summary: MySQL shared libraries for MySQL %{version4} and %{version3} -Source0: MySQL-shared-%{version4}-0.%{_arch}.rpm +Summary: MySQL shared libraries for MySQL %{version40} and %{version3} +Source0: MySQL-shared-%{version40}-0.%{_arch}.rpm Source1: MySQL-shared-%{version3}-1.%{_arch}.rpm # No need to include the RPMs once more - they can be downloaded seperately # if you want to rebuild this package @@ -52,7 +52,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build %description This package includes the shared libraries for both MySQL %{version3} and -MySQL %{version4}. Install this package instead of "MySQL-shared", if you +MySQL %{version40}. Install this package instead of "MySQL-shared", if you have applications installed that are dynamically linked against MySQL 3.23.xx but you want to upgrade to MySQL 4.0.xx without breaking the library dependencies. From 5b4d9d87061e92649ba404a882592c8d96bda141 Mon Sep 17 00:00:00 2001 From: "kroki/tomash@moonlight.home" <> Date: Tue, 9 Jan 2007 12:24:25 +0300 Subject: [PATCH 17/27] BUG#23443: user-defined variables can consume too much memory in the server The problem was that when memory was exhausted HEAP engine could crash (GROUP BY uses HEAP TABLE). Alternatively, if SET was used, it could report an error "You may only use constant expressions with SET" instead of "Out of memory (Needed NNNNNN bytes)". The solution is: - pass MY_WME to (some) calls to my_malloc() to get correct message. - fix heap_write() so that the first key is skipped during cleanup on ENOMEM because it wasn't inserted and doesn't have to be deleted. No test case is provided because we can't test out-of-memory behaviour in our current test framework. --- heap/hp_block.c | 2 +- heap/hp_write.c | 15 ++++++++++++--- sql/item_func.cc | 5 +++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/heap/hp_block.c b/heap/hp_block.c index 5c052218e58..8afcaf8d945 100644 --- a/heap/hp_block.c +++ b/heap/hp_block.c @@ -47,7 +47,7 @@ int _hp_get_new_block(HP_BLOCK *block, ulong *alloc_length) break; *alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer; - if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(0)))) + if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(MY_WME)))) return 1; if (i == 0) diff --git a/heap/hp_write.c b/heap/hp_write.c index 18fa95e7760..b5349d74691 100644 --- a/heap/hp_write.c +++ b/heap/hp_write.c @@ -66,13 +66,22 @@ int heap_write(HP_INFO *info, const byte *record) DBUG_RETURN(0); err: - DBUG_PRINT("info",("Duplicate key: %d",key)); + if (my_errno == HA_ERR_FOUND_DUPP_KEY) + DBUG_PRINT("info",("Duplicate key: %d",key)); info->errkey= key; - do + /* + Because 'key' is unsigned, we increase it before the loop, unless + we have to skip the key that wasn't inserted yet due to OOM. In + the loop we test 'key' before decreasing it as the protection + against value wraparound. + */ + if (my_errno != ENOMEM) + key++; + while (key-- > 0) { if (_hp_delete_key(info,share->keydef+key,record,pos,0)) break; - } while (key-- > 0); + } share->deleted++; *((byte**) pos)=share->del_link; diff --git a/sql/item_func.cc b/sql/item_func.cc index e83d1f35db8..421f72ab69b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1892,8 +1892,9 @@ bool Item_func_set_user_var::update_hash(const void *ptr, uint length, char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); if (entry->value == pos) entry->value=0; - if (!(entry->value=(char*) my_realloc(entry->value, length, - MYF(MY_ALLOW_ZERO_PTR)))) + entry->value= (char*) my_realloc(entry->value, length, + MYF(MY_ALLOW_ZERO_PTR | MY_WME)); + if (!entry->value) goto err; } } From 46a8d14e21887365823977bf631ae2ecb4e8a358 Mon Sep 17 00:00:00 2001 From: "joerg@trift2." <> Date: Tue, 9 Jan 2007 17:21:54 +0100 Subject: [PATCH 18/27] Version 4.0 is in "extended maintenance" by now, and so no future build of it will include Berkeley DB: Remove it from the Windows VC++ project files. --- VC++Files/libmysqld/libmysqld.dsp | 6 +++--- VC++Files/mysql.dsw | 18 ------------------ VC++Files/mysqldemb/mysqldemb.dsp | 10 +++++----- VC++Files/mysqlserver/mysqlserver.dsp | 4 ++-- VC++Files/sql/mysqld.dsp | 12 ++++++------ VC++Files/sql/mysqldmax.dsp | 6 +++--- 6 files changed, 19 insertions(+), 37 deletions(-) diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp index 2d6800de9dc..b5eb0a793c2 100644 --- a/VC++Files/libmysqld/libmysqld.dsp +++ b/VC++Files/libmysqld/libmysqld.dsp @@ -45,7 +45,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBMYSQLD_EXPORTS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FR /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FR /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x416 /d "NDEBUG" @@ -55,7 +55,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=xilink6.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib /nologo /dll /machine:I386 /out:"../lib_release/libmysqld.dll" /implib:"../lib_release/libmysqld.lib" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /dll /machine:I386 /out:"../lib_release/libmysqld.dll" /implib:"../lib_release/libmysqld.lib" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "libmysqld - Win32 Debug" @@ -72,7 +72,7 @@ LINK32=xilink6.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "SAFEMALLOC" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBMYSQLD_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MT /W3 /Z7 /Od /I "../include" /I "../sql" /I "../regex" /I "../bdb/build_win32" /D "WIN32" /D "SAFEMALLOC" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Z7 /Od /I "../include" /I "../sql" /I "../regex" /D "WIN32" /D "SAFEMALLOC" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x416 /d "_DEBUG" diff --git a/VC++Files/mysql.dsw b/VC++Files/mysql.dsw index 6bc9f2e8cb8..a0635447439 100644 --- a/VC++Files/mysql.dsw +++ b/VC++Files/mysql.dsw @@ -18,18 +18,6 @@ Package=<4> ############################################################################### -Project: "bdb"=".\bdb\bdb.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - Project: "comp_err"=".\comp_err\comp_err.dsp" - Package Owner=<4> Package=<5> @@ -143,9 +131,6 @@ Package=<5> Package=<4> {{{ - Begin Project Dependency - Project_Dep_Name bdb - End Project Dependency Begin Project Dependency Project_Dep_Name dbug End Project Dependency @@ -489,9 +474,6 @@ Package=<4> Project_Dep_Name myisammrg End Project Dependency Begin Project Dependency - Project_Dep_Name bdb - End Project Dependency - Begin Project Dependency Project_Dep_Name vio End Project Dependency Begin Project Dependency diff --git a/VC++Files/mysqldemb/mysqldemb.dsp b/VC++Files/mysqldemb/mysqldemb.dsp index 85b9c6ad116..a60d94b25b6 100644 --- a/VC++Files/mysqldemb/mysqldemb.dsp +++ b/VC++Files/mysqldemb/mysqldemb.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Intermediate_Dir "release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG" @@ -67,7 +67,7 @@ LIB32=xilink6.exe -lib # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x416 /d "_DEBUG" # ADD RSC /l 0x416 /d "_DEBUG" @@ -92,7 +92,7 @@ LIB32=xilink6.exe -lib # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_LIB" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "USE_TLS" /D "__WIN__" /D LICENSE=Commercial /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_LIB" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "USE_TLS" /D "__WIN__" /D LICENSE=Commercial /D "DBUG_OFF" /D "_MBCS" /D "NDEBUG" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG" @@ -115,9 +115,9 @@ LIB32=xilink6.exe -lib # PROP Output_Dir "pro" # PROP Intermediate_Dir "pro" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FD /c +# ADD BASE CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /D "NDEBUG" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_LIB" /D "SIGNAL_WITH_VIO_CLOSE" /D "EMBEDDED_LIBRARY" /D "USE_TLS" /D "__WIN__" /D "USE_SYMDIR" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /FD /D MYSQL_SERVER_SUFFIX=-pro /c +# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_LIB" /D "SIGNAL_WITH_VIO_CLOSE" /D "EMBEDDED_LIBRARY" /D "USE_TLS" /D "__WIN__" /D "USE_SYMDIR" /D "MYSQL_SERVER" /D LICENSE=Commercial /D "_MBCS" /D "HAVE_DLOPEN" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "NDEBUG" /D "_WINDOWS" /D "_CONSOLE" /FD /D MYSQL_SERVER_SUFFIX=-pro /c # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG" BSC32=bscmake.exe diff --git a/VC++Files/mysqlserver/mysqlserver.dsp b/VC++Files/mysqlserver/mysqlserver.dsp index 9c23975f5f6..ff0e39e7a60 100644 --- a/VC++Files/mysqlserver/mysqlserver.dsp +++ b/VC++Files/mysqlserver/mysqlserver.dsp @@ -41,7 +41,7 @@ RSC=rc.exe # PROP Intermediate_Dir "release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "NDEBUG" /YX /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "NDEBUG" /YX /FD /c # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG" BSC32=bscmake.exe @@ -64,7 +64,7 @@ LIB32=xilink6.exe -lib # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /I "../sql" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /YX /FD /GZ /c # ADD BASE RSC /l 0x416 /d "_DEBUG" # ADD RSC /l 0x416 /d "_DEBUG" BSC32=bscmake.exe diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index 3198c918a5e..ed35c9aef4e 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -75,7 +75,7 @@ LINK32=xilink6.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /I "../bdb/build_win32" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c +# ADD CPP /nologo /G6 /MTd /W3 /Z7 /Od /I "../include" /I "../regex" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "HAVE_INNOBASE_DB" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /c # SUBTRACT CPP /Fr /YX # ADD BASE RSC /l 0x410 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -84,7 +84,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=xilink6.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\isam.lib ..\lib_debug\merge.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\bdb.lib ..\lib_debug\innodb.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\isam.lib ..\lib_debug\merge.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\innodb.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld.exe" /pdbtype:sept !ELSEIF "$(CFG)" == "mysqld - Win32 nt" @@ -130,7 +130,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../bdb/build_win32" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "_WINDOWS" /D "_CONSOLE" /D "HAVE_DLOPEN" /D "NDEBUG" /D "MYSQL_SERVER" /D "_MBCS" /FD /D MYSQL_SERVER_SUFFIX=-nt-max /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "__NT__" /D "DBUG_OFF" /D "HAVE_INNOBASE_DB" /D "_WINDOWS" /D "_CONSOLE" /D "HAVE_DLOPEN" /D "NDEBUG" /D "MYSQL_SERVER" /D "_MBCS" /FD /D MYSQL_SERVER_SUFFIX=-nt-max /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -140,7 +140,7 @@ BSC32=bscmake.exe LINK32=xilink6.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-nt.exe" # SUBTRACT BASE LINK32 /pdb:none /debug -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-max-nt.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innodb.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-max-nt.exe" # SUBTRACT LINK32 /pdb:none /debug !ELSEIF "$(CFG)" == "mysqld - Win32 Max" @@ -159,7 +159,7 @@ LINK32=xilink6.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /FD /c # SUBTRACT BASE CPP /YX -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /I "../bdb/build_win32" /D "HAVE_INNOBASE_DB" /D "HAVE_BERKELEY_DB" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /D MYSQL_SERVER_SUFFIX=-max /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "HAVE_INNOBASE_DB" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_DLOPEN" /FD /D MYSQL_SERVER_SUFFIX=-max /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -168,7 +168,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=xilink6.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /out:"../client_release/mysqld-opt.exe" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld-max.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld-max.exe" # SUBTRACT LINK32 /debug !ELSEIF "$(CFG)" == "mysqld - Win32 classic" diff --git a/VC++Files/sql/mysqldmax.dsp b/VC++Files/sql/mysqldmax.dsp index 24ea83159d9..1f2354a6661 100644 --- a/VC++Files/sql/mysqldmax.dsp +++ b/VC++Files/sql/mysqldmax.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_INNOBASE_DB" /FD /c # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../regex" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FR /FD /c +# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../regex" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_INNOBASE_DB" /FR /FD /c # ADD BASE RSC /l 0x416 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -92,7 +92,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_BERKELEY_DB" /D "HAVE_INNOBASE_DB" /FD /c +# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../regex" /D "NDEBUG" /D "__NT__" /D "DBUG_OFF" /D "MYSQL_SERVER" /D "_WINDOWS" /D "_CONSOLE" /D "_MBCS" /D "HAVE_INNOBASE_DB" /FD /c # ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe From ac48c8bae1159e8a24a7695e86f19d9f9a89d796 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 9 Jan 2007 22:35:30 +0300 Subject: [PATCH 19/27] Bug#14171: Wrong internal default value for a BINARY field. A BINARY field is represented by the Field_string class. The space character is used as the filler for unused characters in such a field. But a BINARY field should use \x00 instead. Field_string:reset() now detects whether the current field is a BINARY one and if so uses the \x00 character as a default value filler. --- mysql-test/r/type_binary.result | 9 +++++++++ mysql-test/t/type_binary.test | 8 ++++++++ sql/field.h | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_binary.result b/mysql-test/r/type_binary.result index 597defb7a9b..debf4ff8fb8 100644 --- a/mysql-test/r/type_binary.result +++ b/mysql-test/r/type_binary.result @@ -136,4 +136,13 @@ insert into t1 values(NULL, 0x412020); ERROR 22001: Data too long for column 'vb' at row 1 drop table t1; set @@sql_mode= @old_sql_mode; +create table t1(f1 int, f2 binary(2) not null, f3 char(2) not null); +insert into t1 set f1=1; +Warnings: +Warning 1364 Field 'f2' doesn't have a default value +Warning 1364 Field 'f3' doesn't have a default value +select hex(f2), hex(f3) from t1; +hex(f2) hex(f3) +0000 +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/type_binary.test b/mysql-test/t/type_binary.test index 1639aff4711..91eba9b328e 100644 --- a/mysql-test/t/type_binary.test +++ b/mysql-test/t/type_binary.test @@ -91,4 +91,12 @@ insert into t1 values(NULL, 0x412020); drop table t1; set @@sql_mode= @old_sql_mode; +# +# Bug#14171: Wrong default value for a BINARY field +# +create table t1(f1 int, f2 binary(2) not null, f3 char(2) not null); +insert into t1 set f1=1; +select hex(f2), hex(f3) from t1; +drop table t1; + --echo End of 5.0 tests diff --git a/sql/field.h b/sql/field.h index d4bcdf556cf..103b596ae77 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1034,7 +1034,8 @@ public: bool zero_pack() const { return 0; } int reset(void) { - charset()->cset->fill(charset(),ptr,field_length,' '); + charset()->cset->fill(charset(),ptr,field_length, + (has_charset() ? ' ' : 0)); return 0; } int store(const char *to,uint length,CHARSET_INFO *charset); From e098f736e1adc97aa2d4a5ed5bf07c5c94d15399 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 9 Jan 2007 23:24:56 +0300 Subject: [PATCH 20/27] Fixed bug#16861: User defined variable can have a wrong value if a tmp table was used. The Item::save_in_field() function is called from fill_record() to fill the new row with data while execution of the CREATE TABLE ... SELECT statement. Item::save_in_field() calls val_xxx() methods in order to get values. val_xxx() methods do not take into account the result field. Due to this Item_func_set_user_var::val_xxx() methods returns values from the original table, not from the temporary one. The save_in_field() member function is added to the Item_func_set_user_var class. It detects whether the result field should be used and properly updates the value of the user variable. --- mysql-test/r/user_var.result | 9 +++- mysql-test/t/user_var.test | 5 +- sql/item_func.cc | 99 ++++++++++++++++++++++++++++++++++++ sql/item_func.h | 1 + 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 90954fc1ede..753c982155c 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -301,7 +301,14 @@ select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; @var 3 -drop table t1; +create table t2 as select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +select * from t2; +@var:=f2 +3 +select @var; +@var +3 +drop table t1,t2; insert into city 'blah'; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''blah'' at line 1 SHOW COUNT(*) WARNINGS; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 65ca1b2c1b7..70f57fdf283 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -210,7 +210,10 @@ create table t1(f1 int, f2 int); insert into t1 values (1,2),(2,3),(3,1); select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; -drop table t1; +create table t2 as select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +select * from t2; +select @var; +drop table t1,t2; # # Bug#19024 - SHOW COUNT(*) WARNINGS not return Errors diff --git a/sql/item_func.cc b/sql/item_func.cc index 0eab370237d..4138573785e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4056,6 +4056,105 @@ void Item_func_set_user_var::make_field(Send_field *tmp_field) Item::make_field(tmp_field); } + +/* + Save the value of a user variable into a field + + SYNOPSIS + save_in_field() + field target field to save the value to + no_conversion flag indicating whether conversions are allowed + + DESCRIPTION + Save the function value into a field and update the user variable + accordingly. If a result field is defined and the target field doesn't + coincide with it then the value from the result field will be used as + the new value of the user variable. + + The reason to have this method rather than simply using the result + field in the val_xxx() methods is that the value from the result field + not always can be used when the result field is defined. + Let's consider the following cases: + 1) when filling a tmp table the result field is defined but the value of it + is undefined because it has to be produced yet. Thus we can't use it. + 2) on execution of an INSERT ... SELECT statement the save_in_field() + function will be called to fill the data in the new record. If the SELECT + part uses a tmp table then the result field is defined and should be + used in order to get the correct result. + + The difference between the SET_USER_VAR function and regular functions + like CONCAT is that the Item_func objects for the regular functions are + replaced by Item_field objects after the values of these functions have + been stored in a tmp table. Yet an object of the Item_field class cannot + be used to update a user variable. + Due to this we have to handle the result field in a special way here and + in the Item_func_set_user_var::send() function. + + RETURN VALUES + FALSE Ok + TRUE Error +*/ + +int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions) +{ + bool use_result_field= (result_field && result_field != field); + int error; + + /* Update the value of the user variable */ + check(use_result_field); + update(); + + if (result_type() == STRING_RESULT || + result_type() == REAL_RESULT && + field->result_type() == STRING_RESULT) + { + String *result; + CHARSET_INFO *cs= collation.collation; + char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns + str_value.set_quick(buff, sizeof(buff), cs); + result= entry->val_str(&null_value, &str_value, decimals); + + if (null_value) + { + str_value.set_quick(0, 0, cs); + return set_field_to_null_with_conversions(field, no_conversions); + } + + /* NOTE: If null_value == FALSE, "result" must be not NULL. */ + + field->set_notnull(); + error=field->store(result->ptr(),result->length(),cs); + str_value.set_quick(0, 0, cs); + } + else if (result_type() == REAL_RESULT) + { + double nr= entry->val_real(&null_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store(nr); + } + else if (result_type() == DECIMAL_RESULT) + { + my_decimal decimal_value; + my_decimal *value= entry->val_decimal(&null_value, &decimal_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store_decimal(value); + } + else + { + longlong nr= entry->val_int(&null_value); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + error=field->store(nr, unsigned_flag); + } + return error; +} + + String * Item_func_get_user_var::val_str(String *str) { diff --git a/sql/item_func.h b/sql/item_func.h index c116c18bc50..68591f9c6f5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1188,6 +1188,7 @@ public: void print(String *str); void print_as_stmt(String *str); const char *func_name() const { return "set_user_var"; } + int save_in_field(Field *field, bool no_conversions); }; From 578fae9dc85940f42658e6dd5111f66855d296e0 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Wed, 10 Jan 2007 00:27:11 -0800 Subject: [PATCH 21/27] Fixed bug #25427. In the method Item_field::fix_fields we try to resolve the name of the field against the names of the aliases that occur in the select list. This is done by a call of the function find_item_in_list. When this function finds several occurrences of the field name it sends an error message to the error queue and returns 0. Yet the code did not take into account that find_item_in_list could return 0 and tried to dereference the returned value. --- mysql-test/r/order_by.result | 8 ++++++++ mysql-test/t/order_by.test | 15 +++++++++++++++ sql/item.cc | 2 ++ 3 files changed, 25 insertions(+) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 320bb89b62e..ec6032be882 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -847,3 +847,11 @@ num (select num + 2 FROM t1 LIMIT 1) SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; ERROR 42S22: Unknown column 'num' in 'on clause' DROP TABLE t1; +CREATE TABLE t1 (a int); +SELECT p.a AS val, q.a AS val1 FROM t1 p, t1 q ORDER BY val > 1; +val val1 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val; +ERROR 23000: Column 'val' in order clause is ambiguous +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val > 1; +ERROR 23000: Column 'val' in order clause is ambiguous +DROP TABLE t1; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index a8024be7032..3c23ea76d99 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -575,4 +575,19 @@ SELECT a + 1 AS num, (select num + 2 FROM t1 LIMIT 1) FROM t1; SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; DROP TABLE t1; +# +# Bug #25427: crash when order by expression contains a name +# that cannot be resolved unambiguously +# + +CREATE TABLE t1 (a int); + +SELECT p.a AS val, q.a AS val1 FROM t1 p, t1 q ORDER BY val > 1; +--error 1052 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val; +--error 1052 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val > 1; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item.cc b/sql/item.cc index 45d7856b2c1..1e8c70c6616 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1761,6 +1761,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); + if (!res) + return 1; if (res != (Item **)not_found_item) { if ((*res)->type() == Item::FIELD_ITEM) From b61f3545f532595783f88330e6d55f6ab27edb86 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Wed, 10 Jan 2007 12:57:03 +0400 Subject: [PATCH 22/27] Fix for bug#20867 InnoDB Bug - create temporary table+crash => mysqld needs to clean up 2nd version During tmp tables cleanup we get the handler for temporary table and delete table using handler method. --- sql/mysql_priv.h | 1 + sql/mysqld.cc | 2 +- sql/sql_base.cc | 42 +++++++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8d6cdebe1f7..a12944437d7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -861,6 +861,7 @@ bool open_log(MYSQL_LOG *log, const char *hostname, /* mysqld.cc */ extern void yyerror(const char*); +my_bool mysql_rm_tmp_tables(void); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cd0ddc00624..024e4682a22 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3241,7 +3241,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); */ error_handler_hook = my_message_sql; start_signal_handler(); // Creates pidfile - if (acl_init(opt_noacl) || + if (mysql_rm_tmp_tables() || acl_init(opt_noacl) || my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { abort_loop=1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c60bed09cf9..05ecfe9b484 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -34,7 +34,6 @@ HASH assign_cache; static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, const char *name, const char *alias); static void free_cache_entry(TABLE *entry); -static void mysql_rm_tmp_tables(void); extern "C" byte *table_cache_key(const byte *record,uint *length, @@ -47,7 +46,6 @@ extern "C" byte *table_cache_key(const byte *record,uint *length, bool table_cache_init(void) { - mysql_rm_tmp_tables(); return hash_init(&open_cache, &my_charset_bin, table_cache_size+16, 0, 0,table_cache_key, (hash_free_key) free_cache_entry, 0) != 0; @@ -2940,14 +2938,20 @@ fill_record(Field **ptr,List &values, bool ignore_errors) } -static void mysql_rm_tmp_tables(void) +my_bool mysql_rm_tmp_tables(void) { uint i, idx; - char filePath[FN_REFLEN], *tmpdir; + char filePath[FN_REFLEN], *tmpdir, filePathCopy[FN_REFLEN]; MY_DIR *dirp; FILEINFO *file; + TABLE tmp_table; + THD *thd; DBUG_ENTER("mysql_rm_tmp_tables"); + if (!(thd= new THD)) + DBUG_RETURN(1); + thd->store_globals(); + for (i=0; i<=mysql_tmpdir_list.max; i++) { tmpdir=mysql_tmpdir_list.list[i]; @@ -2968,13 +2972,37 @@ static void mysql_rm_tmp_tables(void) if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length)) { - sprintf(filePath,"%s%s",tmpdir,file->name); - VOID(my_delete(filePath,MYF(MY_WME))); + char *ext= fn_ext(file->name); + uint ext_len= strlen(ext); + uint filePath_len= my_snprintf(filePath, sizeof(filePath), + "%s%s", tmpdir, file->name); + if (!bcmp(reg_ext, ext, ext_len)) + { + TABLE tmp_table; + if (!openfrm(filePath, "tmp_table", (uint) 0, + READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, + 0, &tmp_table)) + { + /* We should cut file extention before deleting of table */ + memcpy(filePathCopy, filePath, filePath_len - ext_len); + filePathCopy[filePath_len - ext_len]= 0; + tmp_table.file->delete_table(filePathCopy); + closefrm(&tmp_table); + } + } + /* + File can be already deleted by tmp_table.file->delete_table(). + So we hide error messages which happnes during deleting of these + files(MYF(0)). + */ + VOID(my_delete(filePath, MYF(0))); } } my_dirend(dirp); } - DBUG_VOID_RETURN; + delete thd; + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(0); } From 4a3fe2b6826749ec3981f5778399a0352390b560 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Wed, 10 Jan 2007 14:03:36 +0400 Subject: [PATCH 23/27] after merge fix --- sql/sql_base.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6e93245c95f..5dcd596f6c2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5167,6 +5167,7 @@ my_bool mysql_rm_tmp_tables(void) if (!(thd= new THD)) DBUG_RETURN(1); + thd->thread_stack= (char*) &thd; thd->store_globals(); for (i=0; i<=mysql_tmpdir_list.max; i++) @@ -5196,7 +5197,7 @@ my_bool mysql_rm_tmp_tables(void) if (!bcmp(reg_ext, ext, ext_len)) { TABLE tmp_table; - if (!openfrm(filePath, "tmp_table", (uint) 0, + if (!openfrm(thd, filePath, "tmp_table", (uint) 0, READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, 0, &tmp_table)) { From bd2ec8051dc5d3841e2166f5ddc589b112dcdb41 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Thu, 11 Jan 2007 12:31:52 +0100 Subject: [PATCH 24/27] Many files: Reverted change for bug#13859, applied smaller patch from Marko --- innobase/buf/buf0buf.c | 2 +- innobase/dict/dict0dict.c | 6 +++--- innobase/fil/fil0fil.c | 4 ++-- innobase/ha/ha0ha.c | 2 +- innobase/ha/hash0hash.c | 2 +- innobase/include/hash0hash.h | 5 ++++- innobase/lock/lock0lock.c | 2 +- innobase/log/log0recv.c | 4 ++-- innobase/thr/thr0loc.c | 2 +- 9 files changed, 16 insertions(+), 13 deletions(-) diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 704b8e0a5c7..31a581d2ba8 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -621,7 +621,7 @@ buf_pool_init( } } - buf_pool->page_hash = hash0_create(2 * max_size); + buf_pool->page_hash = hash_create(2 * max_size); buf_pool->n_pend_reads = 0; diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 5e55a44ce56..4b23ce047b2 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -703,13 +703,13 @@ dict_init(void) mutex_create(&(dict_sys->mutex)); mutex_set_level(&(dict_sys->mutex), SYNC_DICT); - dict_sys->table_hash = hash0_create(buf_pool_get_max_size() / + dict_sys->table_hash = hash_create(buf_pool_get_max_size() / (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE)); - dict_sys->table_id_hash = hash0_create(buf_pool_get_max_size() / + dict_sys->table_id_hash = hash_create(buf_pool_get_max_size() / (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE)); - dict_sys->col_hash = hash0_create(buf_pool_get_max_size() / + dict_sys->col_hash = hash_create(buf_pool_get_max_size() / (DICT_POOL_PER_COL_HASH * UNIV_WORD_SIZE)); dict_sys->size = 0; diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 269c25833a4..b576e4f5a70 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -1295,8 +1295,8 @@ fil_system_create( mutex_set_level(&(system->mutex), SYNC_ANY_LATCH); - system->spaces = hash0_create(hash_size); - system->name_hash = hash0_create(hash_size); + system->spaces = hash_create(hash_size); + system->name_hash = hash_create(hash_size); UT_LIST_INIT(system->LRU); diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index a64fb13a5bb..ad1391ff83e 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -32,7 +32,7 @@ ha_create( hash_table_t* table; ulint i; - table = hash0_create(n); + table = hash_create(n); if (in_btr_search) { table->adaptive = TRUE; diff --git a/innobase/ha/hash0hash.c b/innobase/ha/hash0hash.c index 18b5b3cefd6..facdea66198 100644 --- a/innobase/ha/hash0hash.c +++ b/innobase/ha/hash0hash.c @@ -74,7 +74,7 @@ Creates a hash table with >= n array cells. The actual number of cells is chosen to be a prime number slightly bigger than n. */ hash_table_t* -hash0_create( +hash_create( /*========*/ /* out, own: created table */ ulint n) /* in: number of array cells */ diff --git a/innobase/include/hash0hash.h b/innobase/include/hash0hash.h index 3abc05f174c..13f46760698 100644 --- a/innobase/include/hash0hash.h +++ b/innobase/include/hash0hash.h @@ -18,12 +18,15 @@ typedef struct hash_cell_struct hash_cell_t; typedef void* hash_node_t; +/* Fix Bug #13859: symbol collision between imap/mysql */ +#define hash_create hash0_create + /***************************************************************** Creates a hash table with >= n array cells. The actual number of cells is chosen to be a prime number slightly bigger than n. */ hash_table_t* -hash0_create( +hash_create( /*========*/ /* out, own: created table */ ulint n); /* in: number of array cells */ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 19a285ed3f3..1c08d3defaa 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -550,7 +550,7 @@ lock_sys_create( { lock_sys = mem_alloc(sizeof(lock_sys_t)); - lock_sys->rec_hash = hash0_create(n_cells); + lock_sys->rec_hash = hash_create(n_cells); /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */ diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 37d9f5883b2..ddb33de6fa6 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -147,7 +147,7 @@ recv_sys_init( recv_sys->len = 0; recv_sys->recovered_offset = 0; - recv_sys->addr_hash = hash0_create(available_memory / 64); + recv_sys->addr_hash = hash_create(available_memory / 64); recv_sys->n_addrs = 0; recv_sys->apply_log_recs = FALSE; @@ -186,7 +186,7 @@ recv_sys_empty_hash(void) hash_table_free(recv_sys->addr_hash); mem_heap_empty(recv_sys->heap); - recv_sys->addr_hash = hash0_create(buf_pool_get_curr_size() / 256); + recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 256); } /************************************************************ diff --git a/innobase/thr/thr0loc.c b/innobase/thr/thr0loc.c index f71048af2ba..033bb22807f 100644 --- a/innobase/thr/thr0loc.c +++ b/innobase/thr/thr0loc.c @@ -224,7 +224,7 @@ thr_local_init(void) ut_a(thr_local_hash == NULL); - thr_local_hash = hash0_create(OS_THREAD_MAX_N + 100); + thr_local_hash = hash_create(OS_THREAD_MAX_N + 100); mutex_create(&thr_local_mutex); mutex_set_level(&thr_local_mutex, SYNC_THR_LOCAL); From 15bcf131825c64910e98c8238fa7b865c9f6e4fa Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Thu, 11 Jan 2007 19:10:01 +0200 Subject: [PATCH 25/27] BUG#25106: A USING clause in combination with a VIEW results in column aliases ignored When a column reference to a column in JOIN USING is resolved and a new Item is created for this column the user defined name was lost. This fix preserves the alias by setting the name of the new Item to the original alias. --- mysql-test/r/join.result | 16 ++++++++++++++++ mysql-test/t/join.test | 20 ++++++++++++++++++++ sql/sql_base.cc | 13 +++++++++++++ 3 files changed, 49 insertions(+) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 8ad6f344c4f..f3114dc55dd 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -764,3 +764,19 @@ natural join t5; y c b a z 1 3 2 1 4 drop table t1, t2, t3, t4, t5; +CREATE TABLE t1 (ID INTEGER, Name VARCHAR(50)); +CREATE TABLE t2 (Test_ID INTEGER); +CREATE VIEW v1 (Test_ID, Description) AS SELECT ID, Name FROM t1; +CREATE TABLE tv1 SELECT Description AS Name FROM v1 JOIN t2 +USING (Test_ID); +DESCRIBE tv1; +Field Type Null Key Default Extra +Name varchar(50) YES NULL +CREATE TABLE tv2 SELECT Description AS Name FROM v1 JOIN t2 +ON v1.Test_ID = t2.Test_ID; +DESCRIBE tv2; +Field Type Null Key Default Extra +Name varchar(50) YES NULL +DROP VIEW v1; +DROP TABLE t1,t2,tv1,tv2; +End of 5.0 tests. diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index ab85cc5bed2..99dd21e8ee2 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -591,3 +591,23 @@ select * from ((t3 natural join (t1 natural join t2)) natural join t4) drop table t1, t2, t3, t4, t5; # End of tests for WL#2486 - natural/using join + +# +# BUG#25106: A USING clause in combination with a VIEW results in column +# aliases ignored +# +CREATE TABLE t1 (ID INTEGER, Name VARCHAR(50)); +CREATE TABLE t2 (Test_ID INTEGER); +CREATE VIEW v1 (Test_ID, Description) AS SELECT ID, Name FROM t1; + +CREATE TABLE tv1 SELECT Description AS Name FROM v1 JOIN t2 + USING (Test_ID); +DESCRIBE tv1; +CREATE TABLE tv2 SELECT Description AS Name FROM v1 JOIN t2 + ON v1.Test_ID = t2.Test_ID; +DESCRIBE tv2; + +DROP VIEW v1; +DROP TABLE t1,t2,tv1,tv2; + +--echo End of 5.0 tests. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c5a9fad333d..bbae916d5c1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2977,6 +2977,19 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, column reference. See create_view_field() for details. */ item= nj_col->create_item(thd); + /* + *ref != NULL means that *ref contains the item that we need to + replace. If the item was aliased by the user, set the alias to + the replacing item. + We need to set alias on both ref itself and on ref real item. + */ + if (*ref && !(*ref)->is_autogenerated_name) + { + item->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + item->real_item()->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + } if (register_tree_change && arena) thd->restore_active_arena(arena, &backup); From 86890b89190181aff4b58c4110584f29ffaccf75 Mon Sep 17 00:00:00 2001 From: "mmj@tiger.mmj.dk" <> Date: Fri, 12 Jan 2007 01:04:39 +0100 Subject: [PATCH 26/27] mysql_explain_log.sh: Patch from Paul DuBois for better help messages --- scripts/mysql_explain_log.sh | 106 ++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/scripts/mysql_explain_log.sh b/scripts/mysql_explain_log.sh index ad23a42451f..a549817db5a 100644 --- a/scripts/mysql_explain_log.sh +++ b/scripts/mysql_explain_log.sh @@ -21,9 +21,6 @@ use DBI; use Getopt::Long; $Getopt::Long::ignorecase=0; -print "explain_log provided by http://www.mobile.de\n"; -print "=========== ================================\n"; - my $Param={}; $Param->{host}=''; @@ -32,16 +29,28 @@ $Param->{password}=''; $Param->{PrintError}=0; $Param->{socket}=''; -if (!GetOptions ('date|d:i' => \$Param->{ViewDate}, +my $help; + +if (!GetOptions ( + 'date|d:i' => \$Param->{ViewDate}, 'host|h:s' => \$Param->{host}, 'user|u:s' => \$Param->{user}, 'password|p:s' => \$Param->{password}, 'printerror|e:s' => \$Param->{PrintError}, 'socket|s:s' => \$Param->{socket}, + 'help|h' => \$help, )) { ShowOptions(); + exit(0); } -else { +if (defined ($help)) { + ShowOptions(); + exit(0); +} + + print "explain_log provided by http://www.mobile.de\n"; + print "=========== ================================\n"; + $Param->{UpdateCount} = 0; $Param->{SelectCount} = 0; $Param->{IdxUseCount} = 0; @@ -245,7 +254,6 @@ else { print "Finished: \t".localtime(time)."\n"; } -} ########################################################################### @@ -323,21 +331,26 @@ sub ShowOptions { print < Date: Mon, 15 Jan 2007 16:57:22 +0100 Subject: [PATCH 27/27] Raise version number after cloning 5.0.34 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 493fe8f174f..94bc85557df 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.34) +AM_INIT_AUTOMAKE(mysql, 5.0.36) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=34 +NDB_VERSION_BUILD=36 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ?