From 516699af2372f216b612c18c4c5657d31a909b2e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Oct 2005 10:52:34 +0200 Subject: [PATCH 01/48] Fix for BUG#4544 "read_only also affects temporary tables": the READ_ONLY global variable now allows statements which are to update only temporary tables (note: if a statement, after parse stage, looks like it will update a non-temp table, it will be rejected, even if at execution it would have turned out that 0 rows would be updated; for example UPDATE my_non_tem_table SET a=1 WHERE 1 = 0; will be rejected). sql/sql_parse.cc: The READ_ONLY global variable now allows statements which are to update only temporary tables (note: if a statement, after parse stage, looks like it will update a non-temp table, it will be rejected, even if at execution it would have turned out that 0 rows would be updated; for example UPDATE my_non_tem_table SET a=1 WHERE 1 = 0; will be rejected). mysql-test/r/read_only.result: result for new test mysql-test/t/read_only.test: test for READ_ONLY (there was none!) and for the new behaviour of READ_ONLY --- mysql-test/r/read_only.result | 41 ++++++++++++++ mysql-test/t/read_only.test | 103 ++++++++++++++++++++++++++++++++++ sql/sql_parse.cc | 47 ++++++++++++---- 3 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 mysql-test/r/read_only.result create mode 100644 mysql-test/t/read_only.test diff --git a/mysql-test/r/read_only.result b/mysql-test/r/read_only.result new file mode 100644 index 00000000000..09a0861e0c4 --- /dev/null +++ b/mysql-test/r/read_only.result @@ -0,0 +1,41 @@ +DROP TABLE IF EXISTS t1,t2,t3; +grant CREATE, SELECT, DROP on *.* to test@localhost; +set global read_only=0; +create table t1 (a int); +insert into t1 values(1); +create table t2 select * from t1; +set global read_only=1; +create table t3 (a int); +drop table t3; +select @@global.read_only; +@@global.read_only +1 +create table t3 (a int); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t1,t2 from t1,t2 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +create temporary table t3 (a int); +create temporary table t4 (a int) select * from t3; +insert into t3 values(1); +insert into t4 select * from t3; +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t3 from t1,t3 where t1.a=t3.a; +delete t4 from t3,t4 where t4.a=t3.a; +create temporary table t1 (a int); +insert into t1 values(1); +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +drop table t1; +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +drop table t1,t2; +drop user test@localhost; diff --git a/mysql-test/t/read_only.test b/mysql-test/t/read_only.test new file mode 100644 index 00000000000..0861951a6a1 --- /dev/null +++ b/mysql-test/t/read_only.test @@ -0,0 +1,103 @@ +# Test of the READ_ONLY global variable: +# check that it blocks updates unless they are only on temporary tables. + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings + +# READ_ONLY does nothing to SUPER users +# so we use a non-SUPER one: + +grant CREATE, SELECT, DROP on *.* to test@localhost; + +connect (con1,localhost,test,,test); + +connection default; + +set global read_only=0; + +connection con1; + +create table t1 (a int); + +insert into t1 values(1); + +create table t2 select * from t1; + +connection default; + +set global read_only=1; + +# We check that SUPER can: + +create table t3 (a int); +drop table t3; + +connection con1; + +select @@global.read_only; + +--error 1290 +create table t3 (a int); + +--error 1290 +insert into t1 values(1); + +# if a statement, after parse stage, looks like it will update a +# non-temp table, it will be rejected, even if at execution it would +# have turned out that 0 rows would be updated +--error 1290 +update t1 set a=1 where 1=0; + +# multi-update is special (see sql_parse.cc) so we test it +--error 1290 +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; + +# check multi-delete to be sure +--error 1290 +delete t1,t2 from t1,t2 where t1.a=t2.a; + +# With temp tables updates should be accepted: + +create temporary table t3 (a int); + +create temporary table t4 (a int) select * from t3; + +insert into t3 values(1); + +insert into t4 select * from t3; + +# a non-temp table updated: +--error 1290 +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +# no non-temp table updated (just swapped): +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; + +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; + +--error 1290 +delete t1 from t1,t3 where t1.a=t3.a; + +delete t3 from t1,t3 where t1.a=t3.a; + +delete t4 from t3,t4 where t4.a=t3.a; + +# and even homonymous ones + +create temporary table t1 (a int); + +insert into t1 values(1); + +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +delete t1 from t1,t3 where t1.a=t3.a; + +drop table t1; + +--error 1290 +insert into t1 values(1); + +connection default; +drop table t1,t2; +drop user test@localhost; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4d9fddec770..b6865fdebd0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -194,6 +194,18 @@ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) #endif +static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_global) + { + DBUG_ASSERT(table->db && table->table_name); + if (table->updating && + !find_temporary_table(thd, table->db, table->table_name)) + return 1; + } + return 0; +} + static HASH hash_user_connections; static int get_or_create_user_conn(THD *thd, const char *user, @@ -2363,7 +2375,7 @@ mysql_execute_command(THD *thd) mysql_reset_errors(thd, 0); #ifdef HAVE_REPLICATION - if (thd->slave_thread) + if (unlikely(thd->slave_thread)) { /* Check if statment should be skipped because of slave filtering @@ -2402,16 +2414,20 @@ mysql_execute_command(THD *thd) } #endif } + else #endif /* HAVE_REPLICATION */ /* - When option readonly is set deny operations which change tables. - Except for the replication thread and the 'super' users. + When option readonly is set deny operations which change non-temporary + tables. Except for the replication thread and the 'super' users. */ if (opt_readonly && - !(thd->slave_thread || - (thd->security_ctx->master_access & SUPER_ACL)) && - uc_update_queries[lex->sql_command]) + !(thd->security_ctx->master_access & SUPER_ACL) && + uc_update_queries[lex->sql_command] && + !((lex->sql_command == SQLCOM_CREATE_TABLE) && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && + ((lex->sql_command != SQLCOM_UPDATE_MULTI) && + some_non_temp_table_to_be_updated(thd, all_tables))) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); DBUG_RETURN(-1); @@ -3210,13 +3226,24 @@ end_with_restore_list: #ifdef HAVE_REPLICATION /* Check slave filtering rules */ - if (thd->slave_thread && all_tables_not_ok(thd, all_tables)) + if (unlikely(thd->slave_thread)) { - /* we warn the slave SQL thread */ - my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + if (all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + break; + } + } + else +#endif /* HAVE_REPLICATION */ + if (opt_readonly && + !(thd->security_ctx->master_access & SUPER_ACL) && + some_non_temp_table_to_be_updated(thd, all_tables)) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); break; } -#endif /* HAVE_REPLICATION */ res= mysql_multi_update(thd, all_tables, &select_lex->item_list, From 2b7f5a45e96413f88ba93ebd85971a3b82cbeb7c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Oct 2005 19:28:27 +0400 Subject: [PATCH 02/48] BUG#13126: When choosing join order for join with nested joins, don't produce join orders that cannot be handled by the executioner. mysql-test/r/bigint.result: Added mssing "drop table if exists" mysql-test/r/join_nested.result: Testcase for BUG#13126 mysql-test/t/bigint.test: Added mssing "drop table if exists" mysql-test/t/join_nested.test: Testcase for BUG#13126 sql/mysql_priv.h: BUG#13126: Added nested_join_map type. sql/sql_prepare.cc: BUG#13126: Don't set NESTED_JOIN::counter to 0 here as it is reset in other place now. sql/sql_select.cc: BUG#13126: When choosing join order for join with nested joins, don't produce join orders that the executioner cannot handle. The work is done by check_interleaving_with_nj() and restore_prev_nj_state() functions that are used from the join optimizer to avoid building invalid join orders. sql/sql_select.h: BUG#13126: Added JOIN_TAB::embedding_map and JOIN::cur_embedding_map. sql/table.h: BUG#13126: In NESTED_JOIN: added nj_map, added comment about where counter is used. --- mysql-test/r/bigint.result | 2 +- mysql-test/r/join_nested.result | 64 ++++++++ mysql-test/t/bigint.test | 2 +- mysql-test/t/join_nested.test | 68 +++++++++ sql/mysql_priv.h | 5 + sql/sql_prepare.cc | 2 - sql/sql_select.cc | 250 ++++++++++++++++++++++++++++++-- sql/sql_select.h | 11 +- sql/table.h | 10 +- 9 files changed, 397 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index ca9a2662f94..84779858b75 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1, t2; select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296; 0 256 00000000000000065536 2147483647 -2147483648 2147483648 4294967296 0 256 65536 2147483647 -2147483648 2147483648 4294967296 diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 9d514be76e8..c4dd6cf9a86 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1403,3 +1403,67 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); ERROR 42S22: Unknown column 'v2.x' in 'field list' DROP VIEW v1, v2; DROP TABLE t1, t2, t3, t4, t5, t6; +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); +create table t4 (id2 int(11) not null, id3 char(16)); +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); +create view v1 as +select t4.id3 from t4 join t2 on t4.id2 = t2.id2; +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); +id1 +1 +2 +drop view v1; +drop table t1, t2, t3, t4, t5; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; +explain select * from t4 join +t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +1 SIMPLE t4 ref a a 5 test.t3.b X Using where +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b +join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X Using where +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t2.b X +1 SIMPLE t7 ref a a 5 test.t5.b X +explain select * from t2 left join +(t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b +join t5 on t5.a=t3.b) on t3.a=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +drop table t0, t1, t2, t4, t5, t6; diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index d9c1abd9ba9..7871b3647e3 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -2,7 +2,7 @@ # Initialize --disable_warnings -drop table if exists t1; +drop table if exists t1, t2; --enable_warnings # diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 0592ec3152f..9dbf153ec55 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -832,3 +832,71 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); DROP VIEW v1, v2; DROP TABLE t1, t2, t3, t4, t5, t6; + +# +# BUG#13126 -test case from bug report +# +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); + +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); + +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); + +create table t4 (id2 int(11) not null, id3 char(16)); + +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); + +create view v1 as + select t4.id3 from t4 join t2 on t4.id2 = t2.id2; + +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); + +drop view v1; +drop table t1, t2, t3, t4, t5; + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; + +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); + +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; + +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; + +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; + +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; + +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; + +--replace_column 9 X +explain select * from t4 join + t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; + +--replace_column 9 X +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b + join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; + +--replace_column 9 X +explain select * from t2 left join + (t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b + join t5 on t5.a=t3.b) on t3.a=t2.b; + +drop table t0, t1, t2, t4, t5, t6; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 19ebceab719..198a90dbd8a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -44,6 +44,11 @@ typedef ulonglong table_map; /* Used for table bits in join */ typedef Bitmap<64> key_map; /* Used for finding keys */ typedef ulong key_part_map; /* Used for finding key parts */ +/* + Used for nested join bits within a scope of a join (applicable to non-unary + nested joins that have not been simplified away) +*/ +typedef ulonglong nested_join_map; /* query_id */ typedef ulonglong query_id_t; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5f3539ca1e9..bf74dd99a68 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2105,8 +2105,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) were closed in the end of previous prepare or execute call. */ tables->table= 0; - if (tables->nested_join) - tables->nested_join->counter= 0; if (tables->prep_on_expr) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 806a6d3ea32..a74e01b866b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -98,6 +98,12 @@ static COND* substitute_for_best_equal_field(COND *cond, void *table_join_idx); static COND *simplify_joins(JOIN *join, List *join_list, COND *conds, bool top); +static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next); +static void restore_prev_nj_state(JOIN_TAB *last); +static void reset_nj_counters(List *join_list); +static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, + uint first_unused); + static COND *optimize_cond(JOIN *join, COND *conds, List *join_list, Item::cond_result *cond_value); @@ -522,12 +528,14 @@ bool JOIN::test_in_subselect(Item **where) return 0; } + /* global select optimisation. return 0 - success 1 - error error code saved in field 'error' */ + int JOIN::optimize() { @@ -587,6 +595,7 @@ JOIN::optimize() /* Convert all outer joins to inner joins if possible */ conds= simplify_joins(this, join_list, conds, TRUE); + build_nj_bitmap_for_tables(this, join_list, 0); sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; @@ -699,7 +708,8 @@ JOIN::optimize() DBUG_PRINT("error",("Error: make_select() failed")); DBUG_RETURN(1); } - + + reset_nj_counters(join_list); make_outerjoin_info(this); /* @@ -1961,14 +1971,19 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, continue; } outer_join|= table->map; + s->embedding_map= 0; + for (;embedding; embedding= embedding->embedding) + s->embedding_map|= embedding->nested_join->nj_map; continue; } if (embedding) { /* s belongs to a nested join, maybe to several embedded joins */ + s->embedding_map= 0; do { NESTED_JOIN *nested_join= embedding->nested_join; + s->embedding_map|=nested_join->nj_map; s->dependent|= embedding->dep_tables; embedding= embedding->embedding; outer_join|= nested_join->used_tables; @@ -3542,6 +3557,8 @@ choose_plan(JOIN *join, table_map join_tables) bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN; DBUG_ENTER("choose_plan"); + join->cur_embedding_map= 0; + reset_nj_counters(join->join_list); /* if (SELECT_STRAIGHT_JOIN option is set) reorder tables so dependent tables come after tables they depend @@ -4022,7 +4039,9 @@ best_extension_by_limited_search(JOIN *join, for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++) { table_map real_table_bit= s->table->map; - if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent)) + if ((remaining_tables & real_table_bit) && + !(remaining_tables & s->dependent) && + (!idx || !check_interleaving_with_nj(join->positions[idx-1].table, s))) { double current_record_count, current_read_time; @@ -4038,6 +4057,7 @@ best_extension_by_limited_search(JOIN *join, { DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, "prune_by_cost");); + restore_prev_nj_state(s); continue; } @@ -4066,6 +4086,7 @@ best_extension_by_limited_search(JOIN *join, { DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, "pruned_by_heuristic");); + restore_prev_nj_state(s); continue; } } @@ -4100,9 +4121,11 @@ best_extension_by_limited_search(JOIN *join, sizeof(POSITION) * (idx + 1)); join->best_read= current_read_time - 0.001; } - DBUG_EXECUTE("opt", - print_plan(join, current_read_time, current_record_count, idx, "full_plan");); + DBUG_EXECUTE("opt", print_plan(join, current_read_time, + current_record_count, idx, + "full_plan");); } + restore_prev_nj_state(s); } } DBUG_VOID_RETURN; @@ -4147,7 +4170,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, for (JOIN_TAB **pos=join->best_ref+idx ; (s=*pos) ; pos++) { table_map real_table_bit=s->table->map; - if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent)) + if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent) && + (!idx|| !check_interleaving_with_nj(join->positions[idx-1].table, s))) { double best,best_time,records; best=best_time=records=DBL_MAX; @@ -4485,10 +4509,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, join->unit->select_limit_cnt >= records) join->sort_by_table= (TABLE*) 1; // Must use temporary table - /* + /* Go to the next level only if there hasn't been a better key on this level! This will cut down the search for a lot simple cases! - */ + */ double current_record_count=record_count*records; double current_read_time=read_time+best; if (best_record_count > current_record_count || @@ -4509,6 +4533,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, return; swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); } + restore_prev_nj_state(s); if (join->select_options & SELECT_STRAIGHT_JOIN) break; // Don't test all combinations } @@ -5094,7 +5119,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) This function can be called only after the execution plan has been chosen. */ - + static void make_outerjoin_info(JOIN *join) { @@ -7255,11 +7280,11 @@ propagate_cond_constants(THD *thd, I_List *save_list, ascent all attributes are calculated, all outer joins that can be converted are replaced and then all unnecessary braces are removed. As join list contains join tables in the reverse order sequential - elimination of outer joins does not requite extra recursive calls. + elimination of outer joins does not require extra recursive calls. EXAMPLES Here is an example of a join query with invalid cross references: - SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN ON t3.b=t1.b + SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN t3 ON t3.b=t1.b RETURN VALUE The new condition, if success @@ -7416,7 +7441,210 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) } DBUG_RETURN(conds); } - + + +/* + Assign each nested join structure a bit in nested_join_map + + SYNOPSIS + build_nj_bitmap_for_tables() + join Join being processed + join_list List of tables + first_unused Number of first unused bit in nested_join_map before the + call + + DESCRIPTION + Assign each nested join structure (except for unary nested joins, see + below) a bit in nested_join_map. + + NOTE + This function is called after simplify_joins(), when there are no + redundant nested joins, #non_unary_nested_joins <= #tables_in_join so we + will not run out of bits in nested_join_map. + + RETURN + First unused bit in nested_join_map after the call. +*/ + +static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, + uint first_unused) +{ + List_iterator li(*join_list); + TABLE_LIST *table; + DBUG_ENTER("build_nj_bitmap_for_tables"); + while ((table= li++)) + { + NESTED_JOIN *nested_join; + if ((nested_join= table->nested_join)) + { + /* + It is guaranteed by simplify_joins() function that a nested join + that has only one child represents a single table VIEW (and a child + is an underlying table). We don't assign a bit to the nested join + because + 1. it is redundant (a "sequence" of one table cannot be interleaved + with anything) + 2. we could run out bits in nested_join_map otherwise. + */ + if (nested_join->join_list.elements != 1) + { + nested_join->nj_map= 1 << first_unused++; + first_unused= build_nj_bitmap_for_tables(join, &nested_join->join_list, + first_unused); + } + } + } + DBUG_RETURN(first_unused); +} + + +/* + Set NESTED_JOIN::counter=0 in all nested joins in passed list + + SYNOPSIS + reset_nj_counters() + join_list List of nested joins to process. It may also contain base + tables which will be ignored. + + DESCRIPTION + Recursively set NESTED_JOIN::counter=0 for all nested joins contained in + the passed join_list. +*/ + +static void reset_nj_counters(List *join_list) +{ + List_iterator li(*join_list); + TABLE_LIST *table; + DBUG_ENTER("reset_nj_counters"); + while ((table= li++)) + { + NESTED_JOIN *nested_join; + if ((nested_join= table->nested_join)) + { + nested_join->counter= 0; + reset_nj_counters(&nested_join->join_list); + } + } + DBUG_VOID_RETURN; +} + + +/* + Check interleaving with an inner tables of an outer join for extension table + + SYNOPSIS + check_interleaving_with_nj() + join Join being processed + last_tab Last table in current partial join order (this function is + not called for empty partial join orders) + next_tab Table we're going to extend the current partial join with + + DESCRIPTION + Check if table next_tab can be added to current partial join order, and + if yes, record that it has been added. + + The function assumes that both current partial join order and its + extension with next_tab are valid wrt table dependencies. + + NOTE + The nested joins aspect of information about current partial join order is + stored in join->cur_embedding_map and + {each_join_table}->pos_in_table_list (->embedding)+ ->nested_join->counter + Joins optimizer calls check_interleaving_with_nj() and + restore_prev_nj_state() to update this info and avoid constructing invalid + join orders. There is no need for any initialization of + {each_join_table}->...->counter before the join optimizer run. + + IMPLEMENTATION + The nested [outer] joins executioner algorithm imposes these limitations + on join order: + 1. "Outer tables first" - any "outer" table must be before any + corresponding "inner" table. + 2. "No interleaving" - tables inside a nested join must form a continuous + sequence in join order (i.e. the sequence must not be interrupted by + tables that are outside of this nested join). + + #1 is checked elsewhere, this function checks #2 provided that #1 has been + already checked. + + WHY NEED NON-INTERLEAVING + Consider an example: + + select * from t0 join t1 left join (t2 join t3) on cond1 + + The join order "t1 t2 t0 t3" is invalid: + + table t0 is outside of the nested join, so WHERE condition for t0 is + attached directly to t0 (without triggers, and it may be used to access + t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss + combinations of (t1, t2, t3) that satisfy condition cond1, and produce a + null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have + been produced. + + If table t0 is not between t2 and t3, the problem doesn't exist: + * If t0 is located after (t2,t3), WHERE(t0) is applied after nested join + processing has finished. + * If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are + wrapped into condition triggers, which takes care of correct nested + join processing. + + RETURN + FALSE Join order extended, nested joins info about current join order + (see NOTE section) updated. + TRUE Requested join order extension not allowed. +*/ + +static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next) +{ + TABLE_LIST *next_emb= next->table->pos_in_table_list->embedding; + JOIN *join= last->join; + + if (join->cur_embedding_map & ~next->embedding_map) + return TRUE; + + for (;next_emb; next_emb= next_emb->embedding) + { + next_emb->nested_join->counter++; + if (next_emb->nested_join->counter == 1) + { + /* next_emb is a first table inside a nested join */ + join->cur_embedding_map |= next_emb->nested_join->nj_map; + } + if (next_emb->nested_join->join_list.elements != + next_emb->nested_join->counter) + break; + join->cur_embedding_map &= ~next_emb->nested_join->nj_map; + } + return FALSE; +} + + +/* + Nested joins perspective: Remove the last table from the join order + + SYNOPSIS + restore_prev_nj_state() + last join table to remove, it is assumed to be the last in current + partial join order. + + DESCRIPTION + Remove the last table from the partial join order and update the nested + joins counters and join->cur_embedding_map. It is ok to call this + function for the first table in join order (for which + check_interleaving_with_nj has not been called) +*/ + +static void restore_prev_nj_state(JOIN_TAB *last) +{ + TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding; + JOIN *join= last->join; + while (last_emb && !(--last_emb->nested_join->counter)) + { + join->cur_embedding_map &= last_emb->nested_join->nj_map; + last_emb= last_emb->embedding; + } +} + static COND * optimize_cond(JOIN *join, COND *conds, List *join_list, diff --git a/sql/sql_select.h b/sql/sql_select.h index d6161eb6372..15872731f0c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -136,7 +136,9 @@ typedef struct st_join_table { TABLE_REF ref; JOIN_CACHE cache; JOIN *join; - + /* Bitmap of nested joins this table is part of */ + nested_join_map embedding_map; + void cleanup(); } JOIN_TAB; @@ -193,6 +195,13 @@ class JOIN :public Sql_alloc */ ha_rows fetch_limit; POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; + + /* + Bitmap of nested joins embedding the position at the end of the current + partial join (valid only during join optimizer run). + */ + nested_join_map cur_embedding_map; + double best_read; List *fields; List group_fields, group_fields_cache; diff --git a/sql/table.h b/sql/table.h index e76d005f494..00259ec0c18 100644 --- a/sql/table.h +++ b/sql/table.h @@ -757,7 +757,15 @@ typedef struct st_nested_join table_map used_tables; /* bitmap of tables in the nested join */ table_map not_null_tables; /* tables that rejects nulls */ struct st_join_table *first_nested;/* the first nested table in the plan */ - uint counter; /* to count tables in the nested join */ + /* + Used to count tables in the nested join in 2 isolated places: + 1. In make_outerjoin_info(). + 2. check_interleaving_with_nj/restore_prev_nj_state (these are called + by the join optimizer. + Before each use the counters are zeroed by reset_nj_counters. + */ + uint counter; + nested_join_map nj_map; /* Bit used to identify this nested join*/ } NESTED_JOIN; From 8354e066463654723eeb4d64cf10aafeffde0d7a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Oct 2005 17:14:17 +0200 Subject: [PATCH 03/48] bug#13078 - ndb memleak when doing ordered index scan on index with column larger than 32 bytes (recommit for merge to 5.0) ndb/src/ndbapi/NdbImpl.hpp: Fix order of free lists so that destructors are run in correct order ndb/src/ndbapi/NdbRecAttr.cpp: Dont allocate theStorageX twice ndb/src/ndbapi/ndb_cluster_connection.cpp: Destroy mutexes --- ndb/src/ndbapi/NdbImpl.hpp | 10 ++++++---- ndb/src/ndbapi/NdbRecAttr.cpp | 4 ++++ ndb/src/ndbapi/ndb_cluster_connection.cpp | 13 +++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp index 33aaca8de96..aa918a6f9f8 100644 --- a/ndb/src/ndbapi/NdbImpl.hpp +++ b/ndb/src/ndbapi/NdbImpl.hpp @@ -78,11 +78,9 @@ public: /** * NOTE free lists must be _after_ theNdbObjectIdMap take * assure that destructors are run in correct order + * NOTE these has to be in this specific order to make destructor run in + * correct order */ - Ndb_free_list_t theConIdleList; - Ndb_free_list_t theOpIdleList; - Ndb_free_list_t theScanOpIdleList; - Ndb_free_list_t theIndexOpIdleList; Ndb_free_list_t theRecAttrIdleList; Ndb_free_list_t theSignalIdleList; Ndb_free_list_t theLabelList; @@ -91,6 +89,10 @@ public: Ndb_free_list_t theCallList; Ndb_free_list_t theNdbBlobIdleList; Ndb_free_list_t theScanList; + Ndb_free_list_t theScanOpIdleList; + Ndb_free_list_t theOpIdleList; + Ndb_free_list_t theIndexOpIdleList; + Ndb_free_list_t theConIdleList; }; #ifdef VM_TRACE diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp index f993c652bf9..26039fb7867 100644 --- a/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/ndb/src/ndbapi/NdbRecAttr.cpp @@ -35,6 +35,7 @@ Adjust: 971206 UABRONM First version NdbRecAttr::NdbRecAttr(Ndb*) { + theStorageX = 0; init(); } @@ -64,6 +65,9 @@ NdbRecAttr::setup(const NdbColumnImpl* anAttrInfo, char* aValue) theNULLind = 0; m_nullable = anAttrInfo->m_nullable; + if (theStorageX) + delete[] theStorageX; + // check alignment to signal data // a future version could check alignment per data type as well diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 4fcf4d08396..a313a973a42 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -308,6 +308,19 @@ Ndb_cluster_connection_impl::~Ndb_cluster_connection_impl() // fragmentToNodeMap.release(); + if (ndb_global_event_buffer_mutex != NULL) + { + NdbMutex_Destroy(ndb_global_event_buffer_mutex); + ndb_global_event_buffer_mutex= NULL; + } +#ifdef VM_TRACE + if (ndb_print_state_mutex != NULL) + { + NdbMutex_Destroy(ndb_print_state_mutex); + ndb_print_state_mutex= NULL; + } +#endif + DBUG_VOID_RETURN; } From 81882f7127b9d52cd46c92006e1a2231a70c8849 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Oct 2005 23:31:32 +0400 Subject: [PATCH 04/48] Fix for BUG#13814: in mi_pack_key(), when processing NULL value for TINYBLOB key segment, do advance the source pointer over 2 bytes that specify value length. myisam/mi_key.c: Fix for BUG#13814: in mi_pack_key(), when processing NULL value for TINYBLOB key segment, do advance the source pointer over 2 bytes that specify value length (for NULL value the format is: null_marker 0x01, value length 0x00 0x00, data: 0x00 keyseg->length times). We need to advance over 2 bytes separately as keyseg->length doesn't include them. mysql-test/r/myisam.result: Testcase for BUG#13814 mysql-test/t/myisam.test: Testcase for BUG#13814 --- myisam/mi_key.c | 3 +++ mysql-test/r/myisam.result | 18 ++++++++++++++++++ mysql-test/t/myisam.test | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/myisam/mi_key.c b/myisam/mi_key.c index 9df22889b22..f4b92f969db 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -217,7 +217,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, { k_length-=length; if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART)) + { + old+= 2; k_length-=2; /* Skip length */ + } continue; /* Found NULL */ } } diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 17dba82dc00..55504e8e75b 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -702,3 +702,21 @@ t1 1 a 2 b A 0 NULL NULL YES BTREE t1 1 a 3 c A 0 NULL NULL YES BTREE t1 1 a 4 d A 0 NULL NULL YES BTREE set myisam_stats_method=DEFAULT; +drop table t1; +create table t1( +cip INT NOT NULL, +time TIME NOT NULL, +score INT NOT NULL DEFAULT 0, +bob TINYBLOB +); +insert into t1 (cip, time) VALUES (1, '00:01'), (2, '00:02'), (3,'00:03'); +insert into t1 (cip, bob, time) VALUES (4, 'a', '00:04'), (5, 'b', '00:05'), +(6, 'c', '00:06'); +select * from t1 where bob is null and cip=1; +cip time score bob +1 00:01:00 0 NULL +create index bug on t1 (bob(22), cip, time); +select * from t1 where bob is null and cip=1; +cip time score bob +1 00:01:00 0 NULL +drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index fbde658660d..8e9862015bc 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -656,4 +656,22 @@ analyze table t1; show index from t1; set myisam_stats_method=DEFAULT; +drop table t1; + +# BUG#13814 - key value packed incorrectly for TINYBLOBs + +create table t1( + cip INT NOT NULL, + time TIME NOT NULL, + score INT NOT NULL DEFAULT 0, + bob TINYBLOB +); + +insert into t1 (cip, time) VALUES (1, '00:01'), (2, '00:02'), (3,'00:03'); +insert into t1 (cip, bob, time) VALUES (4, 'a', '00:04'), (5, 'b', '00:05'), + (6, 'c', '00:06'); +select * from t1 where bob is null and cip=1; +create index bug on t1 (bob(22), cip, time); +select * from t1 where bob is null and cip=1; +drop table t1; # End of 4.1 tests From 04fcd58e09082f8fbe80744ab7aa6ae71f00e400 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 31 Oct 2005 15:56:52 -0800 Subject: [PATCH 05/48] Fix harmless typo in mysql_fix_privilege_tables.sql (Bug #14469) scripts/mysql_fix_privilege_tables.sql: Remove extra leading - in comment --- scripts/mysql_fix_privilege_tables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 0d7d32fd6a9..a72bd2799aa 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -29,7 +29,7 @@ ALTER TABLE user add Grant_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,a ALTER TABLE host add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Index_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Alter_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; ALTER TABLE db add Grant_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add References_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Index_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL,add Alter_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL; ---- Fix privileges for old tables +-- Fix privileges for old tables UPDATE user SET Grant_priv=File_priv,References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; UPDATE db SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; UPDATE host SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; From abf4f669a62baf64b8b1490e8682a0fdc5a024e6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Nov 2005 08:36:49 +0300 Subject: [PATCH 06/48] BUG#13126: Post-review fixes: better comments, some function renaming. sql/mysql_priv.h: BUG#13126: Post-review fixes: better comments --- sql/mysql_priv.h | 5 +- sql/sql_select.cc | 163 +++++++++++++++++++++++++++++----------------- 2 files changed, 108 insertions(+), 60 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 198a90dbd8a..e7dab6a6377 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -45,8 +45,9 @@ typedef ulonglong table_map; /* Used for table bits in join */ typedef Bitmap<64> key_map; /* Used for finding keys */ typedef ulong key_part_map; /* Used for finding key parts */ /* - Used for nested join bits within a scope of a join (applicable to non-unary - nested joins that have not been simplified away) + Used to identify NESTED_JOIN structures within a join (applicable only to + structures that have not been simplified away and embed more the one + element) */ typedef ulonglong nested_join_map; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a74e01b866b..219f707b0da 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -101,8 +101,8 @@ static COND *simplify_joins(JOIN *join, List *join_list, static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next); static void restore_prev_nj_state(JOIN_TAB *last); static void reset_nj_counters(List *join_list); -static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, - uint first_unused); +static uint build_bitmap_for_nested_joins(List *join_list, + uint first_unused); static COND *optimize_cond(JOIN *join, COND *conds, List *join_list, @@ -595,7 +595,7 @@ JOIN::optimize() /* Convert all outer joins to inner joins if possible */ conds= simplify_joins(this, join_list, conds, TRUE); - build_nj_bitmap_for_tables(this, join_list, 0); + build_bitmap_for_nested_joins(join_list, 0); sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; @@ -7447,31 +7447,31 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) Assign each nested join structure a bit in nested_join_map SYNOPSIS - build_nj_bitmap_for_tables() + build_bitmap_for_nested_joins() join Join being processed join_list List of tables first_unused Number of first unused bit in nested_join_map before the call DESCRIPTION - Assign each nested join structure (except for unary nested joins, see - below) a bit in nested_join_map. + Assign each nested join structure (except "confluent" ones - those that + embed only one element) a bit in nested_join_map. NOTE This function is called after simplify_joins(), when there are no - redundant nested joins, #non_unary_nested_joins <= #tables_in_join so we - will not run out of bits in nested_join_map. + redundant nested joins, #non_confluent_nested_joins <= #tables_in_join so + we will not run out of bits in nested_join_map. RETURN First unused bit in nested_join_map after the call. */ -static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, - uint first_unused) +static uint build_bitmap_for_nested_joins(List *join_list, + uint first_unused) { List_iterator li(*join_list); TABLE_LIST *table; - DBUG_ENTER("build_nj_bitmap_for_tables"); + DBUG_ENTER("build_bitmap_for_nested_joins"); while ((table= li++)) { NESTED_JOIN *nested_join; @@ -7479,9 +7479,9 @@ static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, { /* It is guaranteed by simplify_joins() function that a nested join - that has only one child represents a single table VIEW (and a child - is an underlying table). We don't assign a bit to the nested join - because + that has only one child represents a single table VIEW (and the child + is an underlying table). We don't assign bits to such nested join + structures because 1. it is redundant (a "sequence" of one table cannot be interleaved with anything) 2. we could run out bits in nested_join_map otherwise. @@ -7489,8 +7489,8 @@ static uint build_nj_bitmap_for_tables(JOIN *join, List *join_list, if (nested_join->join_list.elements != 1) { nested_join->nj_map= 1 << first_unused++; - first_unused= build_nj_bitmap_for_tables(join, &nested_join->join_list, - first_unused); + first_unused= build_bitmap_for_nested_joins(&nested_join->join_list, + first_unused); } } } @@ -7546,73 +7546,120 @@ static void reset_nj_counters(List *join_list) The function assumes that both current partial join order and its extension with next_tab are valid wrt table dependencies. - NOTE - The nested joins aspect of information about current partial join order is - stored in join->cur_embedding_map and - {each_join_table}->pos_in_table_list (->embedding)+ ->nested_join->counter - Joins optimizer calls check_interleaving_with_nj() and - restore_prev_nj_state() to update this info and avoid constructing invalid - join orders. There is no need for any initialization of - {each_join_table}->...->counter before the join optimizer run. - IMPLEMENTATION - The nested [outer] joins executioner algorithm imposes these limitations - on join order: - 1. "Outer tables first" - any "outer" table must be before any - corresponding "inner" table. - 2. "No interleaving" - tables inside a nested join must form a continuous - sequence in join order (i.e. the sequence must not be interrupted by - tables that are outside of this nested join). + LIMITATIONS ON JOIN ORDER + The nested [outer] joins executioner algorithm imposes these limitations + on join order: + 1. "Outer tables first" - any "outer" table must be before any + corresponding "inner" table. + 2. "No interleaving" - tables inside a nested join must form a continuous + sequence in join order (i.e. the sequence must not be interrupted by + tables that are outside of this nested join). - #1 is checked elsewhere, this function checks #2 provided that #1 has been - already checked. + #1 is checked elsewhere, this function checks #2 provided that #1 has + been already checked. WHY NEED NON-INTERLEAVING - Consider an example: - - select * from t0 join t1 left join (t2 join t3) on cond1 - - The join order "t1 t2 t0 t3" is invalid: + Consider an example: + + select * from t0 join t1 left join (t2 join t3) on cond1 + + The join order "t1 t2 t0 t3" is invalid: - table t0 is outside of the nested join, so WHERE condition for t0 is - attached directly to t0 (without triggers, and it may be used to access - t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss - combinations of (t1, t2, t3) that satisfy condition cond1, and produce a - null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have - been produced. - - If table t0 is not between t2 and t3, the problem doesn't exist: - * If t0 is located after (t2,t3), WHERE(t0) is applied after nested join - processing has finished. - * If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are - wrapped into condition triggers, which takes care of correct nested - join processing. - + table t0 is outside of the nested join, so WHERE condition for t0 is + attached directly to t0 (without triggers, and it may be used to access + t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss + combinations of (t1, t2, t3) that satisfy condition cond1, and produce a + null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have + been produced. + + If table t0 is not between t2 and t3, the problem doesn't exist: + * If t0 is located after (t2,t3), WHERE(t0) is applied after nested join + processing has finished. + * If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are + wrapped into condition triggers, which takes care of correct nested + join processing. + + HOW IT IS IMPLEMENTED + The limitations on join order can be rephrased as follows: for valid + join order one must be able to: + 1. write down the used tables in the join order on one line. + 2. for each nested join, put one '(' and one ')' on the said line + 3. write "LEFT JOIN" and "ON (...)" where appropriate + 4. get a query equivalent to the query we're trying to execute. + + Calls to check_interleaving_with_nj() are equivalent to writing the + above described line from left to right. + A single check_interleaving_with_nj(A,B) call is equivalent to writing + table B and appropriate brackets on condition that table A and + appropriate brackets is the last what was written. Graphically the + transition is as follows: + + +---- current position + | + ... last_tab ))) | ( next_tab ) )..) | ... + X Y Z | + +- need to move to this + position. + + Notes about the position: + The caller guarantees that there is no more then one X-bracket by + checking "!(remaining_tables & s->dependent)" before calling this + function. X-bracket may have a pair in Y-bracket. + + When "writing" we store/update this auxilary info about the current + position: + 1. join->cur_embedding_map - bitmap of pairs of brackets (aka nested + joins) we've opened but didn't close. + 2. {each NESTED_JOIN structure not simplified away}->counter - number + of this nested join's children that have already been added to to + the partial join order. + RETURN FALSE Join order extended, nested joins info about current join order (see NOTE section) updated. TRUE Requested join order extension not allowed. */ -static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next) +static bool check_interleaving_with_nj(JOIN_TAB *last_tab, JOIN_TAB *next_tab) { - TABLE_LIST *next_emb= next->table->pos_in_table_list->embedding; - JOIN *join= last->join; + TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding; + JOIN *join= last_tab->join; - if (join->cur_embedding_map & ~next->embedding_map) + if (join->cur_embedding_map & ~next_tab->embedding_map) + { + /* + next_tab is outside of the "pair of brackets" we're currently in. + Cannot add it. + */ return TRUE; + } + /* + Do update counters for "pairs of brackets" that we've left (marked as + X,Y,Z in the above picture) + */ for (;next_emb; next_emb= next_emb->embedding) { next_emb->nested_join->counter++; if (next_emb->nested_join->counter == 1) { - /* next_emb is a first table inside a nested join */ + /* + next_emb is the first table inside a nested join we've "entered". In + the picture above, we're looking at the 'X' bracket. Don't exit yet as + X bracket might have Y pair bracket. + */ join->cur_embedding_map |= next_emb->nested_join->nj_map; } + if (next_emb->nested_join->join_list.elements != next_emb->nested_join->counter) break; + + /* + We're currently at Y or Z-bracket as depicted in the above picture. + Mark that we've left it and continue walking up the brackets hierarchy. + */ join->cur_embedding_map &= ~next_emb->nested_join->nj_map; } return FALSE; From caf40acf2801dc2be620b6b82b8bc9aaec4b9206 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Nov 2005 11:08:20 -0800 Subject: [PATCH 07/48] Fix compile using libwrap with gcc 4.0.2. (Bug #12570) sql/mysqld.cc: Fix const-ness of libwrapName variable. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 143ed74e012..432887ab502 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -564,7 +564,7 @@ bool mysqld_embedded=1; static const char* default_dbug_option; #endif #ifdef HAVE_LIBWRAP -char *libwrapName= NULL; +const char *libwrapName= NULL; #endif #ifdef HAVE_QUERY_CACHE static ulong query_cache_limit= 0; From dced93482062f1bf0294ed82d9408781d76879ee Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Nov 2005 20:49:02 +0100 Subject: [PATCH 08/48] config/ac-macros/zlib.m4 Accept any shared library for "libz", not just the static one. Bug#6584 Repetition of the corresponding change, as the 4.1 "acinclude.m4" is not used in 5.0. config/ac-macros/zlib.m4: Accept any shared library for "libz", not just the static one. Bug#6584 Repetition of the corresponding change, as the 4.1 "acinclude.m4" is not used in 5.0. --- config/ac-macros/zlib.m4 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/ac-macros/zlib.m4 b/config/ac-macros/zlib.m4 index 94a26f33dd3..22cf9542cf0 100644 --- a/config/ac-macros/zlib.m4 +++ b/config/ac-macros/zlib.m4 @@ -89,8 +89,9 @@ case $SYSTEM_TYPE in fi ;; *) - if test -f "$mysql_zlib_dir/lib/libz.a" -a \ - -f "$mysql_zlib_dir/include/zlib.h"; then + if test \( -f "$mysql_zlib_dir/lib/libz.a" -o -f "$mysql_zlib_dir/lib/libz.so" -o \ + -f "$mysql_zlib_dir/lib/libz.sl" -o -f "$mysql_zlib_dir/lib/libz.dylib" \) \ + -a -f "$mysql_zlib_dir/include/zlib.h"; then ZLIB_INCLUDES="-I$mysql_zlib_dir/include" ZLIB_LIBS="-L$mysql_zlib_dir/lib -lz" MYSQL_CHECK_ZLIB_DIR From 17fcbcf77290fff34a00ce1387760f5e5c71c134 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Nov 2005 07:05:19 +0300 Subject: [PATCH 09/48] BUG#14026: When doing the end-of-prepare fix up for TABLE_LISTs used in the PS, do the fixup for underlying tables of a merge VIEWs, too. mysql-test/r/view.result: Testcase for BUG#14026 mysql-test/t/view.test: Testcase for BUG#14026 --- mysql-test/r/view.result | 23 ++++++++++++++++++++++- mysql-test/t/view.test | 24 +++++++++++++++++++++++- sql/sql_lex.cc | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6f15e7af399..a10972cca98 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t3,t4,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; use test; @@ -2323,3 +2323,24 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +create table t1 (x int, y int); +create table t2 (x int, y int, z int); +create table t3 (x int, y int, z int); +create table t4 (x int, y int, z int); +create view v1 as +select t1.x +from ( +(t1 join t2 on ((t1.y = t2.y))) +join +(t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z)) +); +prepare stmt1 from "select count(*) from v1 where x = ?"; +set @parm1=1; +execute stmt1 using @parm1; +count(*) +0 +execute stmt1 using @parm1; +count(*) +0 +drop view v1; +drop table t1,t2,t3,t4; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index aa3189bad69..928e5788dd2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1,5 +1,5 @@ --disable_warnings -drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t3,t4,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; --enable_warnings @@ -2189,4 +2189,26 @@ EXPLAIN SELECT * FROM v2 WHERE a=1; DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +# +# BUG#14026 Crash on second PS execution when using views +# +create table t1 (x int, y int); +create table t2 (x int, y int, z int); +create table t3 (x int, y int, z int); +create table t4 (x int, y int, z int); +create view v1 as +select t1.x +from ( + (t1 join t2 on ((t1.y = t2.y))) + join + (t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z)) +); + +prepare stmt1 from "select count(*) from v1 where x = ?"; +set @parm1=1; + +execute stmt1 using @parm1; +execute stmt1 using @parm1; +drop view v1; +drop table t1,t2,t3,t4; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 11f056d6510..a302db15736 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2037,6 +2037,35 @@ void st_lex::cleanup_after_one_table_open() } +/* + Do end-of-prepare fixup for list of tables and their merge-VIEWed tables + + SYNOPSIS + fix_prepare_info_in_table_list() + thd Thread handle + tbl List of tables to process + + DESCRIPTION + Perform end-end-of prepare fixup for list of tables, if any of the tables + is a merge-algorithm VIEW, recursively fix up its underlying tables as + well. + +*/ + +static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl) +{ + for (; tbl; tbl= tbl->next_local) + { + if (tbl->on_expr) + { + tbl->prep_on_expr= tbl->on_expr; + tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); + } + fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list); + } +} + + /* fix some structures at the end of preparation @@ -2056,16 +2085,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) prep_where= *conds; *conds= where= prep_where->copy_andor_structure(thd); } - for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first; - tbl; - tbl= tbl->next_local) - { - if (tbl->on_expr) - { - tbl->prep_on_expr= tbl->on_expr; - tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); - } - } + fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first); } } From 8a80936517515360c432312a05db232a5e4c5dba Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Nov 2005 13:44:58 -0800 Subject: [PATCH 10/48] #view.test#: new file sql_table.cc, handler.h: Fixed bug #14540. Added error mnemonic code HA_ADMIN_NOT_BASE_TABLE to report that an operation cannot be applied for views. view.test, view.result: Added a test case for bug #14540. errmsg.txt: Fixed bug #14540. Added error ER_CHECK_NOT_BASE_TABLE. mysql-test/r/view.result: Added a test case for bug #14540. mysql-test/t/view.test: Added a test case for bug #14540. sql/handler.h: Fixed bug #14540. Added error mnemonic code HA_ADMIN_NOT_BASE_TABLE to report that an operation cannot be applied for views. sql/share/errmsg.txt: Added error ER_CHECK_NOT_BASE_TABLE. sql/sql_table.cc: Fixed bug #14540. Added error mnemonic code HA_ADMIN_NOT_BASE_TABLE to report that an operation cannot be applied for views. --- mysql-test/r/view.result | 19 +++++++++++++++++++ mysql-test/t/view.test | 15 +++++++++++++++ sql/handler.h | 1 + sql/share/errmsg.txt | 2 ++ sql/sql_table.cc | 33 +++++++++++++++++++++++---------- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6f15e7af399..cd35cf4382f 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2323,3 +2323,22 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +CREATE TABLE t1(id INT) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT id FROM t1; +OPTIMIZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 optimize note You cannot apply optimize to a view +ANALYZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 analyze note You cannot apply analyze to a view +REPAIR TABLE v1; +Table Op Msg_type Msg_text +test.v1 repair note You cannot apply repair to a view +DROP TABLE t1; +OPTIMIZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 optimize note You cannot apply optimize to a view +Warnings: +Error 1146 Table 'test.t1' doesn't exist +Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP VIEW v1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index aa3189bad69..2a941027d63 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2189,4 +2189,19 @@ EXPLAIN SELECT * FROM v2 WHERE a=1; DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +# +# Bug #14540: OPTIMIZE, ANALYZE, REPAIR applied to not a view +# + +CREATE TABLE t1(id INT) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT id FROM t1; + +OPTIMIZE TABLE v1; +ANALYZE TABLE v1; +REPAIR TABLE v1; + +DROP TABLE t1; +OPTIMIZE TABLE v1; + +DROP VIEW v1; diff --git a/sql/handler.h b/sql/handler.h index af80f021e75..16eb8dc6f02 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -45,6 +45,7 @@ #define HA_ADMIN_REJECT -6 #define HA_ADMIN_TRY_ALTER -7 #define HA_ADMIN_WRONG_CHECKSUM -8 +#define HA_ADMIN_NOT_BASE_TABLE -9 /* Bits in table_flags() to show what database can do */ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index f85bda90e81..0174a1ef98e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5421,3 +5421,5 @@ ER_NO_REFERENCED_ROW_2 23000 eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" +ER_CHECK_NOT_BASE_TABLE 4200 + eng "You cannot apply %s to a view" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b635c44c6dc..80b337e61d5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2189,7 +2189,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* if view are unsupported */ if (table->view && view_operator_func == NULL) { - result_code= HA_ADMIN_NOT_IMPLEMENTED; + result_code= HA_ADMIN_NOT_BASE_TABLE; goto send_result; } thd->open_options&= ~extra_open_options; @@ -2324,6 +2324,16 @@ send_result_message: } break; + case HA_ADMIN_NOT_BASE_TABLE: + { + char buf[ERRMSGSIZE+20]; + uint length=my_snprintf(buf, ERRMSGSIZE, + ER(ER_CHECK_NOT_BASE_TABLE), operator_name); + protocol->store("note", 4, system_charset_info); + protocol->store(buf, length, system_charset_info); + } + break; + case HA_ADMIN_OK: protocol->store("status", 6, system_charset_info); protocol->store("OK",2, system_charset_info); @@ -2424,16 +2434,19 @@ send_result_message: break; } } - if (fatal_error) - table->table->s->version=0; // Force close of table - else if (open_for_modify) + if (table->table) { - pthread_mutex_lock(&LOCK_open); - remove_table_from_cache(thd, table->table->s->db, - table->table->s->table_name, RTFC_NO_FLAG); - pthread_mutex_unlock(&LOCK_open); - /* May be something modified consequently we have to invalidate cache */ - query_cache_invalidate3(thd, table->table, 0); + if (fatal_error) + table->table->s->version=0; // Force close of table + else if (open_for_modify) + { + pthread_mutex_lock(&LOCK_open); + remove_table_from_cache(thd, table->table->s->db, + table->table->s->table_name, RTFC_NO_FLAG); + pthread_mutex_unlock(&LOCK_open); + /* Something may be modified, that's why we have to invalidate cache */ + query_cache_invalidate3(thd, table->table, 0); + } } close_thread_tables(thd); table->table=0; // For query cache From 3e2e44f044e51d51c5d6b00f94431d527e0a7cc1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Nov 2005 22:13:10 -0800 Subject: [PATCH 11/48] Post review fixes. sql/sql_table.cc: Post review fixes --- mysql-test/r/view.result | 2 +- mysql-test/t/view.test | 2 +- sql/share/errmsg.txt | 2 +- sql/sql_table.cc | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index cd35cf4382f..07627c9078b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2323,7 +2323,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; -CREATE TABLE t1(id INT) ENGINE=MyISAM; +CREATE TABLE t1(id INT); CREATE VIEW v1 AS SELECT id FROM t1; OPTIMIZE TABLE v1; Table Op Msg_type Msg_text diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 2a941027d63..db77982e3eb 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2193,7 +2193,7 @@ DROP TABLE t1,t2,t3; # Bug #14540: OPTIMIZE, ANALYZE, REPAIR applied to not a view # -CREATE TABLE t1(id INT) ENGINE=MyISAM; +CREATE TABLE t1(id INT); CREATE VIEW v1 AS SELECT id FROM t1; OPTIMIZE TABLE v1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 0174a1ef98e..24e1d4b6b81 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5421,5 +5421,5 @@ ER_NO_REFERENCED_ROW_2 23000 eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" -ER_CHECK_NOT_BASE_TABLE 4200 +ER_CHECK_NOT_BASE_TABLE 42000 eng "You cannot apply %s to a view" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 80b337e61d5..bc604537139 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2326,11 +2326,11 @@ send_result_message: case HA_ADMIN_NOT_BASE_TABLE: { - char buf[ERRMSGSIZE+20]; - uint length=my_snprintf(buf, ERRMSGSIZE, - ER(ER_CHECK_NOT_BASE_TABLE), operator_name); - protocol->store("note", 4, system_charset_info); - protocol->store(buf, length, system_charset_info); + char buf[ERRMSGSIZE+20]; + uint length= my_snprintf(buf, ERRMSGSIZE, + ER(ER_CHECK_NOT_BASE_TABLE), operator_name); + protocol->store("note", 4, system_charset_info); + protocol->store(buf, length, system_charset_info); } break; @@ -2442,7 +2442,7 @@ send_result_message: { pthread_mutex_lock(&LOCK_open); remove_table_from_cache(thd, table->table->s->db, - table->table->s->table_name, RTFC_NO_FLAG); + table->table->s->table_name, RTFC_NO_FLAG); pthread_mutex_unlock(&LOCK_open); /* Something may be modified, that's why we have to invalidate cache */ query_cache_invalidate3(thd, table->table, 0); From f8aa1db39ca5a5dfb8027706b73c644e5679d310 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Nov 2005 10:37:49 +0100 Subject: [PATCH 12/48] Bug#13957 yassl: opensrv6c compile failure - Added some ifdefs and turn off auto template instantiation, use explicit template instantiation configure.in: Use -Tno_implict to indicate that we specifiy which template should be instantiated. Turn on HAVE_EXPLICIT_TEMPLATE_INSTATNTIATION extra/yassl/src/socket_wrapper.cpp: Include sys/filio.h if __SCO_VERSION__ is defined extra/yassl/src/timer.cpp: Dont' include files from within namespace yaSSL. --- configure.in | 4 ++++ extra/yassl/src/socket_wrapper.cpp | 2 +- extra/yassl/src/timer.cpp | 12 +++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/configure.in b/configure.in index 2179c82e2e5..5e1cc5f307d 100644 --- a/configure.in +++ b/configure.in @@ -334,6 +334,10 @@ case "$target_os" in # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" CXXFLAGS="$CFLAGS -Kalloca" + # Use no_implicit for templates + CXXFLAGS="$CXXFLAGS -Tno_implicit" + AC_DEFINE([HAVE_EXPLICIT_TEMPLATE_INSTANTIATION], + [1], [Defined by configure. Use explicit template instantiation.]) fi ;; esac diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp index 91cea1f9753..285e0dee2e5 100644 --- a/extra/yassl/src/socket_wrapper.cpp +++ b/extra/yassl/src/socket_wrapper.cpp @@ -39,7 +39,7 @@ #include #endif // _WIN32 -#ifdef __sun +#if defined(__sun) || defined(__SCO_VERSION__) #include #endif diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp index 4fe0d3aa4f9..8b7d2d17a84 100644 --- a/extra/yassl/src/timer.cpp +++ b/extra/yassl/src/timer.cpp @@ -26,13 +26,17 @@ #include "runtime.hpp" #include "timer.hpp" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif + namespace yaSSL { #ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #include - timer_d timer() { static bool init(false); @@ -57,8 +61,6 @@ namespace yaSSL { #else // _WIN32 - #include - timer_d timer() { struct timeval tv; From a7956c817e8afa1c3b5c119cdf2bc033fe839324 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Nov 2005 12:38:46 +0300 Subject: [PATCH 13/48] Post-merge fixes --- mysql-test/r/view.result | 24 ++++++++++++------------ mysql-test/t/view.test | 31 ++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 52ccabf60cd..22edc4969e4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2323,6 +2323,18 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(1,2),(1,3); +create view v1 as select f1 ,group_concat(f2 order by f2 asc) from t1 group by f1; +create view v2 as select f1 ,group_concat(f2 order by f2 desc) from t1 group by f1; +select * from v1; +f1 group_concat(f2 order by f2 asc) +1 1,2,3 +select * from v2; +f1 group_concat(f2 order by f2 desc) +1 3,2,1 +drop view v1,v2; +drop table t1; create table t1 (x int, y int); create table t2 (x int, y int, z int); create table t3 (x int, y int, z int); @@ -2344,15 +2356,3 @@ count(*) 0 drop view v1; drop table t1,t2,t3,t4; -create table t1 (f1 int, f2 int); -insert into t1 values(1,1),(1,2),(1,3); -create view v1 as select f1 ,group_concat(f2 order by f2 asc) from t1 group by f1; -create view v2 as select f1 ,group_concat(f2 order by f2 desc) from t1 group by f1; -select * from v1; -f1 group_concat(f2 order by f2 asc) -1 1,2,3 -select * from v2; -f1 group_concat(f2 order by f2 desc) -1 3,2,1 -drop view v1,v2; -drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7918c78deb3..7ab2c4779b9 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2190,13 +2190,6 @@ DROP VIEW v1,v2; DROP TABLE t1,t2,t3; # -prepare stmt1 from "select count(*) from v1 where x = ?"; -set @parm1=1; - -execute stmt1 using @parm1; -execute stmt1 using @parm1; -drop view v1; -drop table t1,t2,t3,t4; # Bug #14466 lost sort order in GROUP_CONCAT() in a view # create table t1 (f1 int, f2 int); @@ -2207,3 +2200,27 @@ select * from v1; select * from v2; drop view v1,v2; drop table t1; + +# +# BUG#14026 Crash on second PS execution when using views +# +create table t1 (x int, y int); +create table t2 (x int, y int, z int); +create table t3 (x int, y int, z int); +create table t4 (x int, y int, z int); + +create view v1 as +select t1.x +from ( + (t1 join t2 on ((t1.y = t2.y))) + join + (t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z)) +); + +prepare stmt1 from "select count(*) from v1 where x = ?"; +set @parm1=1; + +execute stmt1 using @parm1; +execute stmt1 using @parm1; +drop view v1; +drop table t1,t2,t3,t4; From fb832641c340e528677d8e90f419303e8ae13fd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Nov 2005 13:49:37 +0400 Subject: [PATCH 14/48] Fix for bug #14268 (Bad FLOAT->DECIMAL conversion) mysql-test/r/type_newdecimal.result: test result updated mysql-test/t/type_newdecimal.test: test case added strings/decimal.c: i think that gives the proper precision --- mysql-test/r/type_newdecimal.result | 410 ++++++++++++++++++++++++++++ mysql-test/t/type_newdecimal.test | 35 +++ strings/decimal.c | 2 +- 3 files changed, 446 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 45eb8aab89e..03aa04f491b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1021,3 +1021,413 @@ cast(@non_existing_user_var/2 as DECIMAL) NULL create table t (d decimal(0,10)); ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'd'). +CREATE TABLE t1 ( +my_float FLOAT, +my_double DOUBLE, +my_varchar VARCHAR(50), +my_decimal DECIMAL(65,30) +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `my_float` float default NULL, + `my_double` double default NULL, + `my_varchar` varchar(50) default NULL, + `my_decimal` decimal(65,30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 SET my_float = 1.175494345e-32, +my_double = 1.175494345e-32, +my_varchar = '1.175494345e-32'; +INSERT INTO t1 SET my_float = 1.175494345e-31, +my_double = 1.175494345e-31, +my_varchar = '1.175494345e-31'; +INSERT INTO t1 SET my_float = 1.175494345e-30, +my_double = 1.175494345e-30, +my_varchar = '1.175494345e-30'; +INSERT INTO t1 SET my_float = 1.175494345e-29, +my_double = 1.175494345e-29, +my_varchar = '1.175494345e-29'; +INSERT INTO t1 SET my_float = 1.175494345e-28, +my_double = 1.175494345e-28, +my_varchar = '1.175494345e-28'; +INSERT INTO t1 SET my_float = 1.175494345e-27, +my_double = 1.175494345e-27, +my_varchar = '1.175494345e-27'; +INSERT INTO t1 SET my_float = 1.175494345e-26, +my_double = 1.175494345e-26, +my_varchar = '1.175494345e-26'; +INSERT INTO t1 SET my_float = 1.175494345e-25, +my_double = 1.175494345e-25, +my_varchar = '1.175494345e-25'; +INSERT INTO t1 SET my_float = 1.175494345e-24, +my_double = 1.175494345e-24, +my_varchar = '1.175494345e-24'; +INSERT INTO t1 SET my_float = 1.175494345e-23, +my_double = 1.175494345e-23, +my_varchar = '1.175494345e-23'; +INSERT INTO t1 SET my_float = 1.175494345e-22, +my_double = 1.175494345e-22, +my_varchar = '1.175494345e-22'; +INSERT INTO t1 SET my_float = 1.175494345e-21, +my_double = 1.175494345e-21, +my_varchar = '1.175494345e-21'; +INSERT INTO t1 SET my_float = 1.175494345e-20, +my_double = 1.175494345e-20, +my_varchar = '1.175494345e-20'; +INSERT INTO t1 SET my_float = 1.175494345e-19, +my_double = 1.175494345e-19, +my_varchar = '1.175494345e-19'; +INSERT INTO t1 SET my_float = 1.175494345e-18, +my_double = 1.175494345e-18, +my_varchar = '1.175494345e-18'; +INSERT INTO t1 SET my_float = 1.175494345e-17, +my_double = 1.175494345e-17, +my_varchar = '1.175494345e-17'; +INSERT INTO t1 SET my_float = 1.175494345e-16, +my_double = 1.175494345e-16, +my_varchar = '1.175494345e-16'; +INSERT INTO t1 SET my_float = 1.175494345e-15, +my_double = 1.175494345e-15, +my_varchar = '1.175494345e-15'; +INSERT INTO t1 SET my_float = 1.175494345e-14, +my_double = 1.175494345e-14, +my_varchar = '1.175494345e-14'; +INSERT INTO t1 SET my_float = 1.175494345e-13, +my_double = 1.175494345e-13, +my_varchar = '1.175494345e-13'; +INSERT INTO t1 SET my_float = 1.175494345e-12, +my_double = 1.175494345e-12, +my_varchar = '1.175494345e-12'; +INSERT INTO t1 SET my_float = 1.175494345e-11, +my_double = 1.175494345e-11, +my_varchar = '1.175494345e-11'; +INSERT INTO t1 SET my_float = 1.175494345e-10, +my_double = 1.175494345e-10, +my_varchar = '1.175494345e-10'; +INSERT INTO t1 SET my_float = 1.175494345e-9, +my_double = 1.175494345e-9, +my_varchar = '1.175494345e-9'; +INSERT INTO t1 SET my_float = 1.175494345e-8, +my_double = 1.175494345e-8, +my_varchar = '1.175494345e-8'; +INSERT INTO t1 SET my_float = 1.175494345e-7, +my_double = 1.175494345e-7, +my_varchar = '1.175494345e-7'; +INSERT INTO t1 SET my_float = 1.175494345e-6, +my_double = 1.175494345e-6, +my_varchar = '1.175494345e-6'; +INSERT INTO t1 SET my_float = 1.175494345e-5, +my_double = 1.175494345e-5, +my_varchar = '1.175494345e-5'; +INSERT INTO t1 SET my_float = 1.175494345e-4, +my_double = 1.175494345e-4, +my_varchar = '1.175494345e-4'; +INSERT INTO t1 SET my_float = 1.175494345e-3, +my_double = 1.175494345e-3, +my_varchar = '1.175494345e-3'; +INSERT INTO t1 SET my_float = 1.175494345e-2, +my_double = 1.175494345e-2, +my_varchar = '1.175494345e-2'; +INSERT INTO t1 SET my_float = 1.175494345e-1, +my_double = 1.175494345e-1, +my_varchar = '1.175494345e-1'; +SELECT my_float, my_double, my_varchar FROM t1; +my_float my_double my_varchar +1.17549e-32 1.175494345e-32 1.175494345e-32 +1.17549e-31 1.175494345e-31 1.175494345e-31 +1.17549e-30 1.175494345e-30 1.175494345e-30 +1.17549e-29 1.175494345e-29 1.175494345e-29 +1.17549e-28 1.175494345e-28 1.175494345e-28 +1.17549e-27 1.175494345e-27 1.175494345e-27 +1.17549e-26 1.175494345e-26 1.175494345e-26 +1.17549e-25 1.175494345e-25 1.175494345e-25 +1.17549e-24 1.175494345e-24 1.175494345e-24 +1.17549e-23 1.175494345e-23 1.175494345e-23 +1.17549e-22 1.175494345e-22 1.175494345e-22 +1.17549e-21 1.175494345e-21 1.175494345e-21 +1.17549e-20 1.175494345e-20 1.175494345e-20 +1.17549e-19 1.175494345e-19 1.175494345e-19 +1.17549e-18 1.175494345e-18 1.175494345e-18 +1.17549e-17 1.175494345e-17 1.175494345e-17 +1.17549e-16 1.175494345e-16 1.175494345e-16 +1.17549e-15 1.175494345e-15 1.175494345e-15 +1.17549e-14 1.175494345e-14 1.175494345e-14 +1.17549e-13 1.175494345e-13 1.175494345e-13 +1.17549e-12 1.175494345e-12 1.175494345e-12 +1.17549e-11 1.175494345e-11 1.175494345e-11 +1.17549e-10 1.175494345e-10 1.175494345e-10 +1.17549e-09 1.175494345e-09 1.175494345e-9 +1.17549e-08 1.175494345e-08 1.175494345e-8 +1.17549e-07 1.175494345e-07 1.175494345e-7 +1.17549e-06 1.175494345e-06 1.175494345e-6 +1.17549e-05 1.175494345e-05 1.175494345e-5 +0.000117549 0.0001175494345 1.175494345e-4 +0.00117549 0.001175494345 1.175494345e-3 +0.0117549 0.01175494345 1.175494345e-2 +0.117549 0.1175494345 1.175494345e-1 +SELECT CAST(my_float AS DECIMAL(65,30)), my_float FROM t1; +CAST(my_float AS DECIMAL(65,30)) my_float +0.000000000000000000000000000000 1.17549e-32 +0.000000000000000000000000000000 1.17549e-31 +0.000000000000000000000000000001 1.17549e-30 +0.000000000000000000000000000012 1.17549e-29 +0.000000000000000000000000000118 1.17549e-28 +0.000000000000000000000000001175 1.17549e-27 +0.000000000000000000000000011755 1.17549e-26 +0.000000000000000000000000117549 1.17549e-25 +0.000000000000000000000001175494 1.17549e-24 +0.000000000000000000000011754943 1.17549e-23 +0.000000000000000000000117549438 1.17549e-22 +0.000000000000000000001175494332 1.17549e-21 +0.000000000000000000011754943324 1.17549e-20 +0.000000000000000000117549434853 1.17549e-19 +0.000000000000000001175494374380 1.17549e-18 +0.000000000000000011754943743802 1.17549e-17 +0.000000000000000117549432474939 1.17549e-16 +0.000000000000001175494324749389 1.17549e-15 +0.000000000000011754943671010360 1.17549e-14 +0.000000000000117549429933840000 1.17549e-13 +0.000000000001175494380653563000 1.17549e-12 +0.000000000011754943372854760000 1.17549e-11 +0.000000000117549428524377200000 1.17549e-10 +0.000000001175494368510499000000 1.17549e-09 +0.000000011754943685104990000000 1.17549e-08 +0.000000117549433298336200000000 1.17549e-07 +0.000001175494389826781000000000 1.17549e-06 +0.000011754943443520460000000000 1.17549e-05 +0.000117549432616215200000000000 0.000117549 +0.001175494398921728000000000000 0.00117549 +0.011754943057894710000000000000 0.0117549 +0.117549434304237400000000000000 0.117549 +SELECT CAST(my_double AS DECIMAL(65,30)), my_double FROM t1; +CAST(my_double AS DECIMAL(65,30)) my_double +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-09 +0.000000011754943450000000000000 1.175494345e-08 +0.000000117549434500000000000000 1.175494345e-07 +0.000001175494345000000000000000 1.175494345e-06 +0.000011754943450000000000000000 1.175494345e-05 +0.000117549434500000000000000000 0.0001175494345 +0.001175494345000000000000000000 0.001175494345 +0.011754943450000000000000000000 0.01175494345 +0.117549434500000000000000000000 0.1175494345 +SELECT CAST(my_varchar AS DECIMAL(65,30)), my_varchar FROM t1; +CAST(my_varchar AS DECIMAL(65,30)) my_varchar +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-9 +0.000000011754943450000000000000 1.175494345e-8 +0.000000117549434500000000000000 1.175494345e-7 +0.000001175494345000000000000000 1.175494345e-6 +0.000011754943450000000000000000 1.175494345e-5 +0.000117549434500000000000000000 1.175494345e-4 +0.001175494345000000000000000000 1.175494345e-3 +0.011754943450000000000000000000 1.175494345e-2 +0.117549434500000000000000000000 1.175494345e-1 +UPDATE t1 SET my_decimal = my_float; +Warnings: +Note 1265 Data truncated for column 'my_decimal' at row 1 +Note 1265 Data truncated for column 'my_decimal' at row 2 +Note 1265 Data truncated for column 'my_decimal' at row 3 +Note 1265 Data truncated for column 'my_decimal' at row 4 +Note 1265 Data truncated for column 'my_decimal' at row 5 +Note 1265 Data truncated for column 'my_decimal' at row 6 +Note 1265 Data truncated for column 'my_decimal' at row 7 +Note 1265 Data truncated for column 'my_decimal' at row 8 +Note 1265 Data truncated for column 'my_decimal' at row 9 +Note 1265 Data truncated for column 'my_decimal' at row 10 +Note 1265 Data truncated for column 'my_decimal' at row 11 +Note 1265 Data truncated for column 'my_decimal' at row 12 +Note 1265 Data truncated for column 'my_decimal' at row 13 +Note 1265 Data truncated for column 'my_decimal' at row 14 +Note 1265 Data truncated for column 'my_decimal' at row 15 +Note 1265 Data truncated for column 'my_decimal' at row 16 +Note 1265 Data truncated for column 'my_decimal' at row 17 +Note 1265 Data truncated for column 'my_decimal' at row 19 +Note 1265 Data truncated for column 'my_decimal' at row 20 +Note 1265 Data truncated for column 'my_decimal' at row 21 +Note 1265 Data truncated for column 'my_decimal' at row 22 +Note 1265 Data truncated for column 'my_decimal' at row 23 +Note 1265 Data truncated for column 'my_decimal' at row 26 +Note 1265 Data truncated for column 'my_decimal' at row 27 +Note 1265 Data truncated for column 'my_decimal' at row 30 +Note 1265 Data truncated for column 'my_decimal' at row 31 +Note 1265 Data truncated for column 'my_decimal' at row 32 +SELECT my_decimal, my_float FROM t1; +my_decimal my_float +0.000000000000000000000000000000 1.17549e-32 +0.000000000000000000000000000000 1.17549e-31 +0.000000000000000000000000000001 1.17549e-30 +0.000000000000000000000000000012 1.17549e-29 +0.000000000000000000000000000118 1.17549e-28 +0.000000000000000000000000001175 1.17549e-27 +0.000000000000000000000000011755 1.17549e-26 +0.000000000000000000000000117549 1.17549e-25 +0.000000000000000000000001175494 1.17549e-24 +0.000000000000000000000011754943 1.17549e-23 +0.000000000000000000000117549438 1.17549e-22 +0.000000000000000000001175494332 1.17549e-21 +0.000000000000000000011754943324 1.17549e-20 +0.000000000000000000117549434853 1.17549e-19 +0.000000000000000001175494374380 1.17549e-18 +0.000000000000000011754943743802 1.17549e-17 +0.000000000000000117549432474939 1.17549e-16 +0.000000000000001175494324749389 1.17549e-15 +0.000000000000011754943671010360 1.17549e-14 +0.000000000000117549429933840000 1.17549e-13 +0.000000000001175494380653563000 1.17549e-12 +0.000000000011754943372854760000 1.17549e-11 +0.000000000117549428524377200000 1.17549e-10 +0.000000001175494368510499000000 1.17549e-09 +0.000000011754943685104990000000 1.17549e-08 +0.000000117549433298336200000000 1.17549e-07 +0.000001175494389826781000000000 1.17549e-06 +0.000011754943443520460000000000 1.17549e-05 +0.000117549432616215200000000000 0.000117549 +0.001175494398921728000000000000 0.00117549 +0.011754943057894710000000000000 0.0117549 +0.117549434304237400000000000000 0.117549 +UPDATE t1 SET my_decimal = my_double; +Warnings: +Note 1265 Data truncated for column 'my_decimal' at row 1 +Note 1265 Data truncated for column 'my_decimal' at row 2 +Note 1265 Data truncated for column 'my_decimal' at row 3 +Note 1265 Data truncated for column 'my_decimal' at row 4 +Note 1265 Data truncated for column 'my_decimal' at row 5 +Note 1265 Data truncated for column 'my_decimal' at row 6 +Note 1265 Data truncated for column 'my_decimal' at row 7 +Note 1265 Data truncated for column 'my_decimal' at row 8 +Note 1265 Data truncated for column 'my_decimal' at row 9 +Note 1265 Data truncated for column 'my_decimal' at row 10 +Note 1265 Data truncated for column 'my_decimal' at row 11 +Note 1265 Data truncated for column 'my_decimal' at row 13 +Note 1265 Data truncated for column 'my_decimal' at row 14 +Note 1265 Data truncated for column 'my_decimal' at row 16 +Note 1265 Data truncated for column 'my_decimal' at row 18 +Note 1265 Data truncated for column 'my_decimal' at row 20 +Note 1265 Data truncated for column 'my_decimal' at row 31 +SELECT my_decimal, my_double FROM t1; +my_decimal my_double +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-09 +0.000000011754943450000000000000 1.175494345e-08 +0.000000117549434500000000000000 1.175494345e-07 +0.000001175494345000000000000000 1.175494345e-06 +0.000011754943450000000000000000 1.175494345e-05 +0.000117549434500000000000000000 0.0001175494345 +0.001175494345000000000000000000 0.001175494345 +0.011754943450000000000000000000 0.01175494345 +0.117549434500000000000000000000 0.1175494345 +UPDATE t1 SET my_decimal = my_varchar; +Warnings: +Note 1265 Data truncated for column 'my_decimal' at row 1 +Note 1265 Data truncated for column 'my_decimal' at row 2 +Note 1265 Data truncated for column 'my_decimal' at row 3 +Note 1265 Data truncated for column 'my_decimal' at row 4 +Note 1265 Data truncated for column 'my_decimal' at row 5 +Note 1265 Data truncated for column 'my_decimal' at row 6 +Note 1265 Data truncated for column 'my_decimal' at row 7 +Note 1265 Data truncated for column 'my_decimal' at row 8 +Note 1265 Data truncated for column 'my_decimal' at row 9 +Note 1265 Data truncated for column 'my_decimal' at row 10 +Note 1265 Data truncated for column 'my_decimal' at row 11 +SELECT my_decimal, my_varchar FROM t1; +my_decimal my_varchar +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-9 +0.000000011754943450000000000000 1.175494345e-8 +0.000000117549434500000000000000 1.175494345e-7 +0.000001175494345000000000000000 1.175494345e-6 +0.000011754943450000000000000000 1.175494345e-5 +0.000117549434500000000000000000 1.175494345e-4 +0.001175494345000000000000000000 1.175494345e-3 +0.011754943450000000000000000000 1.175494345e-2 +0.117549434500000000000000000000 1.175494345e-1 +DROP TABLE t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index a7087d46dca..0a96ec17fe6 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1050,3 +1050,38 @@ select cast(@non_existing_user_var/2 as DECIMAL); # --error 1427 create table t (d decimal(0,10)); + +# +# Bug #14268 (bad FLOAT->DECIMAL conversion) +# + +CREATE TABLE t1 ( + my_float FLOAT, + my_double DOUBLE, + my_varchar VARCHAR(50), + my_decimal DECIMAL(65,30) +); +SHOW CREATE TABLE t1; + +let $max_power= 32; +while ($max_power) +{ + eval INSERT INTO t1 SET my_float = 1.175494345e-$max_power, + my_double = 1.175494345e-$max_power, + my_varchar = '1.175494345e-$max_power'; + dec $max_power; +} +SELECT my_float, my_double, my_varchar FROM t1; + +SELECT CAST(my_float AS DECIMAL(65,30)), my_float FROM t1; +SELECT CAST(my_double AS DECIMAL(65,30)), my_double FROM t1; +SELECT CAST(my_varchar AS DECIMAL(65,30)), my_varchar FROM t1; + +UPDATE t1 SET my_decimal = my_float; +SELECT my_decimal, my_float FROM t1; +UPDATE t1 SET my_decimal = my_double; +SELECT my_decimal, my_double FROM t1; +UPDATE t1 SET my_decimal = my_varchar; +SELECT my_decimal, my_varchar FROM t1; + +DROP TABLE t1; diff --git a/strings/decimal.c b/strings/decimal.c index ea6ac2caf38..2fff4d75449 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -973,7 +973,7 @@ int double2decimal(double from, decimal_t *to) { /* TODO: fix it, when we'll have dtoa */ char s[400], *end; - sprintf(s, "%f", from); + sprintf(s, "%.16G", from); end= strend(s); return string2decimal(s, to, &end); } From 234bf9a70cc22f788ae655de1bb140e984918409 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Nov 2005 13:16:46 +0200 Subject: [PATCH 15/48] avoiding of calling Item::val_* methods family with opt_range mem_root, because its life time is too short. (BUG#14342) mysql-test/r/subselect_innodb.result: BUG#14342 test case mysql-test/t/subselect_innodb.test: BUG#14342 test case sql/opt_range.cc: avoiding of calling Item::val_* methods family with opt_range mem_root, because its life time is too short. --- mysql-test/r/subselect_innodb.result | 72 ++++++++++++++++++++++++++++ mysql-test/t/subselect_innodb.test | 54 +++++++++++++++++++++ sql/opt_range.cc | 19 +++++--- 3 files changed, 139 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index a23b584e510..4dec7882d58 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -172,3 +172,75 @@ group by country; countrycount smcnt country total_funds 1 1200 USA 1200 drop table t1; +CREATE TABLE `t1` ( +`t3_id` int NOT NULL, +`t1_id` int NOT NULL, +PRIMARY KEY (`t1_id`) +); +CREATE TABLE `t2` ( +`t2_id` int NOT NULL, +`t1_id` int NOT NULL, +`b` int NOT NULL, +PRIMARY KEY (`t2_id`), +UNIQUE KEY `idx_t2_t1_b` (`t1_id`,`b`) +) ENGINE=InnoDB; +CREATE TABLE `t3` ( +`t3_id` int NOT NULL +); +INSERT INTO `t3` VALUES (3); +select +(SELECT rs.t2_id +FROM t2 rs +WHERE rs.t1_id= +(SELECT lt.t1_id +FROM t1 lt +WHERE lt.t3_id=a.t3_id) +ORDER BY b DESC LIMIT 1) +from t3 AS a; +(SELECT rs.t2_id +FROM t2 rs +WHERE rs.t1_id= +(SELECT lt.t1_id +FROM t1 lt +WHERE lt.t3_id=a.t3_id) +ORDER BY b DESC LIMIT 1) +NULL +DROP PROCEDURE IF EXISTS p1; +create procedure p1() +begin +declare done int default 3; +repeat +select +(SELECT rs.t2_id +FROM t2 rs +WHERE rs.t1_id= +(SELECT lt.t1_id +FROM t1 lt +WHERE lt.t3_id=a.t3_id) +ORDER BY b DESC LIMIT 1) as x +from t3 AS a; +set done= done-1; +until done <= 0 end repeat; +end// +call p1(); +x +NULL +x +NULL +x +NULL +call p1(); +x +NULL +x +NULL +x +NULL +call p1(); +x +NULL +x +NULL +x +NULL +drop tables t1,t2,t3; diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index a07cc93ad68..4bfc4d17588 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -183,3 +183,57 @@ group by country; drop table t1; +# +# BUG#14342: wrong placement of subquery internals in complex queries +# +CREATE TABLE `t1` ( + `t3_id` int NOT NULL, + `t1_id` int NOT NULL, + PRIMARY KEY (`t1_id`) +); +CREATE TABLE `t2` ( + `t2_id` int NOT NULL, + `t1_id` int NOT NULL, + `b` int NOT NULL, + PRIMARY KEY (`t2_id`), + UNIQUE KEY `idx_t2_t1_b` (`t1_id`,`b`) +) ENGINE=InnoDB; +CREATE TABLE `t3` ( + `t3_id` int NOT NULL +); +INSERT INTO `t3` VALUES (3); +select + (SELECT rs.t2_id + FROM t2 rs + WHERE rs.t1_id= + (SELECT lt.t1_id + FROM t1 lt + WHERE lt.t3_id=a.t3_id) + ORDER BY b DESC LIMIT 1) +from t3 AS a; +# repeat above query in SP +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +--enable_warnings +delimiter //; +create procedure p1() +begin + declare done int default 3; + repeat + select + (SELECT rs.t2_id + FROM t2 rs + WHERE rs.t1_id= + (SELECT lt.t1_id + FROM t1 lt + WHERE lt.t3_id=a.t3_id) + ORDER BY b DESC LIMIT 1) as x + from t3 AS a; + set done= done-1; + until done <= 0 end repeat; +end// +delimiter ;// +call p1(); +call p1(); +call p1(); +drop tables t1,t2,t3; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 63a49a46110..de52811c12f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5759,10 +5759,17 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, MEM_ROOT *old_root= thd->mem_root; /* The following call may change thd->mem_root */ QUICK_RANGE_SELECT *quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0); + /* save mem_root set by QUICK_RANGE_SELECT constructor */ + MEM_ROOT *alloc= thd->mem_root; KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; QUICK_RANGE *range; uint part; + /* + return back default mem_root (thd->mem_root) changed by + QUICK_RANGE_SELECT constructor + */ + thd->mem_root= old_root; if (!quick) return 0; /* no ranges found */ @@ -5774,7 +5781,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, quick->records= records; if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error || - !(range= new QUICK_RANGE())) + !(range= new(alloc) QUICK_RANGE())) goto err; // out of memory range->min_key=range->max_key=(char*) ref->key_buff; @@ -5809,20 +5816,20 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, QUICK_RANGE *null_range; *ref->null_ref_key= 1; // Set null byte then create a range - if (!(null_range= new QUICK_RANGE((char*)ref->key_buff, ref->key_length, - (char*)ref->key_buff, ref->key_length, - EQ_RANGE))) + if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff, + ref->key_length, + (char*)ref->key_buff, + ref->key_length, + EQ_RANGE))) goto err; *ref->null_ref_key= 0; // Clear null byte if (insert_dynamic(&quick->ranges,(gptr)&null_range)) goto err; } - thd->mem_root= old_root; return quick; err: - thd->mem_root= old_root; delete quick; return 0; } From 57923440f3711dd6287df9d8f54e94b9031c7ec0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Nov 2005 16:17:43 +0300 Subject: [PATCH 16/48] fix --ansi --pedantic compilation failure --- sql/spatial.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/spatial.h b/sql/spatial.h index acd16172fcc..ec5e80e00fd 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -240,8 +240,8 @@ public: static Geometry *create_from_wkt(Geometry_buffer *buffer, Gis_read_stream *trs, String *wkt, bool init_stream=1); - static int Geometry::create_from_wkb(Geometry_buffer *buffer, - const char *wkb, uint32 len, String *res); + static int create_from_wkb(Geometry_buffer *buffer, + const char *wkb, uint32 len, String *res); int as_wkt(String *wkt, const char **end) { uint32 len= get_class_info()->m_name.length; From 0e878d7e541983757bc0b31e7caa8a16a5fd2896 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Nov 2005 01:44:35 +0100 Subject: [PATCH 17/48] mysql.spec.sh: Always use bundled zlib support-files/mysql.spec.sh: Always use bundled zlib --- support-files/mysql.spec.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 5cd9d1646a4..7a1219736ae 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -249,6 +249,7 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --includedir=%{_includedir} \ --mandir=%{_mandir} \ --enable-thread-safe-client \ + --with-zlib-dir=bundled \ --with-readline ; # Add this for more debugging support # --with-debug From 1b65c7041383073eee99deebe8569399f06e83ee Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Nov 2005 15:08:15 +0300 Subject: [PATCH 18/48] Fix Bug#13894 Server crashes on update of CSV table mysql-test/r/csv.result: update result file mysql-test/t/csv.test: Add test for a bug sql/examples/ha_tina.cc: sort function should return reverted values for chains to be sorted in the right orded. don't do a strange memmove --- mysql-test/r/csv.result | 20 ++++++++++++++++++++ mysql-test/t/csv.test | 18 ++++++++++++++++++ sql/examples/ha_tina.cc | 19 +++++++++---------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index ea0d34271b5..78a1f34636c 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -4929,3 +4929,23 @@ Warnings: Note 1051 Unknown table 't2' Note 1051 Unknown table 't3' Note 1051 Unknown table 't4' +DROP TABLE IF EXISTS bug13894; +CREATE TABLE bug13894 ( val integer ) ENGINE = CSV; +INSERT INTO bug13894 VALUES (5); +INSERT INTO bug13894 VALUES (10); +INSERT INTO bug13894 VALUES (11); +INSERT INTO bug13894 VALUES (10); +SELECT * FROM bug13894; +val +5 +10 +11 +10 +UPDATE bug13894 SET val=6 WHERE val=10; +SELECT * FROM bug13894; +val +5 +11 +6 +6 +DROP TABLE bug13894; diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 2ac46d75f9a..61b4f9607a5 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1314,4 +1314,22 @@ select period from t1; drop table if exists t1,t2,t3,t4; +# +# Bug #13894 Server crashes on update of CSV table +# + +--disable_warnings +DROP TABLE IF EXISTS bug13894; +--enable_warnings + +CREATE TABLE bug13894 ( val integer ) ENGINE = CSV; +INSERT INTO bug13894 VALUES (5); +INSERT INTO bug13894 VALUES (10); +INSERT INTO bug13894 VALUES (11); +INSERT INTO bug13894 VALUES (10); +SELECT * FROM bug13894; +UPDATE bug13894 SET val=6 WHERE val=10; +SELECT * FROM bug13894; +DROP TABLE bug13894; + # End of 4.1 tests diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 8a9aa91c680..f4544670ed9 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -58,12 +58,16 @@ static int tina_init= 0; ** TINA tables *****************************************************************************/ -/* - Used for sorting chains. +/* + Used for sorting chains with qsort(). */ int sort_set (tina_set *a, tina_set *b) { - return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) ); + /* + We assume that intervals do not intersect. So, it is enought to compare + any two points. Here we take start of intervals for comparison. + */ + return ( a->begin > b->begin ? -1 : ( a->begin < b->begin ? 1 : 0 ) ); } static byte* tina_get_key(TINA_SHARE *share,uint *length, @@ -739,13 +743,8 @@ int ha_tina::rnd_end() qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); for (ptr= chain; ptr < chain_ptr; ptr++) { - /* We peek a head to see if this is the last chain */ - if (ptr+1 == chain_ptr) - memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, - length - (size_t)ptr->end); - else - memmove((caddr_t)share->mapped_file + ptr->begin, (caddr_t)share->mapped_file + ptr->end, - (size_t)((ptr++)->begin - ptr->end)); + memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, + length - (size_t)ptr->end); length= length - (size_t)(ptr->end - ptr->begin); } From b0829011b8053058f0419aee48da03970654cbc6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Nov 2005 02:11:12 +0300 Subject: [PATCH 19/48] Fix Bug#14672 Bug in deletion mysql-test/r/csv.result: correct result file mysql-test/t/csv.test: Add test for a bug sql/examples/ha_tina.cc: Add O_APPEND flag to my_open. We should always add rows to the end of file --- mysql-test/r/csv.result | 27 +++++++++++++++++++++++++++ mysql-test/t/csv.test | 19 +++++++++++++++++++ sql/examples/ha_tina.cc | 3 ++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index 78a1f34636c..2e3d11ad461 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -4949,3 +4949,30 @@ val 6 6 DROP TABLE bug13894; +DROP TABLE IF EXISTS bug14672; +CREATE TABLE bug14672 (c1 integer) engine = CSV; +INSERT INTO bug14672 VALUES (1), (2), (3); +SELECT * FROM bug14672; +c1 +1 +2 +3 +DELETE FROM bug14672 WHERE c1 = 2; +SELECT * FROM bug14672; +c1 +1 +3 +INSERT INTO bug14672 VALUES (4); +SELECT * FROM bug14672; +c1 +1 +3 +4 +INSERT INTO bug14672 VALUES (5); +SELECT * FROM bug14672; +c1 +1 +3 +4 +5 +DROP TABLE bug14672; diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 61b4f9607a5..5b693335a43 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1332,4 +1332,23 @@ UPDATE bug13894 SET val=6 WHERE val=10; SELECT * FROM bug13894; DROP TABLE bug13894; +# +# Bug #14672 Bug in deletion +# + +--disable_warnings +DROP TABLE IF EXISTS bug14672; +--enable_warnings + +CREATE TABLE bug14672 (c1 integer) engine = CSV; +INSERT INTO bug14672 VALUES (1), (2), (3); +SELECT * FROM bug14672; +DELETE FROM bug14672 WHERE c1 = 2; +SELECT * FROM bug14672; +INSERT INTO bug14672 VALUES (4); +SELECT * FROM bug14672; +INSERT INTO bug14672 VALUES (5); +SELECT * FROM bug14672; +DROP TABLE bug14672; + # End of 4.1 tests diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index f4544670ed9..91e42bfea31 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -166,7 +166,8 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table) thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); - if ((share->data_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1) + if ((share->data_file= my_open(data_file_name, O_RDWR|O_APPEND, + MYF(0))) == -1) goto error2; /* We only use share->data_file for writing, so we scan to the end to append */ From 502495271ddb0e289c0bd778dbad25e089574b2c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Nov 2005 22:41:36 -0800 Subject: [PATCH 20/48] Post review fixes. --- mysql-test/r/view.result | 8 ++++---- sql/share/errmsg.txt | 2 -- sql/sql_table.cc | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9b434ebe9f4..b92a50d079f 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2339,17 +2339,17 @@ CREATE TABLE t1(id INT); CREATE VIEW v1 AS SELECT id FROM t1; OPTIMIZE TABLE v1; Table Op Msg_type Msg_text -test.v1 optimize note You cannot apply optimize to a view +test.v1 optimize note Unknown table 'test.v1' ANALYZE TABLE v1; Table Op Msg_type Msg_text -test.v1 analyze note You cannot apply analyze to a view +test.v1 analyze note Unknown table 'test.v1' REPAIR TABLE v1; Table Op Msg_type Msg_text -test.v1 repair note You cannot apply repair to a view +test.v1 repair note Unknown table 'test.v1' DROP TABLE t1; OPTIMIZE TABLE v1; Table Op Msg_type Msg_text -test.v1 optimize note You cannot apply optimize to a view +test.v1 optimize note Unknown table 'test.v1' Warnings: Error 1146 Table 'test.t1' doesn't exist Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 24e1d4b6b81..f85bda90e81 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5421,5 +5421,3 @@ ER_NO_REFERENCED_ROW_2 23000 eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" -ER_CHECK_NOT_BASE_TABLE 42000 - eng "You cannot apply %s to a view" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b339e6a81e9..fb190f5524f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2335,7 +2335,7 @@ send_result_message: { char buf[ERRMSGSIZE+20]; uint length= my_snprintf(buf, ERRMSGSIZE, - ER(ER_CHECK_NOT_BASE_TABLE), operator_name); + ER(ER_BAD_TABLE_ERROR), table_name); protocol->store("note", 4, system_charset_info); protocol->store(buf, length, system_charset_info); } From 467deb4cb7aeb456086838cadcdf10b25b667a36 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 09:23:43 +0300 Subject: [PATCH 21/48] BUG#14480, attempt2: In CREATE ... SELECT ..., don't count the same field twice when calculating table->null_fields. mysql-test/r/create.result: Testcase for BUG#14480 mysql-test/t/create.test: Testcase for BUG#14480 sql/sql_table.cc: BUG#14480: For CREATE ... SELECT ... a field list passed to mysql_prepare_table() contains instances of create_field for both create-list and select-list. mysql_prepare_table() matches elements that refer to the same field, and joins them together. When the "join" is performed, both of create_field structures has already been counted in "null_fields". This fix makes sure that "null_fields" contains the correct value after two create_field structures have been joined. --- mysql-test/r/create.result | 68 +++++++++++++++++++++++++++++++++++++- mysql-test/t/create.test | 64 ++++++++++++++++++++++++++++++++++- sql/sql_table.cc | 9 ++++- 3 files changed, 138 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 55ad6e3304a..0c3b7d5d5e7 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t5; drop database if exists mysqltest; create table t1 (b char(0)); insert into t1 values (""),(null); @@ -632,3 +632,69 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +CREATE TABLE t2 ( +a int(11) default NULL +); +insert into t2 values(111); +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select a, 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', + `b` int(11) NOT NULL default '0', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', + `b` int(11) NOT NULL default '0', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin, +b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', + `b` int(11) NOT NULL default '0', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1 ( +a1 int not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, +primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1; +drop table t1, t2; +create table t1 ( +a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, +primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t1, t2; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 966be8b58a3..3bdc970027b 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t5; drop database if exists mysqltest; --enable_warnings @@ -534,4 +534,66 @@ create table t1 ( show create table t1; drop table t1; +# +# BUG#14480: assert failure in CREATE ... SELECT because of wrong +# calculation of number of NULLs. +# +CREATE TABLE t2 ( + a int(11) default NULL +); +insert into t2 values(111); + +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select a, 1 as b from t2 ; +show create table t1; +drop table t1; + +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +drop table t1; + +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin, + b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +drop table t1, t2; + +create table t1 ( + a1 int not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); + +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, + primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; + +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1; + +drop table t1, t2; +create table t1 ( + a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); + +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, + primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; + +drop table t1, t2; + # End of 4.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dcbc2018b49..40777682251 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -647,8 +647,15 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->pack_length= dup_field->pack_length; sql_field->create_length_to_internal_length(); sql_field->decimals= dup_field->decimals; - sql_field->flags= dup_field->flags; sql_field->unireg_check= dup_field->unireg_check; + /* + We're making one field from two, the result field will have + dup_field->flags as flags. If we've incremented null_fields + because of sql_field->flags, decrement it back. + */ + if (!(sql_field->flags & NOT_NULL_FLAG)) + null_fields--; + sql_field->flags= dup_field->flags; it2.remove(); // Remove first (create) definition select_field_pos--; break; From 50f48187f2f135b458aee47c561b3afe7df5aa07 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 16:18:46 +0100 Subject: [PATCH 22/48] Fix for BUG#14703 "Valgrind error when inserting 0 into a BIT column (like in type_bit.test)": test "length" first (otherwise when "length" is 0, the *from invalid access still triggers a Valgrind warning). I wrote to the Valgrind authors in case this is something fixable in Valgrind (normally the decision to issue a warning is based on the simulated CPU condition code, which should not be undefined here). BUILD/compile-pentium64-valgrind-max: putting this script in sync with compile-pentium-valgrind-max, otherwise we didn't have the federated engine compiled in. mysql-test/r/read_only.result: result update sql/field.cc: To avoid a Valgrind warning running the type_bit test: test "length" first (otherwise when "length" is 0, the *from invalid access still triggers a Valgrind warning). --- BUILD/compile-pentium64-valgrind-max | 4 ++-- mysql-test/r/read_only.result | 2 ++ sql/field.cc | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max index 2e4ff8e0082..ef932920130 100755 --- a/BUILD/compile-pentium64-valgrind-max +++ b/BUILD/compile-pentium64-valgrind-max @@ -3,13 +3,13 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium64_cflags $debug_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max" +extra_flags="$pentium64_cflags $debug_cflags $max_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs" # We want to test isam when building with valgrind -extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-raid --with-ndbcluster" +extra_configs="$extra_configs $max_leave_isam_configs --with-isam" . "$path/FINISH.sh" diff --git a/mysql-test/r/read_only.result b/mysql-test/r/read_only.result index 09a0861e0c4..55a14bcaec8 100644 --- a/mysql-test/r/read_only.result +++ b/mysql-test/r/read_only.result @@ -14,6 +14,8 @@ create table t3 (a int); ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement insert into t1 values(1); ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1 set a=1 where 1=0; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement delete t1,t2 from t1,t2 where t1.a=t2.a; diff --git a/sql/field.cc b/sql/field.cc index 03d20b4bfe2..18ef77230f2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7931,7 +7931,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) { int delta; - for (; !*from && length; from++, length--); // skip left 0's + for (; length && !*from; from++, length--); // skip left 0's delta= field_length - length; if (delta < -1 || @@ -8151,7 +8151,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) int delta; uchar bits= create_length & 7; - for (; !*from && length; from++, length--); // skip left 0's + for (; length && !*from; from++, length--); // skip left 0's delta= field_length - length; if (delta < 0 || From 9725d32b5193f7d47eac67abd5aafd38d9a1b8fa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 18:31:48 +0100 Subject: [PATCH 23/48] Bug#13707 - Server crash with INSERT DELAYED on MyISAM table Initialized 'ptr' for a newly instantiated varstring field. This is required by INSERT DELAYED. No test case. This is a migration issue. There are two shell scripts attached to the bug report. They can be used for testing. sql/field.cc: Bug#13707 - Server crash with INSERT DELAYED on MyISAM table Initialized 'ptr' for a newly instantiated varstring field. This is required by INSERT DELAYED. --- sql/field.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 03d20b4bfe2..f7f7c22bfe9 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6202,9 +6202,16 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) This is done to ensure that ALTER TABLE will convert old VARCHAR fields to now VARCHAR fields. */ - return new Field_varstring(field_length, maybe_null(), - field_name, new_table, - charset()); + Field *new_field= new Field_varstring(field_length, maybe_null(), + field_name, new_table, + charset()); + /* + delayed_insert::get_local_table() needs a ptr copied from old table. + This is what other new_field() methods do too. The above method of + Field_varstring sets ptr to NULL. + */ + new_field->ptr= ptr; + return new_field; } /**************************************************************************** From 19a38fb186ecda3a037a4a0fa87d3400544b4c4e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Nov 2005 11:26:02 +0300 Subject: [PATCH 24/48] Trivial post-merge fixes --- myisam/mi_key.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myisam/mi_key.c b/myisam/mi_key.c index 0ee34c2f41e..4cabfc91197 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -241,8 +241,8 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, if (!(*key++= (char) 1-*old++)) /* Copy null marker */ { k_length-=length; -->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) - + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) + { k_length-=2; /* Skip length */ old+= 2; } From f76ff56512e1e10856816d6e5031f2b44df0990f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Nov 2005 09:34:46 +0300 Subject: [PATCH 25/48] BUG#14480: post-fix: use the default field value from CREATE list too. --- mysql-test/r/create.result | 11 +++++++++++ mysql-test/t/create.test | 7 +++++++ sql/sql_table.cc | 1 + 3 files changed, 19 insertions(+) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 0c3b7d5d5e7..a933027cdb1 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -697,4 +697,15 @@ a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; +create table t2 ( a int default 3, b int default 3) +select a1,a2 from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) default '3', + `b` int(11) default '3', + `a1` int(11) default NULL, + `a2` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 3bdc970027b..c9d16916f8a 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -594,6 +594,13 @@ create table t2 ( primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +# Test the default value +drop table t2; + +create table t2 ( a int default 3, b int default 3) + select a1,a2 from t1; +show create table t2; + drop table t1, t2; # End of 4.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 40777682251..d6a7d76ac99 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -639,6 +639,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, else { /* Field redefined */ + sql_field->def= dup_field->def; sql_field->sql_type= dup_field->sql_type; sql_field->charset= (dup_field->charset ? dup_field->charset : From 18b488d7f9d14d3567df853fcb148b18d12ad529 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Nov 2005 14:47:58 +0300 Subject: [PATCH 26/48] BUG#14480 post-fix: merge to 5.0 --- mysql-test/r/create.result | 22 +++++++++++++++++----- mysql-test/t/create.test | 7 +++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 1595a1aeeaf..a201af78518 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -662,11 +662,14 @@ create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) ) select a, 1 as b from t2 ; +Warnings: +Warning 1364 Field 'a' doesn't have a default value +Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', - `b` int(11) NOT NULL default '0', + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, + `b` int(11) NOT NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -674,11 +677,14 @@ create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) ) select 'a' as a , 1 as b from t2 ; +Warnings: +Warning 1364 Field 'a' doesn't have a default value +Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', - `b` int(11) NOT NULL default '0', + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, + `b` int(11) NOT NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -686,11 +692,13 @@ create table t1 ( a varchar(12) charset utf8 collate utf8_bin, b int not null, primary key (a) ) select 'a' as a , 1 as b from t2 ; +Warnings: +Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', - `b` int(11) NOT NULL default '0', + `b` int(11) NOT NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; @@ -704,6 +712,8 @@ a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +Warnings: +Warning 1364 Field 'a1' doesn't have a default value drop table t2; create table t2 ( a1 varchar(12) charset utf8 collate utf8_bin, @@ -719,6 +729,8 @@ a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +Warnings: +Warning 1364 Field 'a1' doesn't have a default value drop table t2; create table t2 ( a int default 3, b int default 3) select a1,a2 from t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 9d66b108469..470a7bcbb59 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -563,6 +563,7 @@ CREATE TABLE t2 ( ); insert into t2 values(111); +--warning 1364 create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) @@ -570,6 +571,7 @@ create table t1 ( show create table t1; drop table t1; +--warning 1364 create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) @@ -577,6 +579,7 @@ create table t1 ( show create table t1; drop table t1; +--warning 1364 create table t1 ( a varchar(12) charset utf8 collate utf8_bin, b int not null, primary key (a) @@ -590,6 +593,7 @@ create table t1 ( ); insert into t1 values (1,1,1, 1,1,1, 1,1,1); +--warning 1364 create table t2 ( a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, @@ -597,17 +601,20 @@ create table t2 ( ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; drop table t2; +--warning 1364 create table t2 ( a1 varchar(12) charset utf8 collate utf8_bin, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1; drop table t1, t2; +--warning 1364 create table t1 ( a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int ); insert into t1 values (1,1,1, 1,1,1, 1,1,1); +--warning 1364 create table t2 ( a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, From 8a719ee91b56b1de86fc42f7ad424132102ffed6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Nov 2005 14:12:44 +0100 Subject: [PATCH 27/48] Raise the version number to 5.0.17. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index c36d24a5bc5..52dec85df8c 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.16) +AM_INIT_AUTOMAKE(mysql, 5.0.17) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -18,7 +18,7 @@ SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=16 +NDB_VERSION_BUILD=17 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From b5e8347f81fd37fba640e29bbfc71e2aeb33b5c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Nov 2005 16:51:00 +0100 Subject: [PATCH 28/48] Fixed BUG#14719: Views DEFINER grammar is incorrect Corrected the syntax for the current_user() case. (It's "definer = current_user[()]", not just "current_user[()]".) mysql-test/r/view.result: New test case for BUG#14719 mysql-test/t/view.test: New test case for BUG#14719 sql/sql_yacc.yy: Corrected the CREATE VIEW syntax for the current_user() DEFINER case. (It's "definer = current_user[()]", not just "current_user[()]".) --- mysql-test/r/view.result | 10 ++++++++++ mysql-test/t/view.test | 13 +++++++++++++ sql/sql_yacc.yy | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b31ec9a3bab..581a27aa7e5 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2375,3 +2375,13 @@ Warnings: Error 1146 Table 'test.t1' doesn't exist Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them DROP VIEW v1; +create definer = current_user() sql security invoker view v1 as select 1; +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` +drop view v1; +create definer = current_user sql security invoker view v1 as select 1; +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` +drop view v1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4e287375e5d..3f599c62fff 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2240,3 +2240,16 @@ DROP TABLE t1; OPTIMIZE TABLE v1; DROP VIEW v1; + + +# +# BUG#14719: Views DEFINER grammar is incorrect +# + +create definer = current_user() sql security invoker view v1 as select 1; +show create view v1; +drop view v1; + +create definer = current_user sql security invoker view v1 as select 1; +show create view v1; +drop view v1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 109dcd7e86a..abc440df1c5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9008,7 +9008,7 @@ view_user: thd->lex->create_view_definer)) YYABORT; } - | CURRENT_USER optional_braces + | DEFINER_SYM EQ CURRENT_USER optional_braces { THD *thd= YYTHD; if (!(thd->lex->create_view_definer= From 75fab5146f0c230115ddc6e2e1e0f1b9c213f3d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Nov 2005 20:31:01 +0300 Subject: [PATCH 29/48] A fix and a test case for Bug#13488 "Left outer join query incorrectly gives MYSQL_DATA_TRUNCATED" sql/sql_cursor.cc: A partial fix for Bug#13488 "Left outer join query incorrectly gives MYSQL_DATA_TRUNCATED": send the correct metadata of the cursor result set at execute. The full fix would be to make sure that the metadata doesn't change between prepare and execute. tests/mysql_client_test.c: A test case for Bug#13488 "Left outer join query incorrectly gives MYSQL_DATA_TRUNCATED" --- sql/sql_cursor.cc | 26 ++++++++++----- tests/mysql_client_test.c | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index e8da691ea18..07be9efa6ac 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -558,6 +558,24 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) result->prepare(item_list, &fake_unit) || table->file->ha_rnd_init(TRUE)); thd->restore_active_arena(this, &backup_arena); + if (rc == 0) + { + /* + Now send the result set metadata to the client. We need to do it + here, as in Select_materialize::send_fields the exact column types + are not yet known. The new types may differ from the original ones + sent at prepare if some of them were altered by MySQL HEAP tables + mechanism -- used when create_tmp_field_from_item may alter the + original column type. + + We can't simply supply SEND_EOF flag to send_fields, because + send_fields doesn't flush the network buffer. + */ + rc= result->send_fields(item_list, Protocol::SEND_NUM_ROWS); + thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; + result->send_eof(); + thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + } return rc; } @@ -647,14 +665,6 @@ bool Select_materialize::send_fields(List &list, uint flags) if (create_result_table(unit->thd, unit->get_unit_column_types(), FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, "")) return TRUE; - /* - We can't simply supply SEND_EOF flag to send_fields, because send_fields - doesn't flush the network buffer. - */ - rc= result->send_fields(list, Protocol::SEND_NUM_ROWS); - thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; - result->send_eof(); - thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; return rc; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 949c3d5bf1c..b065a0dfa03 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14419,6 +14419,74 @@ static void test_bug14210() myquery(rc); } +/* Bug#13488 */ + +static void test_bug13488() +{ + MYSQL_BIND bind[3]; + MYSQL_STMT *stmt1; + int rc, f1, f2, f3, i; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select * from t1 left join t2 on f1=f2 where f1=1"; + + myheader("test_bug13488"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (f1 int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "create table t2 (f2 int not null primary key, " + "f3 int not null)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t2 values (1,2), (2,4)"); + myquery(rc); + + memset(bind, 0, sizeof(bind)); + for (i= 0; i < 3; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer_length= 4; + bind[i].length= 0; + } + bind[0].buffer=&f1; + bind[1].buffer=&f2; + bind[2].buffer=&f3; + + stmt1= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt1,STMT_ATTR_CURSOR_TYPE, (const void *)&type); + check_execute(stmt1, rc); + + rc= mysql_stmt_prepare(stmt1, query, strlen(query)); + check_execute(stmt1, rc); + + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_bind_result(stmt1, bind); + check_execute(stmt1, rc); + + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_free_result(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_reset(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + + if (!opt_silent) + printf("data is: %s", (f1 == 1 && f2 == 1 && f3 == 2)?"OK": + "wrong"); + DIE_UNLESS(f1 == 1 && f2 == 1 && f3 == 2); + rc= mysql_query(mysql, "drop table t1, t2"); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14675,6 +14743,7 @@ static struct my_tests_st my_tests[]= { { "test_bug11904", test_bug11904 }, { "test_bug12243", test_bug12243 }, { "test_bug14210", test_bug14210 }, + { "test_bug13488", test_bug13488 }, { 0, 0 } }; From d295807e88d8efc51c0d598f1ce6d22e78c9ee61 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 14:24:54 +0100 Subject: [PATCH 30/48] Provide a default "minimum thread stack size" PTHREAD_STACK_MIN where it is missing. (Currently, affects only BSD with Linuxthreads) --- server-tools/instance-manager/priv.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc index a5040aa2e83..e39c12f4ebb 100644 --- a/server-tools/instance-manager/priv.cc +++ b/server-tools/instance-manager/priv.cc @@ -76,6 +76,9 @@ int set_stacksize_n_create_thread(pthread_t *thread, pthread_attr_t *attr, int rc= 0; #ifndef __WIN__ +#ifndef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 32768 +#endif /* Set stack size to be safe on the platforms with too small default thread stack. From 96ae0b92b22916c10b92c78862f5daf10e2b329d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 17:05:19 +0300 Subject: [PATCH 31/48] Fix a comment. sql/sql_cursor.cc: A post-review fix for Bug#13488 --- sql/sql_cursor.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 07be9efa6ac..fc169fe18e8 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -561,12 +561,13 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) if (rc == 0) { /* - Now send the result set metadata to the client. We need to do it - here, as in Select_materialize::send_fields the exact column types - are not yet known. The new types may differ from the original ones - sent at prepare if some of them were altered by MySQL HEAP tables - mechanism -- used when create_tmp_field_from_item may alter the - original column type. + Now send the result set metadata to the client. We need to + do it here, as in Select_materialize::send_fields the items + for column types are not yet created (send_fields requires + a list of items). The new types may differ from the original + ones sent at prepare if some of them were altered by MySQL + HEAP tables mechanism -- used when create_tmp_field_from_item + may alter the original column type. We can't simply supply SEND_EOF flag to send_fields, because send_fields doesn't flush the network buffer. From 6e56f7e0a9870aee1435a0eb2870472b2263b26d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 15:12:22 +0100 Subject: [PATCH 32/48] Declaring some class members public for BUG#12377: "Item_date_add_interval needs to have the int_type member as Public". As explained in the bug report, this change is is to help http://search.cpan.org/~philips/DBIx-MyParse-0.20/ So please keep those members public. sql/item_func.h: declaring some class members public for BUG#12377 sql/item_strfunc.h: declaring some class members public for BUG#12377 sql/item_timefunc.h: declaring some class members public for BUG#12377 --- sql/item_func.h | 4 ++-- sql/item_strfunc.h | 2 +- sql/item_timefunc.h | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sql/item_func.h b/sql/item_func.h index 5d6cc445317..2c4976d1152 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -938,7 +938,6 @@ class user_var_entry; class Item_func_set_user_var :public Item_func { enum Item_result cached_result_type; - LEX_STRING name; user_var_entry *entry; char buffer[MAX_FIELD_WIDTH]; String value; @@ -952,6 +951,7 @@ class Item_func_set_user_var :public Item_func public: + LEX_STRING name; // keep it public Item_func_set_user_var(LEX_STRING a,Item *b) :Item_func(b), cached_result_type(INT_RESULT), name(a) {} @@ -972,10 +972,10 @@ public: class Item_func_get_user_var :public Item_func { - LEX_STRING name; user_var_entry *var_entry; public: + LEX_STRING name; // keep it public Item_func_get_user_var(LEX_STRING a): Item_func(), name(a) {} double val(); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 5525c046b95..87aee9ac25c 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -614,8 +614,8 @@ public: class Item_func_conv_charset :public Item_str_func { - CHARSET_INFO *conv_charset; public: + CHARSET_INFO *conv_charset; // keep it public Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a) { conv_charset=cs; } String *val_str(String *); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 16c64620369..ce9d6b0a7aa 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -607,12 +607,12 @@ enum interval_type class Item_date_add_interval :public Item_date_func { - const interval_type int_type; String value; - const bool date_sub_interval; enum_field_types cached_field_type; public: + const interval_type int_type; // keep it public + const bool date_sub_interval; // keep it public Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg) :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} String *val_str(String *); @@ -628,10 +628,10 @@ public: class Item_extract :public Item_int_func { - const interval_type int_type; String value; bool date_value; public: + const interval_type int_type; // keep it public Item_extract(interval_type type_arg, Item *a) :Item_int_func(a), int_type(type_arg) {} longlong val_int(); @@ -856,8 +856,8 @@ enum date_time_format class Item_func_get_format :public Item_str_func { - const timestamp_type type; public: + const timestamp_type type; // keep it public Item_func_get_format(timestamp_type type_arg, Item *a) :Item_str_func(a), type(type_arg) {} From 0c97fbef01d680822c365fd062c19f3d947c39ec Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 18:58:33 +0400 Subject: [PATCH 33/48] Fix for bug #14822: Test "mysqldump" fails, "result" protocol seems wrong. mysql-test/t/mysqldump.test: Fix for bug #14822: Test "mysqldump" fails, "result" protocol seems wrong. 2>&1 added to be able to see error messages. --- mysql-test/r/mysqldump.result | 10 ++++++++++ mysql-test/t/mysqldump.test | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 82a761252b5..2e25019ad6f 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1614,6 +1614,16 @@ mysqldump: Couldn't find table: "t\1" mysqldump: Couldn't find table: "t/1" +mysqldump: Couldn't find table: "T_1" + +mysqldump: Couldn't find table: "T%1" + +mysqldump: Couldn't find table: "T'1" + +mysqldump: Couldn't find table: "T_1" + +mysqldump: Couldn't find table: "T_" + test_sequence ------ Testing with illegal database names ------ mysqldump: Got error: 1049: Unknown database 'mysqldump_test_d' when selecting the database diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 91a87e2c774..0dceba08031 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -658,19 +658,19 @@ select '------ Testing with illegal table names ------' as test_sequence ; --exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t/1" 2>&1 --error 6 ---exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "T_1" 2>&1 --error 6 ---exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T%1" +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "T%1" 2>&1 --error 6 ---exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T'1" +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "T'1" 2>&1 --error 6 ---exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "T_1" 2>&1 --error 6 ---exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_" +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "T_" 2>&1 --disable_query_log select '------ Testing with illegal database names ------' as test_sequence ; From fca8f01abcc7ba150773cda3aeb5322a95a210d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 08:24:21 -0800 Subject: [PATCH 34/48] Added handlerton flag to make storage engines invisable via flag. mysql-test/r/ps_1general.result: Remove binlog from visable engine list. sql/handler.h: Added documentation to HTON's sql/log.cc: binlog now has hidden flag show that it does now show up in show storage engine list. sql/sql_show.cc: Flag removes engines from view in show storage engines --- mysql-test/r/ps_1general.result | 1 - sql/handler.h | 5 +++-- sql/log.cc | 2 +- sql/sql_show.cc | 23 +++++++++++++---------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index d41d1b74ca7..aba3da02c4c 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -332,7 +332,6 @@ CSV YES/NO CSV storage engine ndbcluster YES/NO Clustered, fault-tolerant, memory-based tables FEDERATED YES/NO Federated MySQL storage engine MRG_MYISAM YES/NO Collection of identical MyISAM tables -binlog YES/NO This is a meta storage engine to represent the binlog in a transaction ISAM YES/NO Obsolete storage engine drop table if exists t5; prepare stmt1 from ' drop table if exists t5 ' ; diff --git a/sql/handler.h b/sql/handler.h index e317f95b990..be188f7cacd 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -401,8 +401,9 @@ struct show_table_alias_st { /* Possible flags of a handlerton */ #define HTON_NO_FLAGS 0 #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) -#define HTON_ALTER_NOT_SUPPORTED (1 << 1) -#define HTON_CAN_RECREATE (1 << 2) +#define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter +#define HTON_CAN_RECREATE (1 << 2) //Delete all is used fro truncate +#define HTON_HIDDEN (1 << 3) //Engine does not appear in lists typedef struct st_thd_trans { diff --git a/sql/log.cc b/sql/log.cc index 7ea2dba2144..4b3d6698051 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -67,7 +67,7 @@ handlerton binlog_hton = { NULL, /* create_cursor_read_view */ NULL, /* set_cursor_read_view */ NULL, /* close_cursor_read_view */ - HTON_NO_FLAGS + HTON_HIDDEN }; /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b4b24e0b6be..ef5db767809 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -70,17 +70,20 @@ bool mysqld_show_storage_engines(THD *thd) handlerton **types; for (types= sys_table_types; *types; types++) { - protocol->prepare_for_resend(); - protocol->store((*types)->name, system_charset_info); - const char *option_name= show_comp_option_name[(int) (*types)->state]; + if (!((*types)->flags & HTON_HIDDEN)) + { + protocol->prepare_for_resend(); + protocol->store((*types)->name, system_charset_info); + const char *option_name= show_comp_option_name[(int) (*types)->state]; - if ((*types)->state == SHOW_OPTION_YES && - !my_strcasecmp(system_charset_info, default_type_name, (*types)->name)) - option_name= "DEFAULT"; - protocol->store(option_name, system_charset_info); - protocol->store((*types)->comment, system_charset_info); - if (protocol->write()) - DBUG_RETURN(TRUE); + if ((*types)->state == SHOW_OPTION_YES && + !my_strcasecmp(system_charset_info, default_type_name, (*types)->name)) + option_name= "DEFAULT"; + protocol->store(option_name, system_charset_info); + protocol->store((*types)->comment, system_charset_info); + if (protocol->write()) + DBUG_RETURN(TRUE); + } } send_eof(thd); DBUG_RETURN(FALSE); From 5d9c8e9543b3e77f57aaddbcfa038ab72e504743 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 17:50:51 +0100 Subject: [PATCH 35/48] WL#2971 "change log-bin-trust-routine-creators=0 to apply only to functions". Indeed now that stored procedures CALL is not binlogged, but instead the invoked substatements are, the restrictions applied by log-bin-trust-routine-creators=0 are superfluous for procedures. They still need to apply to functions where function calls are written to the binlog (for example as "DO myfunc(3)"). We rename the variable to log-bin-trust-function-creators but allow the old name until some future version (and issue a warning if old name is used). mysql-test/mysql-test-run.pl: update to new option name mysql-test/mysql-test-run.sh: update to new option name mysql-test/mysql_test_run_new.c: update to new option name mysql-test/r/rpl_sp.result: result update mysql-test/t/rpl_sp-slave.opt: we need to skip this error to not hit BUG#14769 mysql-test/t/rpl_sp.test: Test update: 1) as log-bin-trust-routine-creators now affects only functions, the testing of this option, which was mainly done on procedures, is moved to functions 2) cleanup is simplified; and instead of many SHOW BINLOG EVENTS we do a big one in the end, which is more maintainable. 3) we test a few more function and procedures cases to see how they replicate. 4) removing out-of-date comments sql/item_func.cc: This warning is wrong since binlogging of functions was changed in August. If a function fails in the middle, it will be binlogged with its error code (i.e. properly). sql/mysql_priv.h: variable name changed sql/mysqld.cc: option name changes. A precision about --read-only. sql/set_var.cc: a new class sys_var_trust_routine_creators to be able to issue a "this is a deprecated variable" warning if used. sql/set_var.h: new class to be able to issue a "this is a deprecated variable" warning if used. sql/share/errmsg.txt: routine -> function sql/sp.cc: log-bin-trust-routine-creators now applies only to functions. sql/sql_parse.cc: 1) sending ER_FAILED_ROUTINE_BREAK_BINLOG is wrong since August as we don't binlog CALL anymore but instead binlog the substatements; the clear_error() goes away too as it was necessary only when we created a binlog event from the "CALL" statement. 2) log-bin-trust-routine-creators now applies only to functions. sql/sql_trigger.cc: comments. --- mysql-test/mysql-test-run.pl | 4 +- mysql-test/mysql-test-run.sh | 6 +- mysql-test/mysql_test_run_new.c | 2 +- mysql-test/r/rpl_sp.result | 312 +++++++++++++++++++++----------- mysql-test/t/rpl_sp-slave.opt | 2 +- mysql-test/t/rpl_sp.test | 206 ++++++++++++++------- sql/item_func.cc | 6 - sql/mysql_priv.h | 2 +- sql/mysqld.cc | 29 ++- sql/set_var.cc | 30 ++- sql/set_var.h | 11 ++ sql/share/errmsg.txt | 4 +- sql/sp.cc | 5 +- sql/sql_parse.cc | 21 +-- sql/sql_trigger.cc | 7 +- 15 files changed, 433 insertions(+), 214 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ea4fa1082db..341d9c38f20 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2008,7 +2008,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); mtr_add_arg($args, "%s--core", $prefix); - mtr_add_arg($args, "%s--log-bin-trust-routine-creators", $prefix); + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); @@ -2131,7 +2131,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); mtr_add_arg($args, "%s--sort_buffer=256K", $prefix); mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); - mtr_add_arg($args, "%s--log-bin-trust-routine-creators", $prefix); + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); if ( $opt_ssl_supported ) { diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 62c2b9014c3..c84763713e1 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1275,7 +1275,7 @@ start_master() --language=$LANGUAGE \ --innodb_data_file_path=ibdata1:128M:autoextend \ --open-files-limit=1024 \ - --log-bin-trust-routine-creators \ + --log-bin-trust-function-creators \ $MASTER_40_ARGS \ $SMALL_SERVER \ $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT \ @@ -1296,7 +1296,7 @@ start_master() --tmpdir=$MYSQL_TMP_DIR \ --language=$LANGUAGE \ --innodb_data_file_path=ibdata1:128M:autoextend \ - --log-bin-trust-routine-creators \ + --log-bin-trust-function-creators \ $MASTER_40_ARGS \ $SMALL_SERVER \ $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT \ @@ -1429,7 +1429,7 @@ start_slave() --report-port=$slave_port \ --master-retry-count=10 \ -O slave_net_timeout=10 \ - --log-bin-trust-routine-creators \ + --log-bin-trust-function-creators \ $SMALL_SERVER \ $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT" CUR_MYERR=$slave_err diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c index 33a69eba872..79db71fa274 100644 --- a/mysql-test/mysql_test_run_new.c +++ b/mysql-test/mysql_test_run_new.c @@ -486,7 +486,7 @@ void start_master() #endif add_arg(&al, "--local-infile"); add_arg(&al, "--core"); - add_arg(&al, "--log-bin-trust-routine-creators"); + add_arg(&al, "--log-bin-trust-function-creators"); add_arg(&al, "--datadir=%s", master_dir); #ifndef __WIN__ add_arg(&al, "--pid-file=%s", master_pid); diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 5f1c3afd14d..58692ec5b82 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -4,16 +4,11 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create database if not exists mysqltest1; +drop database if exists mysqltest1; +create database mysqltest1; use mysqltest1; create table t1 (a varchar(100)); use mysqltest1; -drop procedure if exists foo; -drop procedure if exists foo2; -drop procedure if exists foo3; -drop procedure if exists foo4; -drop procedure if exists bar; -drop function if exists fn1; create procedure foo() begin declare b int; @@ -21,21 +16,9 @@ set b = 8; insert into t1 values (b); insert into t1 values (unix_timestamp()); end| -ERROR HY000: This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable) -show binlog events from 98| -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # create database if not exists mysqltest1 -master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) -create procedure foo() deterministic -begin -declare b int; -set b = 8; -insert into t1 values (b); -insert into t1 values (unix_timestamp()); -end| select * from mysql.proc where name='foo' and db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment -mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL YES DEFINER begin +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin declare b int; set b = 8; insert into t1 values (b); @@ -43,7 +26,7 @@ insert into t1 values (unix_timestamp()); end root@localhost # # select * from mysql.proc where name='foo' and db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment -mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL YES DEFINER begin +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin declare b int; set b = 8; insert into t1 values (b); @@ -51,17 +34,6 @@ insert into t1 values (unix_timestamp()); end @ # # set timestamp=1000000000; call foo(); -show binlog events from 308; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo() deterministic -begin -declare b int; -set b = 8; -insert into t1 values (b); -insert into t1 values (unix_timestamp()); -end -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) select * from t1; a 8 @@ -72,22 +44,10 @@ a 1000000000 delete from t1; create procedure foo2() -not deterministic -reads sql data select * from mysqltest1.t1; call foo2(); a -show binlog events from 518; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo2() -not deterministic -reads sql data -select * from mysqltest1.t1 alter procedure foo2 contains sql; -ERROR HY000: This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable) drop table t1; create table t1 (a int); create table t2 like t1; @@ -99,80 +59,62 @@ grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; create procedure foo4() deterministic -insert into t1 values (10); -ERROR HY000: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable) -set global log_bin_trust_routine_creators=1; -create procedure foo4() -deterministic begin insert into t2 values(3); insert into t1 values (5); end| call foo4(); Got one of the listed errors -show warnings; -Level Code Message -Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1' -Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes call foo3(); show warnings; Level Code Message call foo4(); Got one of the listed errors -show warnings; -Level Code Message -Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'127.0.0.1' for table 't1' -Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes alter procedure foo4 sql security invoker; call foo4(); show warnings; Level Code Message -show binlog events from 990; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 -master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) -master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 -master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo3() -deterministic -insert into t1 values (15) -master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4() +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +delete from t2; +alter table t2 add unique (a); +drop procedure foo4; +create procedure foo4() deterministic begin -insert into t2 values(3); -insert into t1 values (5); -end -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) -select * from t1; -a -15 -5 +insert into t2 values(20),(20); +end| +call foo4(); +ERROR 23000: Duplicate entry '20' for key 1 +show warnings; +Level Code Message +Error 1062 Duplicate entry '20' for key 1 select * from t2; a -3 -3 -3 -select * from t1; -a -15 -5 +20 select * from t2; a -3 -3 -3 +20 select * from mysql.proc where name="foo4" and db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment -mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES INVOKER begin -insert into t2 values(3); -insert into t1 values (5); +mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES DEFINER begin +insert into t2 values(20),(20); end @ # # drop procedure foo4; select * from mysql.proc where name="foo4" and db='mysqltest1'; @@ -184,6 +126,13 @@ drop procedure foo2; drop procedure foo3; create function fn1(x int) returns int +begin +insert into t1 values (x); +return x+2; +end| +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +create function fn1(x int) +returns int deterministic begin insert into t1 values (x); @@ -211,18 +160,55 @@ a drop function fn1; create function fn1() returns int -deterministic +no sql begin return unix_timestamp(); end| +alter function fn1 contains sql; +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) delete from t1; set timestamp=1000000000; insert into t1 values(fn1()); +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +ERROR HY000: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +set global log_bin_trust_routine_creators=1; +Warnings: +Warning 1287 'log_bin_trust_routine_creators' is deprecated; use 'log_bin_trust_function_creators' instead +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +set global log_bin_trust_function_creators=1; +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +create function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end| +select fn3(); +fn3() +0 select * from mysql.proc where db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment -mysqltest1 fn1 FUNCTION fn1 SQL CONTAINS_SQL YES DEFINER int(11) begin +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin return unix_timestamp(); end root@localhost # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end zedjzlcsjhd@localhost # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end root@localhost # # select * from t1; a 1000000000 @@ -232,12 +218,34 @@ a 1000000000 select * from mysql.proc where db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment -mysqltest1 fn1 FUNCTION fn1 SQL CONTAINS_SQL YES DEFINER int(11) begin +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin return unix_timestamp(); end @ # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end @ # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end @ # # +delete from t2; +alter table t2 add unique (a); +drop function fn1; +create function fn1() +returns int +begin +insert into t2 values(20),(20); +return 10; +end| +select fn1(); +ERROR 23000: Duplicate entry '20' for key 1 +select * from t2; +a +20 +select * from t2; +a +20 create trigger trg before insert on t1 for each row set new.a= 10; ERROR 42000: Access denied; you need the SUPER privilege for this operation -flush logs; delete from t1; create trigger trg before insert on t1 for each row set new.a= 10; insert into t1 values (1); @@ -253,14 +261,106 @@ insert into t1 values (1); select * from t1; a 1 -show binlog events in 'master-bin.000002' from 98; +show binlog events in 'master-bin.000001' from 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 -master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) -master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger trg -master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query 1 # drop database if exists mysqltest1 +master-bin.000001 # Query 1 # create database mysqltest1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo2() +select * from mysqltest1.t1 +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql +master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) +master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo3() +deterministic +insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(20),(20) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2 +master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1()) +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() +returns int +begin +insert into t2 values(20),(20); +return 10; +end +master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`() +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; drop trigger trg +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) select * from t1; a 1 diff --git a/mysql-test/t/rpl_sp-slave.opt b/mysql-test/t/rpl_sp-slave.opt index 709a224fd92..611ee1f33be 100644 --- a/mysql-test/t/rpl_sp-slave.opt +++ b/mysql-test/t/rpl_sp-slave.opt @@ -1 +1 @@ ---log_bin_trust_routine_creators=0 +--log_bin_trust_routine_creators=0 --slave-skip-errors=1062 diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index e62a6c73c0a..e7a3afca9cb 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -1,10 +1,18 @@ # Test of replication of stored procedures (WL#2146 for MySQL 5.0) +# Modified by WL#2971. + +# Note that in the .opt files we still use the old variable name +# log-bin-trust-routine-creators so that this test checks that it's +# still accepted (this test also checks that the new name is +# accepted). The old name could be removed in 5.1 or 6.0. source include/master-slave.inc; -# First let's test replication of current_user() (that's a related thing) # we need a db != test, where we don't have automatic grants -create database if not exists mysqltest1; +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings +create database mysqltest1; use mysqltest1; create table t1 (a varchar(100)); sync_slave_with_master; @@ -16,18 +24,14 @@ use mysqltest1; # (same definer, same properties...) connection master; -# cleanup ---disable_warnings -drop procedure if exists foo; -drop procedure if exists foo2; -drop procedure if exists foo3; -drop procedure if exists foo4; -drop procedure if exists bar; -drop function if exists fn1; ---enable_warnings delimiter |; ---error 1418 # not deterministic + +# Stored procedures don't have the limitations that functions have +# regarding binlogging: it's ok to create a procedure as not +# deterministic and updating data, while it's not ok to create such a +# function. We test this. + create procedure foo() begin declare b int; @@ -35,17 +39,6 @@ begin insert into t1 values (b); insert into t1 values (unix_timestamp()); end| - ---replace_column 2 # 5 # -show binlog events from 98| # check that not there - -create procedure foo() deterministic -begin - declare b int; - set b = 8; - insert into t1 values (b); - insert into t1 values (unix_timestamp()); -end| delimiter ;| # we replace columns having times @@ -54,38 +47,29 @@ delimiter ;| --replace_column 13 # 14 # select * from mysql.proc where name='foo' and db='mysqltest1'; sync_slave_with_master; +# You will notice in the result that the definer does not match what +# it is on master, it is a known bug on which Alik is working --replace_result localhost.localdomain localhost 127.0.0.1 localhost --replace_column 13 # 14 # select * from mysql.proc where name='foo' and db='mysqltest1'; -# Now when we call it, does the CALL() get into binlog, -# or the substatements? connection master; # see if timestamp used in SP on slave is same as on master set timestamp=1000000000; call foo(); ---replace_column 2 # 5 # -show binlog events from 308; select * from t1; sync_slave_with_master; select * from t1; -# Now a SP which is supposed to not update tables (CALL should not be -# binlogged) as it's "read sql data", so should not give error even if -# non-deterministic. +# Now a SP which is not updating tables connection master; delete from t1; create procedure foo2() - not deterministic - reads sql data select * from mysqltest1.t1; call foo2(); -# verify CALL is not in binlog ---replace_column 2 # 5 # -show binlog events from 518; ---error 1418 +# check that this is allowed (it's not for functions): alter procedure foo2 contains sql; # SP with definer's right @@ -106,15 +90,7 @@ grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); connection con1; ---error 1419 # only full-global-privs user can create a routine -create procedure foo4() - deterministic - insert into t1 values (10); - -connection master; -set global log_bin_trust_routine_creators=1; -connection con1; - +# this routine will fail in the second INSERT because of privileges delimiter |; create procedure foo4() deterministic @@ -128,29 +104,22 @@ delimiter ;| # I add ,0 so that it does not print the error in the test output, # because this error is hostname-dependent --error 1142,0 -call foo4(); # invoker has no INSERT grant on table => failure -show warnings; +call foo4(); # invoker has no INSERT grant on table t1 => failure connection master; call foo3(); # success (definer == root) show warnings; ---replace_result localhost.localdomain localhost 127.0.0.1 localhost --error 1142,0 call foo4(); # definer's rights => failure -show warnings; # we test replication of ALTER PROCEDURE alter procedure foo4 sql security invoker; call foo4(); # invoker's rights => success show warnings; -# Check that only successful CALLs are in binlog ---replace_column 2 # 5 # -show binlog events from 990; - -# Note that half-failed CALLs are not in binlog, which is a known -# bug. If we compare t2 on master and slave we see they differ: +# Note that half-failed procedure calls are ok with binlogging; +# if we compare t2 on master and slave we see they are identical: select * from t1; select * from t2; @@ -158,6 +127,30 @@ sync_slave_with_master; select * from t1; select * from t2; +# Let's check another failing-in-the-middle procedure +connection master; +delete from t2; +alter table t2 add unique (a); + +drop procedure foo4; +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(20),(20); + end| + +delimiter ;| + +--error 1062 +call foo4(); +show warnings; + +select * from t2; +sync_slave_with_master; +# check that this failed-in-the-middle replicated right: +select * from t2; + # Test of DROP PROCEDURE --replace_result localhost.localdomain localhost 127.0.0.1 localhost @@ -177,6 +170,14 @@ drop procedure foo2; drop procedure foo3; delimiter |; +# check that needs "deterministic" +--error 1418 +create function fn1(x int) + returns int +begin + insert into t1 values (x); + return x+2; +end| create function fn1(x int) returns int deterministic @@ -202,15 +203,69 @@ drop function fn1; create function fn1() returns int - deterministic + no sql begin return unix_timestamp(); end| + delimiter ;| +# check that needs "deterministic" +--error 1418 +alter function fn1 contains sql; + delete from t1; set timestamp=1000000000; insert into t1 values(fn1()); +connection con1; + +delimiter |; +--error 1419 # only full-global-privs user can create a function +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| +connection master; +# test old variable name: +set global log_bin_trust_routine_creators=1; +# now use new name: +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +# slave needs it too otherwise will not execute what master allowed: +connection slave; +set global log_bin_trust_function_creators=1; + +connection con1; + +delimiter |; +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| + +connection master; + +# Now a function which is supposed to not update tables +# as it's "reads sql data", so should not give error even if +# non-deterministic. + +delimiter |; +create function fn3() + returns int + not deterministic + reads sql data +begin + return 0; +end| +delimiter ;| + +select fn3(); --replace_result localhost.localdomain localhost 127.0.0.1 localhost --replace_column 13 # 14 # select * from mysql.proc where db='mysqltest1'; @@ -223,18 +278,43 @@ select * from t1; --replace_column 13 # 14 # select * from mysql.proc where db='mysqltest1'; -# And now triggers +# Let's check a failing-in-the-middle function +connection master; +delete from t2; +alter table t2 add unique (a); + +drop function fn1; + +delimiter |; +create function fn1() + returns int +begin + insert into t2 values(20),(20); + return 10; +end| + +delimiter ;| + +# Because of BUG#14769 the following statement requires that we start +# slave with --slave-skip-errors=1062. When that bug is fixed, that +# option can be removed. + +--error 1062 +select fn1(); + +select * from t2; +sync_slave_with_master; + +# check that this failed-in-the-middle replicated right: +select * from t2; + +# ********************** PART 3 : TRIGGERS *************** connection con1; --error 1227 create trigger trg before insert on t1 for each row set new.a= 10; connection master; -# fn1() above uses timestamps, so in !ps-protocol, the timezone will be -# binlogged, but in --ps-protocol it will not be (BUG#9359) so -# the binlog offsets get shifted which spoils SHOW BINLOG EVENTS. -# To be immune, we take a new binlog. -flush logs; delete from t1; # TODO: when triggers can contain an update, test that this update # does not go into binlog. @@ -253,7 +333,7 @@ drop trigger trg; insert into t1 values (1); select * from t1; --replace_column 2 # 5 # -show binlog events in 'master-bin.000002' from 98; +show binlog events in 'master-bin.000001' from 98; sync_slave_with_master; select * from t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index f467981540b..9201eb9dda2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4775,12 +4775,6 @@ Item_func_sp::execute(Item **itp) res= m_sp->execute_function(thd, args, arg_count, itp); thd->restore_sub_statement_state(&statement_state); - if (res && mysql_bin_log.is_open() && - (m_sp->m_chistics->daccess == SP_CONTAINS_SQL || - m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_FAILED_ROUTINE_BREAK_BINLOG, - ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); #ifndef NO_EMBEDDED_ACCESS_CHECKS sp_restore_security_context(thd, save_ctx_func); error: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b7bd34c613f..64b0d820a7f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1180,7 +1180,7 @@ extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; extern my_bool opt_log_slow_admin_statements; extern my_bool sp_automatic_privileges, opt_noacl; -extern my_bool opt_old_style_user_limits, trust_routine_creators; +extern my_bool opt_old_style_user_limits, trust_function_creators; extern uint opt_crash_binlog_innodb; extern char *shared_memory_base_name, *mysqld_unix_port; extern my_bool opt_enable_shared_memory; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index acad378353b..dc7d11ad728 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -371,7 +371,7 @@ my_bool opt_log_slow_admin_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; uint opt_large_page_size= 0; -my_bool opt_old_style_user_limits= 0, trust_routine_creators= 0; +my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; /* True if there is at least one per-hour limit for some user, so we should check them before each query (and possibly reset counters when hour is @@ -4432,7 +4432,7 @@ enum options_mysqld OPT_INNODB_FAST_SHUTDOWN, OPT_INNODB_FILE_PER_TABLE, OPT_CRASH_BINLOG_INNODB, OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG, - OPT_LOG_BIN_TRUST_ROUTINE_CREATORS, + OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG, OPT_INNODB, OPT_ISAM, OPT_ENGINE_CONDITION_PUSHDOWN, @@ -4857,16 +4857,27 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "File that holds the names for last binary log files.", (gptr*) &opt_binlog_index_name, (gptr*) &opt_binlog_index_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef TO_BE_REMOVED_IN_5_1_OR_6_0 + /* + In 5.0.6 we introduced the below option, then in 5.0.16 we renamed it to + log-bin-trust-function-creators but kept also the old name for + compatibility; the behaviour was also changed to apply only to functions + (and triggers). In a future release this old name could be removed. + */ + {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, + "(deprecated) Use log-bin-trust-function-creators.", + (gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* This option starts with "log-bin" to emphasize that it is specific of - binary logging. Hopefully in 5.1 nobody will need it anymore, when we have - row-level binlog. + binary logging. */ - {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_ROUTINE_CREATORS, + {"log-bin-trust-function-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, "If equal to 0 (the default), then when --log-bin is used, creation of " - "a routine is allowed only to users having the SUPER privilege and only" - "if this routine may not break binary logging", - (gptr*) &trust_routine_creators, (gptr*) &trust_routine_creators, 0, + "a function is allowed only to users having the SUPER privilege and only " + "if this function may not break binary logging.", + (gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-error", OPT_ERROR_LOG_FILE, "Error log file.", (gptr*) &log_error_file_ptr, (gptr*) &log_error_file_ptr, 0, GET_STR, @@ -5725,7 +5736,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, {"read_only", OPT_READONLY, - "Make all tables readonly, with the exception for replication (slave) threads and users with the SUPER privilege", + "Make all non-temporary tables read-only, with the exception for replication (slave) threads and users with the SUPER privilege", (gptr*) &opt_readonly, (gptr*) &opt_readonly, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, diff --git a/sql/set_var.cc b/sql/set_var.cc index 8cf7311265c..5a6ff7d05ad 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -200,9 +200,12 @@ sys_var_key_cache_long sys_key_cache_age_threshold("key_cache_age_threshold", param_age_threshold)); sys_var_bool_ptr sys_local_infile("local_infile", &opt_local_infile); -sys_var_bool_ptr +sys_var_trust_routine_creators sys_trust_routine_creators("log_bin_trust_routine_creators", - &trust_routine_creators); + &trust_function_creators); +sys_var_bool_ptr +sys_trust_function_creators("log_bin_trust_function_creators", + &trust_function_creators); sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings); sys_var_thd_ulong sys_long_query_time("long_query_time", &SV::long_query_time); @@ -722,6 +725,7 @@ sys_var *sys_variables[]= &sys_innodb_commit_concurrency, #endif &sys_trust_routine_creators, + &sys_trust_function_creators, &sys_engine_condition_pushdown, #ifdef HAVE_NDBCLUSTER_DB &sys_ndb_autoincrement_prefetch_sz, @@ -865,7 +869,7 @@ struct show_var_st init_vars[]= { #endif {"log", (char*) &opt_log, SHOW_BOOL}, {"log_bin", (char*) &opt_bin_log, SHOW_BOOL}, - {sys_trust_routine_creators.name,(char*) &sys_trust_routine_creators, SHOW_SYS}, + {sys_trust_function_creators.name,(char*) &sys_trust_function_creators, SHOW_SYS}, {"log_error", (char*) log_error_file, SHOW_CHAR}, #ifdef HAVE_REPLICATION {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL}, @@ -3463,6 +3467,26 @@ bool process_key_caches(int (* func) (const char *name, KEY_CACHE *)) } +void sys_var_trust_routine_creators::warn_deprecated(THD *thd) +{ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), "log_bin_trust_routine_creators", + "log_bin_trust_function_creators"); +} + +void sys_var_trust_routine_creators::set_default(THD *thd, enum_var_type type) +{ + warn_deprecated(thd); + sys_var_bool_ptr::set_default(thd, type); +} + +bool sys_var_trust_routine_creators::update(THD *thd, set_var *var) +{ + warn_deprecated(thd); + return sys_var_bool_ptr::update(thd, var); +} + /**************************************************************************** Used templates ****************************************************************************/ diff --git a/sql/set_var.h b/sql/set_var.h index 854409c159e..18c3353e8ff 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -738,6 +738,17 @@ public: byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; +class sys_var_trust_routine_creators :public sys_var_bool_ptr +{ + /* We need a derived class only to have a warn_deprecated() */ +public: + sys_var_trust_routine_creators(const char *name_arg, my_bool *value_arg) : + sys_var_bool_ptr(name_arg, value_arg) {}; + void warn_deprecated(THD *thd); + void set_default(THD *thd, enum_var_type type); + bool update(THD *thd, set_var *var); +}; + /**************************************************************************** Classes for parsing of the SET command ****************************************************************************/ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index f85bda90e81..8497e236235 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5349,9 +5349,9 @@ ER_CANT_CREATE_GEOMETRY_OBJECT 22003 ER_FAILED_ROUTINE_BREAK_BINLOG eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" ER_BINLOG_UNSAFE_ROUTINE - eng "This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" + eng "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" ER_BINLOG_CREATE_ROUTINE_NEED_SUPER - eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" + eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" ER_EXEC_STMT_WITH_OPEN_CURSOR eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it." ER_STMT_HAS_NO_OPEN_CURSOR diff --git a/sql/sp.cc b/sql/sp.cc index 8386c5d58a2..e01d05cf405 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -551,12 +551,13 @@ db_create_routine(THD *thd, int type, sp_head *sp) store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, system_charset_info); - if (!trust_routine_creators && mysql_bin_log.is_open()) + if ((sp->m_type == TYPE_ENUM_FUNCTION) && + !trust_function_creators && mysql_bin_log.is_open()) { if (!sp->m_chistics->detistic) { /* - Note that for a _function_ this test is not enough; one could use + Note that this test is not perfect; one could use a non-deterministic read-only function in an update statement. */ enum enum_sp_data_access access= diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4bbca55f6ba..6677b8a09ad 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4318,18 +4318,6 @@ end_with_restore_list: So just execute the statement. */ res= sp->execute_procedure(thd, &lex->value_list); - if (mysql_bin_log.is_open() && - (sp->m_chistics->daccess == SP_CONTAINS_SQL || - sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) - { - if (res) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_FAILED_ROUTINE_BREAK_BINLOG, - ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); - else - thd->clear_error(); - } - /* If warnings have been cleared, we have to clear total_warn_count too, otherwise the clients get confused. @@ -4388,7 +4376,8 @@ end_with_restore_list: if (end_active_trans(thd)) goto error; memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics)); - if (!trust_routine_creators && mysql_bin_log.is_open() && + if ((sp->m_type == TYPE_ENUM_FUNCTION) && + !trust_function_creators && mysql_bin_log.is_open() && !sp->m_chistics->detistic && (chistics.daccess == SP_CONTAINS_SQL || chistics.daccess == SP_MODIFIES_SQL_DATA)) @@ -4399,6 +4388,12 @@ end_with_restore_list: } else { + /* + Note that if you implement the capability of ALTER FUNCTION to + alter the body of the function, this command should be made to + follow the restrictions that log-bin-trust-function-creators=0 + already puts on CREATE FUNCTION. + */ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics); else diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index dbad8dcffb5..3eaa067807a 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -131,9 +131,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) But a trigger can in theory be used to do nasty things (if it supported DROP for example) so we do the check for privileges. For now there is already a stronger test right above; but when this stronger test will - be removed, the test below will hold. + be removed, the test below will hold. Because triggers have the same + nature as functions regarding binlogging: their body is implicitely + binlogged, so they share the same danger, so trust_function_creators + applies to them too. */ - if (!trust_routine_creators && mysql_bin_log.is_open() && + if (!trust_function_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); From 7dbea7df275237f8b3ed29cdc499f443a4f9f51f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Nov 2005 22:25:03 +0300 Subject: [PATCH 36/48] WL#2818 (Add creator to the trigger definition for privilege checks on trigger activation) mysql-test/r/information_schema.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/mysqldump.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/rpl_ddl.result: Update result file: a new column DEFINER has been added to INFORMATION_SCHEMA.TRIGGERS. mysql-test/r/rpl_sp.result: Update result file: a new clause DEFINER has been added to CREATE TRIGGER statement. mysql-test/r/rpl_trigger.result: Results for new test cases were added. mysql-test/r/skip_grants.result: Error message has been changed. mysql-test/r/trigger.result: Added DEFINER column. mysql-test/r/view.result: Error messages have been changed. mysql-test/r/view_grant.result: Error messages have been changed. mysql-test/t/mysqldump.test: Drop created procedure to not affect further tests. mysql-test/t/rpl_trigger.test: Add tests for new column in information schema. mysql-test/t/skip_grants.test: Error tag has been renamed. mysql-test/t/view.test: Error tag has been renamed. mysql-test/t/view_grant.test: Error tag has been changed. sql/item_func.cc: Fix typo in comments. sql/mysql_priv.h: A try to minimize copy&paste: - introduce operations to be used from sql_yacc.yy; - introduce an operation to be used from trigger and view processing code. sql/share/errmsg.txt: - Rename ER_NO_VIEW_USER to ER_MALFORMED_DEFINER in order to be shared for view and trigger implementations; - Fix a typo; - Add a new error code for trigger warning. sql/sp.cc: set_info() was split into set_info() and set_definer(). sql/sp_head.cc: set_info() was split into set_info() and set_definer(). sql/sp_head.h: set_info() was split into set_info() and set_definer(). sql/sql_acl.cc: Add a new check: exit from the cycle if the table is NULL. sql/sql_lex.h: - Rename create_view_definer to definer, since it is used for views and triggers; - Change st_lex_user to LEX_USER, since st_lex_user is a structure. So, formally, it should be "struct st_lex_user", which is longer than just LEX_USER; - Add trigger_definition_begin. sql/sql_parse.cc: - Add a new check: exit from the cycle if the table is NULL; - Implement definer-related functions. sql/sql_show.cc: Add DEFINER column. sql/sql_trigger.cc: Add DEFINER support for triggers. sql/sql_trigger.h: Add DEFINER support for triggers. sql/sql_view.cc: Rename create_view_definer to definer. sql/sql_yacc.yy: Add support for DEFINER-clause in CREATE TRIGGER statement. Since CREATE TRIGGER and CREATE VIEW can be similar at the start, yacc is unable to distinguish between them. So, had to modify both statements in order to make it parsable by yacc. mysql-test/r/trigger-compat.result: Result file for triggers backward compatibility test. mysql-test/r/trigger-grant.result: Result file of the test for WL#2818. mysql-test/t/trigger-compat.test: Triggers backward compatibility test: check that the server still can load triggers w/o definer attribute and modify tables with such triggers (add a new trigger, etc). mysql-test/t/trigger-grant.test: Test for WL#2818 -- check that DEFINER support in triggers works properly --- mysql-test/r/information_schema.result | 17 +- mysql-test/r/mysqldump.result | 23 +- mysql-test/r/rpl_ddl.result | 12 +- mysql-test/r/rpl_sp.result | 2 +- mysql-test/r/rpl_trigger.result | 16 + mysql-test/r/skip_grants.result | 2 +- mysql-test/r/trigger-compat.result | 40 +++ mysql-test/r/trigger-grant.result | 238 +++++++++++++ mysql-test/r/trigger.result | 10 +- mysql-test/r/view.result | 4 +- mysql-test/r/view_grant.result | 2 +- mysql-test/t/mysqldump.test | 1 + mysql-test/t/rpl_trigger.test | 23 ++ mysql-test/t/skip_grants.test | 2 +- mysql-test/t/trigger-compat.test | 83 +++++ mysql-test/t/trigger-grant.test | 475 +++++++++++++++++++++++++ mysql-test/t/view.test | 2 +- mysql-test/t/view_grant.test | 2 +- sql/item_func.cc | 2 +- sql/mysql_priv.h | 7 +- sql/share/errmsg.txt | 10 +- sql/sp.cc | 4 +- sql/sp_head.cc | 42 ++- sql/sp_head.h | 5 +- sql/sql_acl.cc | 2 +- sql/sql_lex.h | 15 +- sql/sql_parse.cc | 85 ++++- sql/sql_show.cc | 49 ++- sql/sql_trigger.cc | 311 ++++++++++++++-- sql/sql_trigger.h | 20 +- sql/sql_view.cc | 21 +- sql/sql_yacc.yy | 367 +++++++++++-------- 32 files changed, 1601 insertions(+), 293 deletions(-) create mode 100644 mysql-test/r/trigger-compat.result create mode 100644 mysql-test/r/trigger-grant.result create mode 100644 mysql-test/t/trigger-compat.test create mode 100644 mysql-test/t/trigger-grant.test diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index a5852dc31b4..9cd97784832 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -722,6 +722,7 @@ information_schema ROUTINES SQL_MODE information_schema TRIGGERS ACTION_CONDITION information_schema TRIGGERS ACTION_STATEMENT information_schema TRIGGERS SQL_MODE +information_schema TRIGGERS DEFINER information_schema VIEWS VIEW_DEFINITION select table_name, column_name, data_type from information_schema.columns where data_type = 'datetime'; @@ -800,45 +801,45 @@ set @fired:= "Yes"; end if; end| show triggers; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer trg1 INSERT t1 begin if new.j > 10 then set new.j := 10; end if; -end BEFORE NULL +end BEFORE NULL root@localhost trg2 UPDATE t1 begin if old.i % 2 = 0 then set new.j := -1; end if; -end BEFORE NULL +end BEFORE NULL root@localhost trg3 UPDATE t1 begin if new.j = -1 then set @fired:= "Yes"; end if; -end AFTER NULL +end AFTER NULL root@localhost select * from information_schema.triggers; -TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER NULL test trg1 INSERT NULL test t1 0 NULL begin if new.j > 10 then set new.j := 10; end if; -end ROW BEFORE NULL NULL OLD NEW NULL +end ROW BEFORE NULL NULL OLD NEW NULL root@localhost NULL test trg2 UPDATE NULL test t1 0 NULL begin if old.i % 2 = 0 then set new.j := -1; end if; -end ROW BEFORE NULL NULL OLD NEW NULL +end ROW BEFORE NULL NULL OLD NEW NULL root@localhost NULL test trg3 UPDATE NULL test t1 0 NULL begin if new.j = -1 then set @fired:= "Yes"; end if; -end ROW AFTER NULL NULL OLD NEW NULL +end ROW AFTER NULL NULL OLD NEW NULL root@localhost drop trigger trg1; drop trigger trg2; drop trigger trg3; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 82a761252b5..14fcb158dbc 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1926,23 +1926,23 @@ end if; end| set sql_mode=default| show triggers like "t1"; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer trg1 INSERT t1 begin if new.a > 10 then set new.a := 10; set new.a := 11; end if; -end BEFORE 0000-00-00 00:00:00 +end BEFORE 0000-00-00 00:00:00 root@localhost trg2 UPDATE t1 begin if old.a % 2 = 0 then set new.b := 12; end if; -end BEFORE 0000-00-00 00:00:00 +end BEFORE 0000-00-00 00:00:00 root@localhost trg3 UPDATE t1 begin if new.a = -1 then set @fired:= "Yes"; end if; -end AFTER 0000-00-00 00:00:00 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +end AFTER 0000-00-00 00:00:00 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER root@localhost INSERT INTO t1 (a) VALUES (1),(2),(3),(22); update t1 set a = 4 where a=3; @@ -2085,29 +2085,29 @@ Tables_in_test t1 t2 show triggers; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer trg1 INSERT t1 begin if new.a > 10 then set new.a := 10; set new.a := 11; end if; -end BEFORE # +end BEFORE # root@localhost trg2 UPDATE t1 begin if old.a % 2 = 0 then set new.b := 12; end if; -end BEFORE # +end BEFORE # root@localhost trg3 UPDATE t1 begin if new.a = -1 then set @fired:= "Yes"; end if; -end AFTER # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +end AFTER # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER root@localhost trg4 INSERT t2 begin if new.a > 10 then set @fired:= "No"; end if; -end BEFORE # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +end BEFORE # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER root@localhost DROP TABLE t1, t2; --port=1234 --port=1234 @@ -2130,9 +2130,9 @@ SELECT * FROM `test2`; a2 1 SHOW TRIGGERS; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer testref INSERT test1 BEGIN -INSERT INTO test2 SET a2 = NEW.a1; END BEFORE NULL +INSERT INTO test2 SET a2 = NEW.a1; END BEFORE NULL root@localhost SELECT * FROM `test1`; a1 1 @@ -2147,6 +2147,7 @@ DROP FUNCTION IF EXISTS bug9056_func1; DROP FUNCTION IF EXISTS bug9056_func2; DROP PROCEDURE IF EXISTS bug9056_proc1; DROP PROCEDURE IF EXISTS bug9056_proc2; +DROP PROCEDURE IF EXISTS `a'b`; CREATE TABLE t1 (id int); INSERT INTO t1 VALUES(1), (2), (3), (4), (5); CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) RETURN a+b // diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result index 2a97da63c64..4d8f2f11d4a 100644 --- a/mysql-test/r/rpl_ddl.result +++ b/mysql-test/r/rpl_ddl.result @@ -1465,13 +1465,13 @@ flush logs; -------- switch to master ------- SHOW TRIGGERS; -Trigger Event Table Statement Timing Created sql_mode -trg1 INSERT t1 SET @a:=1 BEFORE NULL +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost -------- switch to slave ------- SHOW TRIGGERS; -Trigger Event Table Statement Timing Created sql_mode -trg1 INSERT t1 SET @a:=1 BEFORE NULL +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost ######## DROP TRIGGER trg1 ######## @@ -1520,11 +1520,11 @@ flush logs; -------- switch to master ------- SHOW TRIGGERS; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer -------- switch to slave ------- SHOW TRIGGERS; -Trigger Event Table Statement Timing Created sql_mode +Trigger Event Table Statement Timing Created sql_mode Definer ######## CREATE USER user1@localhost ######## diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 5f1c3afd14d..4bb8434c973 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -256,7 +256,7 @@ a show binlog events in 'master-bin.000002' from 98; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000002 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger trg diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index db824c9c423..999af131b8b 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -89,8 +89,24 @@ insert into t1 set a = now(); select a=b && a=c from t1; a=b && a=c 1 +SELECT routine_name, definer +FROM information_schema.routines; +routine_name definer +bug12480 root@localhost +SELECT trigger_name, definer +FROM information_schema.triggers; +trigger_name definer +t1_first root@localhost --- On slave -- +SELECT routine_name, definer +FROM information_schema.routines; +routine_name definer +bug12480 @ +SELECT trigger_name, definer +FROM information_schema.triggers; +trigger_name definer +t1_first root@localhost select a=b && a=c from t1; a=b && a=c 1 diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index 4d723f8e12a..5dc770a7363 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -4,7 +4,7 @@ drop procedure if exists f1; use test; create table t1 (field1 INT); CREATE VIEW v1 AS SELECT field1 FROM t1; -ERROR HY000: View definer is not fully qualified +ERROR HY000: Definer is not fully qualified drop table t1; create procedure f1() select 1; drop procedure f1; diff --git a/mysql-test/r/trigger-compat.result b/mysql-test/r/trigger-compat.result new file mode 100644 index 00000000000..5c104a2d2d5 --- /dev/null +++ b/mysql-test/r/trigger-compat.result @@ -0,0 +1,40 @@ +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; +GRANT SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT CREATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +---> connection: wl2818_definer_con +CREATE TABLE t1(num_value INT); +CREATE TABLE t2(user_str TEXT); +CREATE TRIGGER wl2818_trg1 BEFORE INSERT ON t1 +FOR EACH ROW +INSERT INTO t2 VALUES(CURRENT_USER()); + +---> patching t1.TRG... + +CREATE TRIGGER wl2818_trg2 AFTER INSERT ON t1 +FOR EACH ROW +INSERT INTO t2 VALUES(CURRENT_USER()); +Warnings: +Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'wl2818_trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. + +SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; +trigger_name definer +wl2818_trg1 +wl2818_trg2 mysqltest_dfn@localhost +Warnings: +Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'wl2818_trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER +NULL mysqltest_db1 wl2818_trg1 INSERT NULL mysqltest_db1 t1 0 NULL +INSERT INTO t2 VALUES(CURRENT_USER()) ROW BEFORE NULL NULL OLD NEW NULL +NULL mysqltest_db1 wl2818_trg2 INSERT NULL mysqltest_db1 t1 0 NULL +INSERT INTO t2 VALUES(CURRENT_USER()) ROW AFTER NULL NULL OLD NEW NULL mysqltest_dfn@localhost diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result new file mode 100644 index 00000000000..eda1adfdf65 --- /dev/null +++ b/mysql-test/r/trigger-grant.result @@ -0,0 +1,238 @@ +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; +GRANT SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT CREATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +---> connection: wl2818_definer_con +CREATE TABLE t1(num_value INT); +CREATE TABLE t2(user_str TEXT); +CREATE TRIGGER trg1 AFTER INSERT ON t1 +FOR EACH ROW +INSERT INTO t2 VALUES(CURRENT_USER()); + +---> connection: default +GRANT ALL PRIVILEGES ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; +GRANT ALL PRIVILEGES ON mysqltest_db1.t2 TO mysqltest_dfn@localhost; +GRANT ALL PRIVILEGES ON mysqltest_db1.t1 +TO 'mysqltest_inv'@localhost; +GRANT SELECT ON mysqltest_db1.t2 +TO 'mysqltest_inv'@localhost; + +---> connection: wl2818_definer_con +use mysqltest_db1; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; +num_value +1 +SELECT * FROM t2; +user_str +mysqltest_dfn@localhost + +---> connection: wl2818_invoker_con +use mysqltest_db1; +INSERT INTO t1 VALUES(2); +SELECT * FROM t1; +num_value +1 +2 +SELECT * FROM t2; +user_str +mysqltest_dfn@localhost +mysqltest_dfn@localhost + +---> connection: default +use mysqltest_db1; +REVOKE INSERT ON mysqltest_db1.t2 FROM mysqltest_dfn@localhost; + +---> connection: wl2818_invoker_con +use mysqltest_db1; +INSERT INTO t1 VALUES(3); +ERROR 42000: INSERT command denied to user 'mysqltest_dfn'@'localhost' for table 't2' +SELECT * FROM t1; +num_value +1 +2 +3 +SELECT * FROM t2; +user_str +mysqltest_dfn@localhost +mysqltest_dfn@localhost + +---> connection: default +use mysqltest_db1; +REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; + +---> connection: wl2818_definer_con +use mysqltest_db1; +DROP TRIGGER trg1; +SET @new_sum = 0; +SET @old_sum = 0; +---> INSERT INTO statement; BEFORE timing +CREATE TRIGGER trg1 BEFORE INSERT ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +INSERT INTO t1 VALUES(4); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> INSERT INTO statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER INSERT ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +INSERT INTO t1 VALUES(5); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> UPDATE statement; BEFORE timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 BEFORE UPDATE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +UPDATE t1 SET num_value = 10; +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> UPDATE statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER UPDATE ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +UPDATE t1 SET num_value = 20; +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> DELETE statement; BEFORE timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 BEFORE DELETE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +DELETE FROM t1; +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> DELETE statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER DELETE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +DELETE FROM t1; +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1' + +---> connection: default +use mysqltest_db1; +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; + +---> connection: wl2818_definer_con +use mysqltest_db1; +DROP TRIGGER trg1; +SET @new_sum = 0; +SET @old_sum = 0; +---> INSERT INTO statement; BEFORE timing +CREATE TRIGGER trg1 BEFORE INSERT ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +INSERT INTO t1 VALUES(4); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> INSERT INTO statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER INSERT ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +INSERT INTO t1 VALUES(5); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> UPDATE statement; BEFORE timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 BEFORE UPDATE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +UPDATE t1 SET num_value = 10; +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> UPDATE statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER UPDATE ON t1 +FOR EACH ROW +SET @new_sum = @new_sum + NEW.num_value; +UPDATE t1 SET num_value = 20; +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> DELETE statement; BEFORE timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 BEFORE DELETE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +DELETE FROM t1; +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' +---> DELETE statement; AFTER timing +DROP TRIGGER trg1; +CREATE TRIGGER trg1 AFTER DELETE ON t1 +FOR EACH ROW +SET @old_sum = @old_sum + OLD.num_value; +DELETE FROM t1; +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1' + +---> connection: wl2818_definer_con +use mysqltest_db1; +DROP TRIGGER trg1; +CREATE DEFINER='mysqltest_inv'@'localhost' + TRIGGER trg1 BEFORE INSERT ON t1 +FOR EACH ROW +SET @new_sum = 0; +CREATE DEFINER='mysqltest_nonexs'@'localhost' + TRIGGER trg2 AFTER INSERT ON t1 +FOR EACH ROW +SET @new_sum = 0; +Warnings: +Note 1449 There is no 'mysqltest_nonexs'@'localhost' registered +INSERT INTO t1 VALUES(6); +ERROR 42000: Access denied; you need the SUPER privilege for this operation +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 +SET @new_sum = 0 BEFORE NULL mysqltest_inv@localhost +trg2 INSERT t1 +SET @new_sum = 0 AFTER NULL mysqltest_nonexs@localhost +DROP TRIGGER trg1; +DROP TRIGGER trg2; +CREATE TRIGGER trg1 BEFORE INSERT ON t1 +FOR EACH ROW +SET @a = 1; +CREATE TRIGGER trg2 AFTER INSERT ON t1 +FOR EACH ROW +SET @a = 2; +CREATE TRIGGER trg3 BEFORE UPDATE ON t1 +FOR EACH ROW +SET @a = 3; +CREATE TRIGGER trg4 AFTER UPDATE ON t1 +FOR EACH ROW +SET @a = 4; +CREATE TRIGGER trg5 BEFORE DELETE ON t1 +FOR EACH ROW +SET @a = 5; + +SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; +trigger_name definer +trg1 +trg2 @ +trg3 @abc@def@@ +trg4 @hostname +trg5 @abcdef@@@hostname +Warnings: +Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER +NULL mysqltest_db1 trg1 INSERT NULL mysqltest_db1 t1 0 NULL +SET @a = 1 ROW BEFORE NULL NULL OLD NEW NULL +NULL mysqltest_db1 trg2 INSERT NULL mysqltest_db1 t1 0 NULL +SET @a = 2 ROW AFTER NULL NULL OLD NEW NULL @ +NULL mysqltest_db1 trg3 UPDATE NULL mysqltest_db1 t1 0 NULL +SET @a = 3 ROW BEFORE NULL NULL OLD NEW NULL @abc@def@@ +NULL mysqltest_db1 trg4 UPDATE NULL mysqltest_db1 t1 0 NULL +SET @a = 4 ROW AFTER NULL NULL OLD NEW NULL @hostname +NULL mysqltest_db1 trg5 DELETE NULL mysqltest_db1 t1 0 NULL +SET @a = 5 ROW BEFORE NULL NULL OLD NEW NULL @abcdef@@@hostname + +---> connection: default +DROP USER mysqltest_dfn@localhost; +DROP USER mysqltest_inv@localhost; +DROP DATABASE mysqltest_db1; +Warnings: +Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index b305691fa18..d3fbb56e493 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -611,9 +611,9 @@ select @a; @a 10 show triggers; -Trigger Event Table Statement Timing Created sql_mode -t1_bi INSERT t1 set new."t1 column" = 5 BEFORE # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI -t1_af INSERT t1 set @a=10 AFTER # +Trigger Event Table Statement Timing Created sql_mode Definer +t1_bi INSERT t1 set new."t1 column" = 5 BEFORE # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI root@localhost +t1_af INSERT t1 set @a=10 AFTER # root@localhost drop table t1; set sql_mode="traditional"; create table t1 (a date); @@ -633,8 +633,8 @@ t1 CREATE TABLE `t1` ( `a` date default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 show triggers; -Trigger Event Table Statement Timing Created sql_mode -t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # +Trigger Event Table Statement Timing Created sql_mode Definer +t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # root@localhost drop table t1; create table t1 (id int); create trigger t1_ai after insert on t1 for each row flush tables; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 581a27aa7e5..97df059c86a 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2199,10 +2199,10 @@ r_object_id users_names drop view v1, v2; drop table t1, t2; create definer=some_user@`` sql security invoker view v1 as select 1; -ERROR HY000: View definer is not fully qualified +ERROR HY000: Definer is not fully qualified create definer=some_user@localhost sql security invoker view v1 as select 1; Warnings: -Note 1449 There is not some_user@localhost registered +Note 1449 There is no 'some_user'@'localhost' registered show create view v1; View Create View v1 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 43df5c29f92..89067ec23a2 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -13,7 +13,7 @@ create table mysqltest.t2 (a int, b int); grant select on mysqltest.t1 to mysqltest_1@localhost; grant create view,select on test.* to mysqltest_1@localhost; create definer=root@localhost view v1 as select * from mysqltest.t1; -ERROR HY000: You need the SUPER privilege for creation view with root@localhost definer +ERROR 42000: Access denied; you need the SUPER privilege for this operation create view v1 as select * from mysqltest.t1; alter view v1 as select * from mysqltest.t1; ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 91a87e2c774..ef3a3131a8a 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -882,6 +882,7 @@ DROP FUNCTION IF EXISTS bug9056_func1; DROP FUNCTION IF EXISTS bug9056_func2; DROP PROCEDURE IF EXISTS bug9056_proc1; DROP PROCEDURE IF EXISTS bug9056_proc2; +DROP PROCEDURE IF EXISTS `a'b`; --enable_warnings CREATE TABLE t1 (id int); diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index 715222f0314..bf2836b6049 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -87,12 +87,35 @@ insert into t1 set a = now(); select a=b && a=c from t1; let $time=`select a from t1`; +# Check that definer attribute is replicated properly: +# - dump definers on the master; +# - wait for the slave to synchronize with the master; +# - dump definers on the slave; + +SELECT routine_name, definer +FROM information_schema.routines; + +SELECT trigger_name, definer +FROM information_schema.triggers; + save_master_pos; connection slave; sync_with_master; --disable_query_log select "--- On slave --" as ""; --enable_query_log + +# XXX: Definers of stored procedures and functions are not replicated. WL#2897 +# (Complete definer support in the stored routines) addresses this issue. So, +# the result file is expected to be changed after implementation of this WL +# item. + +SELECT routine_name, definer +FROM information_schema.routines; + +SELECT trigger_name, definer +FROM information_schema.triggers; + select a=b && a=c from t1; --disable_query_log eval select a='$time' as 'test' from t1; diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 7a729f98661..16b0fbc4d25 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -9,7 +9,7 @@ use test; # test that we can create VIEW if privileges check switched off # create table t1 (field1 INT); --- error ER_NO_VIEW_USER +-- error ER_MALFORMED_DEFINER CREATE VIEW v1 AS SELECT field1 FROM t1; drop table t1; diff --git a/mysql-test/t/trigger-compat.test b/mysql-test/t/trigger-compat.test new file mode 100644 index 00000000000..ace18639172 --- /dev/null +++ b/mysql-test/t/trigger-compat.test @@ -0,0 +1,83 @@ +# Test case(s) in this file contain(s) GRANT/REVOKE statements, which are not +# supported in embedded server. So, this test should not be run on embedded +# server. + +-- source include/not_embedded.inc + +########################################################################### +# +# Tests for WL#2818: +# - Check that triggers created w/o DEFINER information work well: +# - create the first trigger; +# - manually remove definer information from corresponding TRG file; +# - create the second trigger (the first trigger will be reloaded; check +# that we receive a warning); +# - check that the triggers loaded correctly; +# +########################################################################### + +# +# Prepare environment. +# + +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; + +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; + +GRANT SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT CREATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +# +# Create a table and the first trigger. +# + +--connect (wl2818_definer_con,localhost,mysqltest_dfn,,mysqltest_db1) +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +CREATE TABLE t1(num_value INT); +CREATE TABLE t2(user_str TEXT); + +CREATE TRIGGER wl2818_trg1 BEFORE INSERT ON t1 + FOR EACH ROW + INSERT INTO t2 VALUES(CURRENT_USER()); + +# +# Remove definers from TRG file. +# + +--echo +--echo ---> patching t1.TRG... + +--exec grep --text -v 'definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG +--exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG + +# +# Create a new trigger. +# + +--echo + +CREATE TRIGGER wl2818_trg2 AFTER INSERT ON t1 + FOR EACH ROW + INSERT INTO t2 VALUES(CURRENT_USER()); + +--echo + +SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; + +--echo + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test new file mode 100644 index 00000000000..c058816ee75 --- /dev/null +++ b/mysql-test/t/trigger-grant.test @@ -0,0 +1,475 @@ +# Test case(s) in this file contain(s) GRANT/REVOKE statements, which are not +# supported in embedded server. So, this test should not be run on embedded +# server. + +-- source include/not_embedded.inc + +########################################################################### +# +# Tests for WL#2818: +# - Check that triggers are executed under the authorization of the definer. +# - Check that if trigger contains NEW/OLD variables, the definer must have +# SELECT privilege on the subject table. +# - Check DEFINER clause of CREATE TRIGGER statement; +# - Check that SUPER privilege required to create a trigger with different +# definer. +# - Check that if the user specified as DEFINER does not exist, a warning +# is emitted. +# - Check that the definer of a trigger does not exist, the trigger will +# not be activated. +# - Check that SHOW TRIGGERS statement provides "Definer" column. +# +# Let's also check that user name part of definer can contain '@' symbol (to +# check that triggers are not affected by BUG#13310 "incorrect user parsing +# by SP"). +# +########################################################################### + +# +# Prepare environment. +# + +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; + +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; + +GRANT SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT CREATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +# +# Check that triggers are executed under the authorization of the definer: +# - create two tables under "definer"; +# - grant all privileges on the test db to "definer"; +# - grant all privileges on the first table to "invoker"; +# - grant only select privilege on the second table to "invoker"; +# - create a trigger, which inserts a row into the second table after +# inserting into the first table. +# - insert a row into the first table under "invoker". A row also should be +# inserted into the second table. +# + +--connect (wl2818_definer_con,localhost,mysqltest_dfn,,mysqltest_db1) +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +CREATE TABLE t1(num_value INT); +CREATE TABLE t2(user_str TEXT); + +CREATE TRIGGER trg1 AFTER INSERT ON t1 + FOR EACH ROW + INSERT INTO t2 VALUES(CURRENT_USER()); + +--connection default +--echo +--echo ---> connection: default + +# Setup definer's privileges. + +GRANT ALL PRIVILEGES ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; +GRANT ALL PRIVILEGES ON mysqltest_db1.t2 TO mysqltest_dfn@localhost; + +# Setup invoker's privileges. + +GRANT ALL PRIVILEGES ON mysqltest_db1.t1 + TO 'mysqltest_inv'@localhost; + +GRANT SELECT ON mysqltest_db1.t2 + TO 'mysqltest_inv'@localhost; + +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +use mysqltest_db1; + +INSERT INTO t1 VALUES(1); + +SELECT * FROM t1; +SELECT * FROM t2; + +--connect (wl2818_invoker_con,localhost,mysqltest_inv,,mysqltest_db1) +--connection wl2818_invoker_con +--echo +--echo ---> connection: wl2818_invoker_con + +use mysqltest_db1; + +INSERT INTO t1 VALUES(2); + +SELECT * FROM t1; +SELECT * FROM t2; + +# +# Check that if definer lost some privilege required to execute (activate) a +# trigger, the trigger will not be activated: +# - create a trigger on insert into the first table, which will insert a row +# into the second table; +# - revoke INSERT privilege on the second table from the definer; +# - insert a row into the first table; +# - check that an error has been risen; +# - check that no row has been inserted into the second table; +# + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +REVOKE INSERT ON mysqltest_db1.t2 FROM mysqltest_dfn@localhost; + +--connection wl2818_invoker_con +--echo +--echo ---> connection: wl2818_invoker_con + +use mysqltest_db1; + +--error ER_TABLEACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(3); + +SELECT * FROM t1; +SELECT * FROM t2; + +# +# Check that if trigger contains NEW/OLD variables, the definer must have +# SELECT/UPDATE privilege on the subject table: +# - drop the trigger; +# - create a new trigger, which will use NEW variable; +# - create another new trigger, which will use OLD variable; +# - revoke SELECT/UPDATE privilege on the first table from "definer"; +# - insert a row into the first table; +# - analyze error code; +# + +# +# SELECT privilege. +# + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; + +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +use mysqltest_db1; + +DROP TRIGGER trg1; + +SET @new_sum = 0; +SET @old_sum = 0; + +# INSERT INTO statement; BEFORE timing + +--echo ---> INSERT INTO statement; BEFORE timing + +CREATE TRIGGER trg1 BEFORE INSERT ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(4); + +# INSERT INTO statement; AFTER timing + +--echo ---> INSERT INTO statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER INSERT ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(5); + +# UPDATE statement; BEFORE timing + +--echo ---> UPDATE statement; BEFORE timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 BEFORE UPDATE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +UPDATE t1 SET num_value = 10; + +# UPDATE statement; AFTER timing + +--echo ---> UPDATE statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER UPDATE ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +UPDATE t1 SET num_value = 20; + +# DELETE statement; BEFORE timing + +--echo ---> DELETE statement; BEFORE timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 BEFORE DELETE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +DELETE FROM t1; + +# DELETE statement; AFTER timing + +--echo ---> DELETE statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER DELETE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +DELETE FROM t1; + +# +# UPDATE privilege +# +# NOTE: At the moment, UPDATE privilege is required if the trigger contains +# NEW/OLD variables, whenever the trigger modifies them or not. Moreover, +# UPDATE privilege is checked for whole table, not for individual columns. +# +# The following test cases should be changed when full support of UPDATE +# privilege will be done. +# + +--connection default +--echo +--echo ---> connection: default + +use mysqltest_db1; + +GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost; +REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost; + +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +use mysqltest_db1; + +DROP TRIGGER trg1; + +SET @new_sum = 0; +SET @old_sum = 0; + +# INSERT INTO statement; BEFORE timing + +--echo ---> INSERT INTO statement; BEFORE timing + +CREATE TRIGGER trg1 BEFORE INSERT ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(4); + +# INSERT INTO statement; AFTER timing + +--echo ---> INSERT INTO statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER INSERT ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(5); + +# UPDATE statement; BEFORE timing + +--echo ---> UPDATE statement; BEFORE timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 BEFORE UPDATE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +UPDATE t1 SET num_value = 10; + +# UPDATE statement; AFTER timing + +--echo ---> UPDATE statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER UPDATE ON t1 + FOR EACH ROW + SET @new_sum = @new_sum + NEW.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +UPDATE t1 SET num_value = 20; + +# DELETE statement; BEFORE timing + +--echo ---> DELETE statement; BEFORE timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 BEFORE DELETE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +DELETE FROM t1; + +# DELETE statement; AFTER timing + +--echo ---> DELETE statement; AFTER timing + +DROP TRIGGER trg1; + +CREATE TRIGGER trg1 AFTER DELETE ON t1 + FOR EACH ROW + SET @old_sum = @old_sum + OLD.num_value; + +--error ER_TABLEACCESS_DENIED_ERROR +DELETE FROM t1; + +# +# Check DEFINER clause of CREATE TRIGGER statement. +# +# NOTE: there is no dedicated TRIGGER privilege for CREATE TRIGGER statement. +# SUPER privilege is used instead. I.e., if one invokes CREATE TRIGGER, it should +# have SUPER privilege, so this test is meaningless right now. +# +# - Check that SUPER privilege required to create a trigger with different +# definer: +# - try to create a trigger with DEFINER="definer@localhost" under +# "invoker"; +# - analyze error code; +# - Check that if the user specified as DEFINER does not exist, a warning is +# emitted: +# - create a trigger with DEFINER="non_existent_user@localhost" from +# "definer"; +# - check that a warning emitted; +# - Check that the definer of a trigger does not exist, the trigger will not +# be activated: +# - activate just created trigger; +# - check error code; +# + +--connection wl2818_definer_con +--echo +--echo ---> connection: wl2818_definer_con + +use mysqltest_db1; + +DROP TRIGGER trg1; + +# Check that SUPER is required to specify different DEFINER. +# NOTE: meaningless at the moment + +CREATE DEFINER='mysqltest_inv'@'localhost' + TRIGGER trg1 BEFORE INSERT ON t1 + FOR EACH ROW + SET @new_sum = 0; + +# Create with non-existent user. + +CREATE DEFINER='mysqltest_nonexs'@'localhost' + TRIGGER trg2 AFTER INSERT ON t1 + FOR EACH ROW + SET @new_sum = 0; + +# Check that trg2 will not be activated. + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +INSERT INTO t1 VALUES(6); + +# +# Check that SHOW TRIGGERS statement provides "Definer" column. +# + +SHOW TRIGGERS; + +# +# Check that weird definer values do not break functionality. I.e. check the +# following definer values: +# - ''; +# - '@'; +# - '@abc@def@@'; +# - '@hostname'; +# - '@abc@def@@@hostname'; +# + +DROP TRIGGER trg1; +DROP TRIGGER trg2; + +CREATE TRIGGER trg1 BEFORE INSERT ON t1 + FOR EACH ROW + SET @a = 1; + +CREATE TRIGGER trg2 AFTER INSERT ON t1 + FOR EACH ROW + SET @a = 2; + +CREATE TRIGGER trg3 BEFORE UPDATE ON t1 + FOR EACH ROW + SET @a = 3; + +CREATE TRIGGER trg4 AFTER UPDATE ON t1 + FOR EACH ROW + SET @a = 4; + +CREATE TRIGGER trg5 BEFORE DELETE ON t1 + FOR EACH ROW + SET @a = 5; + +--exec egrep --text -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG +--exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQL_TEST_DIR/var/tmp/t1.TRG +--exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG + +--echo + +SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; + +--echo + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; + +# +# Cleanup +# + +--connection default +--echo +--echo ---> connection: default + +DROP USER mysqltest_dfn@localhost; +DROP USER mysqltest_inv@localhost; + +DROP DATABASE mysqltest_db1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 3f599c62fff..5addcd2570d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2081,7 +2081,7 @@ drop table t1, t2; # # DEFINER information check # --- error ER_NO_VIEW_USER +-- error ER_MALFORMED_DEFINER create definer=some_user@`` sql security invoker view v1 as select 1; create definer=some_user@localhost sql security invoker view v1 as select 1; show create view v1; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 7f0cb6d9406..b4f367c2065 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -24,7 +24,7 @@ grant create view,select on test.* to mysqltest_1@localhost; connect (user1,localhost,mysqltest_1,,test); connection user1; --- error ER_VIEW_OTHER_USER +-- error ER_SPECIFIC_ACCESS_DENIED create definer=root@localhost view v1 as select * from mysqltest.t1; create view v1 as select * from mysqltest.t1; # try to modify view without DROP privilege on it diff --git a/sql/item_func.cc b/sql/item_func.cc index f467981540b..f5d5cac7e17 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4894,7 +4894,7 @@ Item_func_sp::tmp_table_field(TABLE *t_arg) /* - Find the function and chack access rigths to the function + Find the function and check access rights to the function SYNOPSIS find_and_check_access() diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b7bd34c613f..feede38c286 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -522,8 +522,9 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); -bool default_view_definer(Security_context *sctx, st_lex_user *definer); +bool get_default_definer(THD *thd, LEX_USER *definer); +LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); enum enum_mysql_completiontype { ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, @@ -847,6 +848,10 @@ bool mysqld_show_column_types(THD *thd); bool mysqld_help (THD *thd, const char *text); void calc_sum_of_all_status(STATUS_VAR *to); +void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, + const LEX_STRING *definer_host); + + /* information schema */ extern LEX_STRING information_schema_name; LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index f85bda90e81..b35a31081a3 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5405,14 +5405,14 @@ ER_PS_NO_RECURSION eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner" ER_SP_CANT_SET_AUTOCOMMIT eng "Not allowed to set autocommit from a stored function or trigger" -ER_NO_VIEW_USER - eng "View definer is not fully qualified" +ER_MALFORMED_DEFINER + eng "Definer is not fully qualified" ER_VIEW_FRM_NO_USER eng "View %-.64s.%-.64s has not definer information (old table format). Current user is used as definer. Please recreate view!" ER_VIEW_OTHER_USER - eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer" + eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer" ER_NO_SUCH_USER - eng "There is not %-.64s@%-.64s registered" + eng "There is no '%-.64s'@'%-.64s' registered" ER_FORBID_SCHEMA_CHANGE eng "Changing schema from '%-.64s' to '%-.64s' is not allowed." ER_ROW_IS_REFERENCED_2 23000 @@ -5421,3 +5421,5 @@ ER_NO_REFERENCED_ROW_2 23000 eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)" ER_SP_BAD_VAR_SHADOW 42000 eng "Variable '%-.64s' must be quoted with `...`, or renamed" +ER_TRG_NO_DEFINER + eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger." diff --git a/sql/sp.cc b/sql/sp.cc index 8386c5d58a2..8d6e093c70d 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -441,8 +441,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) goto done; *sphp= thd->lex->sphead; - (*sphp)->set_info((char *)definer, (uint)strlen(definer), - created, modified, &chistics, sql_mode); + (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); + (*sphp)->set_info(created, modified, &chistics, sql_mode); (*sphp)->optimize(); } thd->lex->sql_command= oldcmd; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index abc66ce0b21..08a189165b5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1569,21 +1569,9 @@ sp_head::check_backpatch(THD *thd) } void -sp_head::set_info(char *definer, uint definerlen, - longlong created, longlong modified, +sp_head::set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode) { - char *p= strchr(definer, '@'); - uint len; - - if (! p) - p= definer; // Weird... - len= p-definer; - m_definer_user.str= strmake_root(mem_root, definer, len); - m_definer_user.length= len; - len= definerlen-len-1; - m_definer_host.str= strmake_root(mem_root, p+1, len); - m_definer_host.length= len; m_created= created; m_modified= modified; m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics, @@ -1597,6 +1585,34 @@ sp_head::set_info(char *definer, uint definerlen, m_sql_mode= sql_mode; } + +void +sp_head::set_definer(char *definer, uint definerlen) +{ + char *p= strrchr(definer, '@'); + + if (!p) + { + m_definer_user.str= strmake_root(mem_root, "", 0); + m_definer_user.length= 0; + + m_definer_host.str= strmake_root(mem_root, "", 0); + m_definer_host.length= 0; + } + else + { + const uint user_name_len= p - definer; + const uint host_name_len= definerlen - user_name_len - 1; + + m_definer_user.str= strmake_root(mem_root, definer, user_name_len); + m_definer_user.length= user_name_len; + + m_definer_host.str= strmake_root(mem_root, p + 1, host_name_len); + m_definer_host.length= host_name_len; + } +} + + void sp_head::reset_thd_mem_root(THD *thd) { diff --git a/sql/sp_head.h b/sql/sp_head.h index ed0f3987e01..d1a122fd410 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -251,10 +251,11 @@ public: Field *make_field(uint max_length, const char *name, TABLE *dummy); - void set_info(char *definer, uint definerlen, - longlong created, longlong modified, + void set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode); + void set_definer(char *definer, uint definerlen); + void reset_thd_mem_root(THD *thd); void restore_thd_mem_root(THD *thd); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2b5945b74af..bc8b9ba2efb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3532,7 +3532,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, of other queries). For simple queries first_not_own_table is 0. */ for (i= 0, table= tables; - table != first_not_own_table && i < number; + table && table != first_not_own_table && i < number; table= table->next_global, i++) { /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a8bee9bb59b..0e836b6e9b9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -737,10 +737,15 @@ typedef struct st_lex TABLE_LIST **query_tables_last; /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; - st_lex_user *create_view_definer; char *create_view_start; char *create_view_select_start; + /* + The definer of the object being created (view, trigger, stored routine). + I.e. the value of DEFINER clause. + */ + LEX_USER *definer; + List col_list; List ref_list; List interval_list; @@ -887,6 +892,14 @@ typedef struct st_lex */ SQL_LIST trg_table_fields; + /* + trigger_definition_begin points to the beginning of the word "TRIGGER" in + CREATE TRIGGER statement. This is used to add possibly omitted DEFINER + clause to the trigger definition statement before dumping it to the + binlog. + */ + const char *trigger_definition_begin; + /* If non-0 then indicates that query requires prelocking and points to next_global member of last own element in query table list (i.e. last diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4bbca55f6ba..96e7393e4d6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5062,7 +5062,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, the given table list refers to the list for prelocking (contains tables of other queries). For simple queries first_not_own_table is 0. */ - for (; tables != first_not_own_table; tables= tables->next_global) + for (; tables && tables != first_not_own_table; tables= tables->next_global) { if (tables->schema_table && (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) @@ -7466,32 +7466,81 @@ Item *negate_expression(THD *thd, Item *expr) return new Item_func_not(expr); } - /* - Assign as view definer current user - + Set the specified definer to the default value, which is the current user in + the thread. Also check that the current user satisfies to the definers + requirements. + SYNOPSIS - default_view_definer() - sctx current security context - definer structure where it should be assigned - + get_default_definer() + thd [in] thread handler + definer [out] definer + RETURN - FALSE OK - TRUE Error + error status, that is: + - FALSE -- on success; + - TRUE -- on error (current user can not be a definer). */ - -bool default_view_definer(Security_context *sctx, st_lex_user *definer) + +bool get_default_definer(THD *thd, LEX_USER *definer) { - definer->user.str= sctx->priv_user; - definer->user.length= strlen(sctx->priv_user); + /* Check that current user has non-empty host name. */ - if (!*sctx->priv_host) + const Security_context *sctx= thd->security_ctx; + + if (sctx->priv_host[0] == 0) { - my_error(ER_NO_VIEW_USER, MYF(0)); + my_error(ER_MALFORMED_DEFINER, MYF(0)); return TRUE; } - definer->host.str= sctx->priv_host; - definer->host.length= strlen(sctx->priv_host); + /* Fill in. */ + + definer->user.str= (char *) sctx->priv_user; + definer->user.length= strlen(definer->user.str); + + definer->host.str= (char *) sctx->priv_host; + definer->host.length= strlen(definer->host.str); + return FALSE; } + + +/* + Create definer with the given user and host names. Also check that the user + and host names satisfy definers requirements. + + SYNOPSIS + create_definer() + thd [in] thread handler + user_name [in] user name + host_name [in] host name + + RETURN + On success, return a valid pointer to the created and initialized + LEX_STRING, which contains definer information. + On error, return 0. +*/ + +LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) +{ + LEX_USER *definer; + + /* Check that specified host name is valid. */ + + if (host_name->length == 0) + { + my_error(ER_MALFORMED_DEFINER, MYF(0)); + return 0; + } + + /* Create and initialize. */ + + if (! (definer= (LEX_USER*) thd->alloc(sizeof (LEX_USER)))) + return 0; + + definer->user= *user_name; + definer->host= *host_name; + + return definer; +} diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b4b24e0b6be..0e42c45b273 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1060,18 +1060,36 @@ view_store_options(THD *thd, TABLE_LIST *table, String *buff) default: DBUG_ASSERT(0); // never should happen } - buff->append("DEFINER=", 8); - append_identifier(thd, buff, - table->definer.user.str, table->definer.user.length); - buff->append('@'); - append_identifier(thd, buff, - table->definer.host.str, table->definer.host.length); + append_definer(thd, buff, &table->definer.user, &table->definer.host); if (table->view_suid) - buff->append(" SQL SECURITY DEFINER ", 22); + buff->append("SQL SECURITY DEFINER ", 21); else - buff->append(" SQL SECURITY INVOKER ", 22); + buff->append("SQL SECURITY INVOKER ", 21); } + +/* + Append DEFINER clause to the given buffer. + + SYNOPSIS + append_definer() + thd [in] thread handle + buffer [inout] buffer to hold DEFINER clause + definer_user [in] user name part of definer + definer_host [in] host name part of definer +*/ + +void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, + const LEX_STRING *definer_host) +{ + buffer->append(STRING_WITH_LEN("DEFINER=")); + append_identifier(thd, buffer, definer_user->str, definer_user->length); + buffer->append('@'); + append_identifier(thd, buffer, definer_host->str, definer_host->length); + buffer->append(' '); +} + + static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) { @@ -3094,7 +3112,8 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db, enum trg_event_type event, enum trg_action_time_type timing, LEX_STRING *trigger_stmt, - ulong sql_mode) + ulong sql_mode, + LEX_STRING *definer_buffer) { CHARSET_INFO *cs= system_charset_info; byte *sql_mode_str; @@ -3119,6 +3138,7 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db, sql_mode, &sql_mode_len); table->field[17]->store((const char*)sql_mode_str, sql_mode_len, cs); + table->field[18]->store((const char *)definer_buffer->str, definer_buffer->length, cs); return schema_table_store_record(thd, table); } @@ -3152,15 +3172,21 @@ static int get_schema_triggers_record(THD *thd, struct st_table_list *tables, LEX_STRING trigger_name; LEX_STRING trigger_stmt; ulong sql_mode; + char definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + LEX_STRING definer_buffer; + definer_buffer.str= definer_holder; if (triggers->get_trigger_info(thd, (enum trg_event_type) event, (enum trg_action_time_type)timing, &trigger_name, &trigger_stmt, - &sql_mode)) + &sql_mode, + &definer_buffer)) continue; + if (store_trigger(thd, table, base_name, file_name, &trigger_name, (enum trg_event_type) event, (enum trg_action_time_type) timing, &trigger_stmt, - sql_mode)) + sql_mode, + &definer_buffer)) DBUG_RETURN(1); } } @@ -4064,6 +4090,7 @@ ST_FIELD_INFO triggers_fields_info[]= {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0}, {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"}, {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"}, + {"DEFINER", 65535, MYSQL_TYPE_STRING, 0, 0, "Definer"}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} }; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index dbad8dcffb5..3ab389d0519 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -32,15 +32,36 @@ const char * const triggers_file_ext= ".TRG"; */ static File_option triggers_file_parameters[]= { - {{(char*)"triggers", 8}, + { + { (char *) STRING_WITH_LEN("triggers") }, offsetof(class Table_triggers_list, definitions_list), - FILE_OPTIONS_STRLIST}, - {{(char*)"sql_modes", 13}, + FILE_OPTIONS_STRLIST + }, + { + /* + FIXME: Length specified for "sql_modes" key is erroneous, problem caused + by this are reported as BUG#14090 and should be fixed ASAP. + */ + { (char *) "sql_modes", 13 }, offsetof(class Table_triggers_list, definition_modes_list), - FILE_OPTIONS_ULLLIST}, - {{0, 0}, 0, FILE_OPTIONS_STRING} + FILE_OPTIONS_ULLLIST + }, + { + { (char *) STRING_WITH_LEN("definers") }, + offsetof(class Table_triggers_list, definers_list), + FILE_OPTIONS_STRLIST + }, + { { 0, 0 }, 0, FILE_OPTIONS_STRING } }; +/* + This must be kept up to date whenever a new option is added to the list + above, as it specifies the number of required parameters of the trigger in + .trg file. +*/ + +static const int TRG_NUM_REQUIRED_PARAMETERS= 4; +static const int TRG_MAX_VERSIONS= 3; /* Structure representing contents of .TRN file which are used to support @@ -58,9 +79,16 @@ const char * const trigname_file_ext= ".TRN"; static File_option trigname_file_parameters[]= { - {{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table), - FILE_OPTIONS_ESTRING}, - {{0, 0}, 0, FILE_OPTIONS_STRING} + { + /* + FIXME: Length specified for "trigger_table" key is erroneous, problem + caused by this are reported as BUG#14090 and should be fixed ASAP. + */ + { (char *) "trigger_table", 15 }, + offsetof(struct st_trigname, trigger_table), + FILE_OPTIONS_ESTRING + }, + { { 0, 0 }, 0, FILE_OPTIONS_STRING } }; @@ -104,6 +132,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { TABLE *table; bool result= TRUE; + LEX_STRING definer_user; + LEX_STRING definer_host; + DBUG_ENTER("mysql_create_or_drop_trigger"); /* @@ -184,7 +215,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) } result= (create ? - table->triggers->create_trigger(thd, tables): + table->triggers->create_trigger(thd, tables, &definer_user, &definer_host): table->triggers->drop_trigger(thd, tables)); end: @@ -192,17 +223,30 @@ end: start_waiting_global_read_lock(thd); if (!result) + { + if (mysql_bin_log.is_open()) { - if (mysql_bin_log.is_open()) + thd->clear_error(); + + String log_query(thd->query, thd->query_length, system_charset_info); + + if (create) { - thd->clear_error(); - /* Such a statement can always go directly to binlog, no trans cache */ - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); + log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */ + + log_query.append("CREATE "); + append_definer(thd, &log_query, &definer_user, &definer_host); + log_query.append(thd->lex->trigger_definition_begin); } - send_ok(thd); + + /* Such a statement can always go directly to binlog, no trans cache. */ + Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE); + mysql_bin_log.write(&qinfo); } + send_ok(thd); + } + DBUG_RETURN(result); } @@ -212,15 +256,26 @@ end: SYNOPSIS create_trigger() - thd - current thread context (including trigger definition in LEX) - tables - table list containing one open table for which trigger is - created. + thd - current thread context (including trigger definition in + LEX) + tables - table list containing one open table for which the + trigger is created. + definer_user - [out] after a call it points to 0-terminated string, + which contains user name part of the actual trigger + definer. The caller is responsible to provide memory for + storing LEX_STRING object. + definer_host - [out] after a call it points to 0-terminated string, + which contains host name part of the actual trigger + definer. The caller is responsible to provide memory for + storing LEX_STRING object. RETURN VALUE False - success True - error */ -bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) +bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, + LEX_STRING *definer_user, + LEX_STRING *definer_host) { LEX *lex= thd->lex; TABLE *table= tables->table; @@ -229,6 +284,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) LEX_STRING dir, file, trigname_file; LEX_STRING *trg_def, *name; ulonglong *trg_sql_mode; + char trg_definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + LEX_STRING *trg_definer; Item_trigger_field *trg_field; struct st_trigname trigname; @@ -249,6 +306,31 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) return 1; } + /* + Definer attribute of the Lex instance is always set in sql_yacc.yy when + trigger is created. + */ + + DBUG_ASSERT(lex->definer); + + /* + If the specified definer differs from the current user, we should check + that the current user has SUPER privilege (in order to create trigger + under another user one must have SUPER privilege). + */ + + if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) || + my_strcasecmp(system_charset_info, + lex->definer->host.str, + thd->security_ctx->priv_host)) + { + if (check_global_access(thd, SUPER_ACL)) + { + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); + return TRUE; + } + } + /* Let us check if all references to fields in old/new versions of row in this trigger are ok. @@ -318,15 +400,39 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) definitions_list.push_back(trg_def, &table->mem_root) || !(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root, sizeof(ulonglong))) || - definition_modes_list.push_back(trg_sql_mode, &table->mem_root)) + definition_modes_list.push_back(trg_sql_mode, &table->mem_root) || + !(trg_definer= (LEX_STRING*) alloc_root(&table->mem_root, + sizeof(LEX_STRING))) || + definers_list.push_back(trg_definer, &table->mem_root)) goto err_with_cleanup; trg_def->str= thd->query; trg_def->length= thd->query_length; *trg_sql_mode= thd->variables.sql_mode; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (!is_acl_user(lex->definer->host.str, + lex->definer->user.str)) + { + push_warning_printf(thd, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NO_SUCH_USER, + ER(ER_NO_SUCH_USER), + lex->definer->user.str, + lex->definer->host.str); + } +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ + + *definer_user= lex->definer->user; + *definer_host= lex->definer->host; + + trg_definer->str= trg_definer_holder; + trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@", + definer_host->str, NullS) - trg_definer->str; + if (!sql_create_definition_file(&dir, &file, &triggers_file_type, - (gptr)this, triggers_file_parameters, 3)) + (gptr)this, triggers_file_parameters, + TRG_MAX_VERSIONS)) return 0; err_with_cleanup: @@ -403,12 +509,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) List_iterator_fast it_name(names_list); List_iterator it_def(definitions_list); List_iterator it_mod(definition_modes_list); + List_iterator it_definer(definers_list); char path[FN_REFLEN]; while ((name= it_name++)) { it_def++; it_mod++; + it_definer++; if (my_strcasecmp(table_alias_charset, lex->spname->m_name.str, name->str) == 0) @@ -419,6 +527,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) */ it_def.remove(); it_mod.remove(); + it_definer.remove(); if (definitions_list.is_empty()) { @@ -446,7 +555,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) if (sql_create_definition_file(&dir, &file, &triggers_file_type, (gptr)this, triggers_file_parameters, - 3)) + TRG_MAX_VERSIONS)) return 1; } @@ -568,7 +677,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_RETURN(0); /* - File exists so we got to load triggers + File exists so we got to load triggers. FIXME: A lot of things to do here e.g. how about other funcs and being more paranoical ? */ @@ -584,13 +693,16 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_RETURN(1); /* - We don't have sql_modes in old versions of .TRG file, so we should - initialize list for safety. + We don't have the following attributes in old versions of .TRG file, so + we should initialize the list for safety: + - sql_modes; + - definers; */ triggers->definition_modes_list.empty(); + triggers->definers_list.empty(); if (parser->parse((gptr)triggers, &table->mem_root, - triggers_file_parameters, 2)) + triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS)) DBUG_RETURN(1); List_iterator_fast it(triggers->definitions_list); @@ -612,7 +724,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_RETURN(1); // EOM } *trg_sql_mode= global_system_variables.sql_mode; - while ((trg_create_str= it++)) + while (it++) { if (triggers->definition_modes_list.push_back(trg_sql_mode, &table->mem_root)) @@ -623,8 +735,43 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, it.rewind(); } + if (triggers->definers_list.is_empty() && + !triggers->definitions_list.is_empty()) + { + /* + It is old file format => we should fill list of definers. + + If there is no definer information, we should not switch context to + definer when checking privileges. I.e. privileges for such triggers + are checked for "invoker" rather than for "definer". + */ + + LEX_STRING *trg_definer; + + if (! (trg_definer= (LEX_STRING*)alloc_root(&table->mem_root, + sizeof(LEX_STRING)))) + DBUG_RETURN(1); // EOM + + trg_definer->str= ""; + trg_definer->length= 0; + + while (it++) + { + if (triggers->definers_list.push_back(trg_definer, + &table->mem_root)) + { + DBUG_RETURN(1); // EOM + } + } + + it.rewind(); + } + DBUG_ASSERT(triggers->definition_modes_list.elements == triggers->definitions_list.elements); + DBUG_ASSERT(triggers->definers_list.elements == + triggers->definitions_list.elements); + table->triggers= triggers; /* @@ -647,6 +794,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, char *trg_name_buff; List_iterator_fast itm(triggers->definition_modes_list); + List_iterator_fast it_definer(triggers-> + definers_list); LEX *old_lex= thd->lex, lex; ulong save_sql_mode= thd->variables.sql_mode; @@ -659,22 +808,55 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, while ((trg_create_str= it++)) { trg_sql_mode= itm++; + LEX_STRING *trg_definer= it_definer++; thd->variables.sql_mode= (ulong)*trg_sql_mode; lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length); if (yyparse((void *)thd) || thd->is_fatal_error) { /* - Free lex associated resources + Free lex associated resources. QQ: Do we really need all this stuff here ? */ delete lex.sphead; goto err_with_lex_cleanup; } - lex.sphead->m_sql_mode= *trg_sql_mode; + lex.sphead->set_info(0, 0, &lex.sp_chistics, *trg_sql_mode); + triggers->bodies[lex.trg_chistics.event] [lex.trg_chistics.action_time]= lex.sphead; + + if (!trg_definer->length) + { + /* + This trigger was created/imported from the previous version of + MySQL, which does not support triggers definers. We should emit + warning here. + */ + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), + (const char*) db, + (const char*) lex.sphead->m_name.str); + + /* + Set definer to the '' to correct displaying in the information + schema. + */ + + lex.sphead->set_definer("", 0); + + /* + Triggers without definer information are executed under the + authorization of the invoker. + */ + + lex.sphead->m_chistics->suid= SP_IS_NOT_SUID; + } + else + lex.sphead->set_definer(trg_definer->str, trg_definer->length); + if (triggers->names_list.push_back(&lex.sphead->m_name, &table->mem_root)) goto err_with_lex_cleanup; @@ -701,6 +883,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, trg_field= trg_field->next_trg_field) trg_field->setup_field(thd, table); + triggers->m_spec_var_used[lex.trg_chistics.event] + [lex.trg_chistics.action_time]= + lex.trg_table_fields.first ? TRUE : FALSE; + lex_end(&lex); } thd->db= save_db.str; @@ -744,6 +930,9 @@ err_with_lex_cleanup: name - returns name of trigger stmt - returns statement of trigger sql_mode - returns sql_mode of trigger + definer_user - returns definer/creator of trigger. The caller is + responsible to allocate enough space for storing definer + information. RETURN VALUE False - success @@ -754,7 +943,8 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, trg_action_time_type time_type, LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, - ulong *sql_mode) + ulong *sql_mode, + LEX_STRING *definer) { sp_head *body; DBUG_ENTER("get_trigger_info"); @@ -763,6 +953,18 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, *trigger_name= body->m_name; *trigger_stmt= body->m_body; *sql_mode= body->m_sql_mode; + + if (body->m_chistics->suid == SP_IS_NOT_SUID) + { + definer->str[0]= 0; + definer->length= 0; + } + else + { + definer->length= strxmov(definer->str, body->m_definer_user.str, "@", + body->m_definer_host.str, NullS) - definer->str; + } + DBUG_RETURN(0); } DBUG_RETURN(1); @@ -898,8 +1100,9 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, bool old_row_is_record1) { int res= 0; + sp_head *sp_trigger= bodies[event][time_type]; - if (bodies[event][time_type]) + if (sp_trigger) { Sub_statement_state statement_state; @@ -914,14 +1117,54 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, old_field= table->field; } +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *save_ctx; + + if (sp_change_security_context(thd, sp_trigger, &save_ctx)) + return TRUE; + /* - FIXME: We should juggle with security context here (because trigger - should be invoked with creator rights). + NOTE: TRIGGER_ACL should be used below. */ + if (check_global_access(thd, SUPER_ACL)) + { + sp_restore_security_context(thd, save_ctx); + return TRUE; + } + + /* + If the trigger uses special variables (NEW/OLD), check that we have + SELECT and UPDATE privileges on the subject table. + */ + + if (is_special_var_used(event, time_type)) + { + TABLE_LIST table_list; + bzero((char *) &table_list, sizeof (table_list)); + table_list.db= (char *) table->s->db; + table_list.db_length= strlen(table_list.db); + table_list.table_name= (char *) table->s->table_name; + table_list.table_name_length= strlen(table_list.table_name); + table_list.alias= (char *) table->alias; + table_list.table= table; + + if (check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0)) + { + sp_restore_security_context(thd, save_ctx); + return TRUE; + } + } + +#endif // NO_EMBEDDED_ACCESS_CHECKS + thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); - res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); + res= sp_trigger->execute_function(thd, 0, 0, 0); thd->restore_sub_statement_state(&statement_state); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + sp_restore_security_context(thd, save_ctx); +#endif // NO_EMBEDDED_ACCESS_CHECKS } return res; diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index c1d1f8d0e9e..6be42d7b868 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -55,6 +55,12 @@ class Table_triggers_list: public Sql_alloc */ LEX_STRING sroutines_key; + /* + is_special_var_used specifies whether trigger body contains special + variables (NEW/OLD). + */ + bool m_spec_var_used[TRG_EVENT_MAX][TRG_ACTION_MAX]; + public: /* Field responsible for storing triggers definitions in file. @@ -66,6 +72,8 @@ public: */ List definition_modes_list; + List definers_list; + Table_triggers_list(TABLE *table_arg): record1_field(0), table(table_arg) { @@ -73,7 +81,9 @@ public: } ~Table_triggers_list(); - bool create_trigger(THD *thd, TABLE_LIST *table); + bool create_trigger(THD *thd, TABLE_LIST *table, + LEX_STRING *definer_user, + LEX_STRING *definer_host); bool drop_trigger(THD *thd, TABLE_LIST *table); bool process_triggers(THD *thd, trg_event_type event, trg_action_time_type time_type, @@ -81,7 +91,8 @@ public: bool get_trigger_info(THD *thd, trg_event_type event, trg_action_time_type time_type, LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, - ulong *sql_mode); + ulong *sql_mode, + LEX_STRING *definer); static bool check_n_load(THD *thd, const char *db, const char *table_name, TABLE *table, bool names_only); @@ -98,6 +109,11 @@ public: return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); } + inline bool is_special_var_used(int event, int action_time) const + { + return m_spec_var_used[event][action_time]; + } + void set_table(TABLE *new_table); friend class Item_trigger_field; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 71c5d198b27..b642d24b30d 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -214,29 +214,28 @@ bool mysql_create_view(THD *thd, - same as current user - current user has SUPER_ACL */ - if (strcmp(lex->create_view_definer->user.str, + if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 || my_strcasecmp(system_charset_info, - lex->create_view_definer->host.str, + lex->definer->host.str, thd->security_ctx->priv_host) != 0) { if (!(thd->security_ctx->master_access & SUPER_ACL)) { - my_error(ER_VIEW_OTHER_USER, MYF(0), lex->create_view_definer->user.str, - lex->create_view_definer->host.str); + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); res= TRUE; goto err; } else { - if (!is_acl_user(lex->create_view_definer->host.str, - lex->create_view_definer->user.str)) + if (!is_acl_user(lex->definer->host.str, + lex->definer->user.str)) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_NO_SUCH_USER, ER(ER_NO_SUCH_USER), - lex->create_view_definer->user.str, - lex->create_view_definer->host.str); + lex->definer->user.str, + lex->definer->host.str); } } } @@ -658,8 +657,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } view->algorithm= lex->create_view_algorithm; - view->definer.user= lex->create_view_definer->user; - view->definer.host= lex->create_view_definer->host; + view->definer.user= lex->definer->user; + view->definer.host= lex->definer->host; view->view_suid= lex->create_view_suid; view->with_check= lex->create_view_check; if ((view->updatable_view= (can_be_merged && @@ -807,7 +806,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER), table->db, table->table_name); - if (default_view_definer(thd->security_ctx, &table->definer)) + if (get_default_definer(thd, &table->definer)) goto err; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index abc440df1c5..55002def5e9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -776,7 +776,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp -%type user grant_user +%type user grant_user get_definer %type opt_collate @@ -827,10 +827,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); subselect_end select_var_list select_var_list_init help opt_len opt_extended_describe prepare prepare_src execute deallocate - statement sp_suid opt_view_list view_list or_replace algorithm + statement sp_suid sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec - view_user view_suid + definer view_replace_or_algorithm view_replace view_algorithm_opt + view_algorithm view_or_trigger_tail view_suid view_tail view_list_opt + view_list view_select view_check_option trigger_tail END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -1258,80 +1260,14 @@ create: YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); } - | CREATE or_replace algorithm view_user view_suid VIEW_SYM table_ident + | CREATE { - THD *thd= YYTHD; - LEX *lex= thd->lex; - lex->sql_command= SQLCOM_CREATE_VIEW; - lex->create_view_start= thd->query; - /* first table in list is target VIEW name */ - if (!lex->select_lex.add_table_to_list(thd, $7, NULL, 0)) - YYABORT; + Lex->create_view_mode= VIEW_CREATE_NEW; + Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; + Lex->create_view_suid= TRUE; } - opt_view_list AS select_view_init check_option + view_or_trigger {} - | CREATE TRIGGER_SYM sp_name trg_action_time trg_event - ON table_ident FOR_SYM EACH_SYM ROW_SYM - { - LEX *lex= Lex; - sp_head *sp; - - if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"); - YYABORT; - } - - if (!(sp= new sp_head())) - YYABORT; - sp->reset_thd_mem_root(YYTHD); - sp->init(lex); - - sp->m_type= TYPE_ENUM_TRIGGER; - lex->sphead= sp; - lex->spname= $3; - /* - We have to turn of CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; - YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; - - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->m_body_begin= lex->ptr; - } - sp_proc_stmt - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - - lex->sql_command= SQLCOM_CREATE_TRIGGER; - sp->init_strings(YYTHD, lex, $3); - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; - sp->restore_thd_mem_root(YYTHD); - - if (sp->is_not_allowed_in_function("trigger")) - YYABORT; - - /* - We have to do it after parsing trigger body, because some of - sp_proc_stmt alternatives are not saving/restoring LEX, so - lex->query_tables can be wiped out. - - QQ: What are other consequences of this? - - QQ: Could we loosen lock type in certain cases ? - */ - if (!lex->select_lex.add_table_to_list(YYTHD, $7, - (LEX_STRING*) 0, - TL_OPTION_UPDATING, - TL_WRITE)) - YYABORT; - } | CREATE USER clear_privileges grant_list { Lex->sql_command = SQLCOM_CREATE_USER; @@ -3435,7 +3371,8 @@ alter: lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->spname= $3; } - | ALTER algorithm view_user view_suid VIEW_SYM table_ident + | ALTER view_algorithm_opt definer view_suid + VIEW_SYM table_ident { THD *thd= YYTHD; LEX *lex= thd->lex; @@ -3445,7 +3382,7 @@ alter: /* first table in list is target VIEW name */ lex->select_lex.add_table_to_list(thd, $6, NULL, 0); } - opt_view_list AS select_view_init check_option + view_list_opt AS view_select view_check_option {} ; @@ -4013,18 +3950,6 @@ select_init: | '(' select_paren ')' union_opt; -select_view_init: - SELECT_SYM remember_name select_init2 - { - Lex->create_view_select_start= $2; - } - | - '(' remember_name select_paren ')' union_opt - { - Lex->create_view_select_start= $2; - } - ; - select_paren: SELECT_SYM select_part2 { @@ -8963,8 +8888,119 @@ subselect_end: lex->current_select = lex->current_select->return_after_parsing(); }; -opt_view_list: - /* empty */ {} +definer: + get_definer + { + THD *thd= YYTHD; + + if (! (thd->lex->definer= create_definer(thd, &$1->user, &$1->host))) + YYABORT; + } + ; + +get_definer: + opt_current_definer + { + THD *thd= YYTHD; + + if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + YYABORT; + + if (get_default_definer(thd, $$)) + YYABORT; + } + | DEFINER_SYM EQ ident_or_text '@' ident_or_text + { + if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user)))) + YYABORT; + + $$->user= $3; + $$->host= $5; + } + ; + +opt_current_definer: + /* empty */ + | DEFINER_SYM EQ CURRENT_USER optional_braces + ; + +/************************************************************************** + + CREATE VIEW statement options. + +**************************************************************************/ + +view_replace_or_algorithm: + view_replace + {} + | view_replace view_algorithm + {} + | view_algorithm + {} + ; + +view_replace: + OR_SYM REPLACE + { Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; } + ; + +view_algorithm: + ALGORITHM_SYM EQ UNDEFINED_SYM + { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } + | ALGORITHM_SYM EQ MERGE_SYM + { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } + | ALGORITHM_SYM EQ TEMPTABLE_SYM + { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } + ; + +view_algorithm_opt: + /* empty */ + { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } + | view_algorithm + {} + ; + +view_or_trigger: + definer view_or_trigger_tail + {} + | view_replace_or_algorithm definer view_tail + {} + ; + +view_or_trigger_tail: + view_tail + {} + | trigger_tail + {} + ; + +view_suid: + /* empty */ + { Lex->create_view_suid= TRUE; } + | SQL_SYM SECURITY_SYM DEFINER_SYM + { Lex->create_view_suid= TRUE; } + | SQL_SYM SECURITY_SYM INVOKER_SYM + { Lex->create_view_suid= FALSE; } + ; + +view_tail: + view_suid VIEW_SYM table_ident + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + lex->sql_command= SQLCOM_CREATE_VIEW; + lex->create_view_start= thd->query; + /* first table in list is target VIEW name */ + if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + YYABORT; + } + view_list_opt AS view_select view_check_option + {} + ; + +view_list_opt: + /* empty */ + {} | '(' view_list ')' ; @@ -8981,79 +9017,102 @@ view_list: } ; -or_replace: - /* empty */ { Lex->create_view_mode= VIEW_CREATE_NEW; } - | OR_SYM REPLACE { Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; } +view_select: + SELECT_SYM remember_name select_init2 + { + Lex->create_view_select_start= $2; + } + | '(' remember_name select_paren ')' union_opt + { + Lex->create_view_select_start= $2; + } ; -algorithm: +view_check_option: /* empty */ - { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } - | ALGORITHM_SYM EQ UNDEFINED_SYM - { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; } - | ALGORITHM_SYM EQ MERGE_SYM - { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } - | ALGORITHM_SYM EQ TEMPTABLE_SYM - { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } + { Lex->create_view_check= VIEW_CHECK_NONE; } + | WITH CHECK_SYM OPTION + { Lex->create_view_check= VIEW_CHECK_CASCADED; } + | WITH CASCADED CHECK_SYM OPTION + { Lex->create_view_check= VIEW_CHECK_CASCADED; } + | WITH LOCAL_SYM CHECK_SYM OPTION + { Lex->create_view_check= VIEW_CHECK_LOCAL; } ; -view_user: - /* empty */ - { - THD *thd= YYTHD; - if (!(thd->lex->create_view_definer= - (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) - YYABORT; - if (default_view_definer(thd->security_ctx, - thd->lex->create_view_definer)) - YYABORT; - } - | DEFINER_SYM EQ CURRENT_USER optional_braces - { - THD *thd= YYTHD; - if (!(thd->lex->create_view_definer= - (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) - YYABORT; - if (default_view_definer(thd->security_ctx, - thd->lex->create_view_definer)) - YYABORT; - } - | DEFINER_SYM EQ ident_or_text '@' ident_or_text +/************************************************************************** + + CREATE TRIGGER statement parts. + +**************************************************************************/ + +trigger_tail: + TRIGGER_SYM remember_name sp_name trg_action_time trg_event + ON table_ident FOR_SYM EACH_SYM ROW_SYM + { + LEX *lex= Lex; + sp_head *sp; + + if (lex->sphead) { - THD *thd= YYTHD; - st_lex_user *view_user; - if (!(thd->lex->create_view_definer= view_user= - (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) - YYABORT; - view_user->user = $3; view_user->host=$5; - if (view_user->host.length == 0) - { - my_error(ER_NO_VIEW_USER, MYF(0)); - YYABORT; - } + my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"); + YYABORT; } - ; - -view_suid: - /* empty */ - { Lex->create_view_suid= TRUE; } - | - SQL_SYM SECURITY_SYM DEFINER_SYM - { Lex->create_view_suid= TRUE; } - | SQL_SYM SECURITY_SYM INVOKER_SYM - { Lex->create_view_suid= FALSE; } + + if (!(sp= new sp_head())) + YYABORT; + sp->reset_thd_mem_root(YYTHD); + sp->init(lex); + + lex->trigger_definition_begin= $2; + + sp->m_type= TYPE_ENUM_TRIGGER; + lex->sphead= sp; + lex->spname= $3; + /* + We have to turn of CLIENT_MULTI_QUERIES while parsing a + stored procedure, otherwise yylex will chop it into pieces + at each ';'. + */ + sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; + YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; + + bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->m_body_begin= lex->ptr; + } + sp_proc_stmt + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + + lex->sql_command= SQLCOM_CREATE_TRIGGER; + sp->init_strings(YYTHD, lex, $3); + /* Restore flag if it was cleared above */ + if (sp->m_old_cmq) + YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; + sp->restore_thd_mem_root(YYTHD); + + if (sp->is_not_allowed_in_function("trigger")) + YYABORT; + + /* + We have to do it after parsing trigger body, because some of + sp_proc_stmt alternatives are not saving/restoring LEX, so + lex->query_tables can be wiped out. + + QQ: What are other consequences of this? + + QQ: Could we loosen lock type in certain cases ? + */ + if (!lex->select_lex.add_table_to_list(YYTHD, $7, + (LEX_STRING*) 0, + TL_OPTION_UPDATING, + TL_WRITE)) + YYABORT; + } ; -check_option: - /* empty */ - { Lex->create_view_check= VIEW_CHECK_NONE; } - | WITH CHECK_SYM OPTION - { Lex->create_view_check= VIEW_CHECK_CASCADED; } - | WITH CASCADED CHECK_SYM OPTION - { Lex->create_view_check= VIEW_CHECK_CASCADED; } - | WITH LOCAL_SYM CHECK_SYM OPTION - { Lex->create_view_check= VIEW_CHECK_LOCAL; } - ; +/*************************************************************************/ xa: XA_SYM begin_or_start xid opt_join_or_resume { From 5d425f936190057f727f73c8575fe5953cf56101 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 03:28:35 +0300 Subject: [PATCH 37/48] Manual merge. --- mysql-test/r/rpl_sp.result | 99 +++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 7ec78af2548..ba840caf6c2 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -263,7 +263,104 @@ a 1 show binlog events in 'master-bin.000001' from 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query 1 # drop database if exists mysqltest1 +master-bin.000001 # Query 1 # create database mysqltest1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo2() +select * from mysqltest1.t1 +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql +master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) +master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo3() +deterministic +insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(20),(20) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2 +master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1()) +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() +returns int +begin +insert into t2 values(20),(20); +return 10; +end +master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`() +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; drop trigger trg +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) select * from t1; a 1 From 534275921e9f20bd071a3514b28ff795be04a4e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 13:39:46 +0400 Subject: [PATCH 38/48] Fix for bug#13818 SHOW CREATE VIEW / TABLE and information_schema.views fail for invalid view Permit SHOW CREATE VIEW, SHOW CREATE TABLE, and retrieval of metadata from information_schema for invalid views mysql-test/r/information_schema.result: Fix for bug#13818 SHOW CREATE VIEW / TABLE and information_schema.views fail for invalid view test case mysql-test/t/information_schema.test: Fix for bug#13818 SHOW CREATE VIEW / TABLE and information_schema.views fail for invalid view test case --- mysql-test/r/information_schema.result | 14 +++++ mysql-test/t/information_schema.test | 2 + sql/sql_show.cc | 81 +++++++++++++++----------- 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 9cd97784832..079a1af1184 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -647,12 +647,16 @@ drop function sub1; select table_name from information_schema.views where table_schema='test'; table_name +v2 +v3 Warnings: Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them select table_name from information_schema.views where table_schema='test'; table_name +v2 +v3 Warnings: Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them @@ -669,6 +673,16 @@ f1_key select constraint_name from information_schema.table_constraints where table_schema='test'; constraint_name +show create view v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `test`.`t1`.`f1` AS `c` from `t1` +Warnings: +Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +show create table v3; +View Create View +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select sql_no_cache `test`.`sub1`(1) AS `c` +Warnings: +Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them drop view v2; drop view v3; drop table t4; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 8a28e8bbf02..1cd55926e80 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -379,6 +379,8 @@ where table_schema='test'; select index_name from information_schema.statistics where table_schema='test'; select constraint_name from information_schema.table_constraints where table_schema='test'; +show create view v2; +show create table v3; drop view v2; drop view v3; drop table t4; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 09fd982bdab..5ad987d6b7a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -362,7 +362,21 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Only one table for now, but VIEW can involve several tables */ if (open_normal_and_derived_tables(thd, table_list, 0)) - DBUG_RETURN(TRUE); + { + if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID) + DBUG_RETURN(TRUE); + /* + Clear all messages with 'error' level status and + issue a warning with 'warning' level status in + case of invalid view and last error is ER_VIEW_INVALID + */ + mysql_reset_errors(thd, true); + push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + table_list->view_db.str, + table_list->view_name.str); + } /* TODO: add environment variables show when it become possible */ if (thd->lex->only_view && !table_list->view) @@ -2992,47 +3006,44 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, DBUG_ENTER("get_schema_views_record"); char definer[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; uint definer_len; - if (!res) + + if (tables->view) { - if (tables->view) + restore_record(table, s->default_values); + table->field[1]->store(tables->view_db.str, tables->view_db.length, cs); + table->field[2]->store(tables->view_name.str, tables->view_name.length, + cs); + table->field[3]->store(tables->query.str, tables->query.length, cs); + + if (tables->with_check != VIEW_CHECK_NONE) { - restore_record(table, s->default_values); - table->field[1]->store(tables->view_db.str, tables->view_db.length, cs); - table->field[2]->store(tables->view_name.str, tables->view_name.length, - cs); - table->field[3]->store(tables->query.str, tables->query.length, cs); - - if (tables->with_check != VIEW_CHECK_NONE) - { - if (tables->with_check == VIEW_CHECK_LOCAL) - table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs); - else - table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs); - } + if (tables->with_check == VIEW_CHECK_LOCAL) + table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs); else - table->field[4]->store(STRING_WITH_LEN("NONE"), cs); - - if (tables->updatable_view) - table->field[5]->store(STRING_WITH_LEN("YES"), cs); - else - table->field[5]->store(STRING_WITH_LEN("NO"), cs); - definer_len= (strxmov(definer, tables->definer.user.str, "@", - tables->definer.host.str, NullS) - definer); - table->field[6]->store(definer, definer_len, cs); - if (tables->view_suid) - table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); - else - table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); - DBUG_RETURN(schema_table_store_record(thd, table)); + table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs); } - } - else - { - if (tables->view) + else + table->field[4]->store(STRING_WITH_LEN("NONE"), cs); + + if (tables->updatable_view) + table->field[5]->store(STRING_WITH_LEN("YES"), cs); + else + table->field[5]->store(STRING_WITH_LEN("NO"), cs); + definer_len= (strxmov(definer, tables->definer.user.str, "@", + tables->definer.host.str, NullS) - definer); + table->field[6]->store(definer, definer_len, cs); + if (tables->view_suid) + table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); + else + table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + if (res) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); - thd->clear_error(); } + if (res) + thd->clear_error(); DBUG_RETURN(0); } From 9a0da055fd6bd662b83eacef2a60350b32ded966 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 11:40:35 +0200 Subject: [PATCH 39/48] Fix for BUG#14662: view column in ORDER BY considered ambiguous if SELECT contains the same column as an aliased and as a non-aliased column. The problem was that Item_direct_view_ref::eq() was first comparing view columns by name, and in this case the name of one of them is different since it is aliased. mysql-test/r/select.result: Added test for BUG#14662. mysql-test/t/select.test: Added test for BUG#14662. sql/item.cc: Changed the way view column refenreces are compared. Two view columns are equal if they resolve to the same result field of a view. --- mysql-test/r/select.result | 42 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/select.test | 20 ++++++++++++++++++ sql/item.cc | 31 ++++++++++++++++++---------- 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 318cf8e7b65..8a126b7ddfb 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3241,3 +3241,45 @@ f1 f2 Warnings: Warning 1292 Incorrect date value: '2005-09-3a' for column 'f2' at row 1 drop table t1; +create table t1 (f1 int, f2 int); +insert into t1 values (1, 30), (2, 20), (3, 10); +create algorithm=merge view v1 as select f1, f2 from t1; +create algorithm=merge view v2 (f2, f1) as select f1, f2 from t1; +create algorithm=merge view v3 as select t1.f1 as f2, t1.f2 as f1 from t1; +select t1.f1 as x1, f1 from t1 order by t1.f1; +x1 f1 +1 1 +2 2 +3 3 +select v1.f1 as x1, f1 from v1 order by v1.f1; +x1 f1 +1 1 +2 2 +3 3 +select v2.f1 as x1, f1 from v2 order by v2.f1; +x1 f1 +10 10 +20 20 +30 30 +select v3.f1 as x1, f1 from v3 order by v3.f1; +x1 f1 +10 10 +20 20 +30 30 +select f1, f2, v1.f1 as x1 from v1 order by v1.f1; +f1 f2 x1 +1 30 1 +2 20 2 +3 10 3 +select f1, f2, v2.f1 as x1 from v2 order by v2.f1; +f1 f2 x1 +10 3 10 +20 2 20 +30 1 30 +select f1, f2, v3.f1 as x1 from v3 order by v3.f1; +f1 f2 x1 +10 3 10 +20 2 20 +30 1 30 +drop table t1; +drop view v1, v2, v3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index e7e6d899a66..33a3ff578f8 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2729,3 +2729,23 @@ select * from t1 where f2 >= '2005-09-3a'; select * from t1 where f2 <= '2005-09-31'; select * from t1 where f2 <= '2005-09-3a'; drop table t1; + +# +# Bug ##14662 ORDER BY on column of a view, with an alias of the same +# column causes ambiguous +# + +create table t1 (f1 int, f2 int); +insert into t1 values (1, 30), (2, 20), (3, 10); +create algorithm=merge view v1 as select f1, f2 from t1; +create algorithm=merge view v2 (f2, f1) as select f1, f2 from t1; +create algorithm=merge view v3 as select t1.f1 as f2, t1.f2 as f1 from t1; +select t1.f1 as x1, f1 from t1 order by t1.f1; +select v1.f1 as x1, f1 from v1 order by v1.f1; +select v2.f1 as x1, f1 from v2 order by v2.f1; +select v3.f1 as x1, f1 from v3 order by v3.f1; +select f1, f2, v1.f1 as x1 from v1 order by v1.f1; +select f1, f2, v2.f1 as x1 from v2 order by v2.f1; +select f1, f2, v3.f1 as x1 from v3 order by v3.f1; +drop table t1; +drop view v1, v2, v3; diff --git a/sql/item.cc b/sql/item.cc index 1850b7d05c3..1767f9d97c1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4938,8 +4938,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) } /* - Compare view field's name with item's name before call to referenced - item's eq() + Compare two view column references for equality. SYNOPSIS Item_direct_view_ref::eq() @@ -4947,12 +4946,13 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) binary_cmp make binary comparison DESCRIPTION - Consider queries: - create view v1 as select t1.f1 as f2, t1.f2 as f1 from t1; - select * from v1 order by f1; - In order to choose right field for sorting we need to compare - given item's name (f1) to view field's name prior to calling - referenced item's eq(). + A view column reference is considered equal to another column + reference if the second one is a view column and if both column + references point to the same field. For views 'same field' means + the same Item_field object in the view translation table, where + the view translation table contains all result columns of the + view. This definition ensures that view columns are resolved + in the same manner as table columns. RETURN TRUE Referenced item is equal to given item @@ -4962,9 +4962,18 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const { - Item *it= ((Item *) item)->real_item(); - return (!it->name || !my_strcasecmp(system_charset_info, it->name, - field_name)) && ref && (*ref)->real_item()->eq(it, binary_cmp); + if (item->type() == REF_ITEM) + { + Item_ref *item_ref= (Item_ref*) item; + if (item_ref->ref_type() == VIEW_REF) + { + Item *item_ref_ref= *(item_ref->ref); + DBUG_ASSERT((*ref)->type() == FIELD_ITEM && + (item_ref_ref->type() == FIELD_ITEM)); + return (*ref == item_ref_ref); + } + } + return FALSE; } void Item_null_helper::print(String *str) From cb38411696dfa0f98bdd1d90a99f34c3d930afd5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 19:06:18 +0300 Subject: [PATCH 40/48] Fixes bug #14569. In addition to check current db of not being NULL value it is added a check of not being empty value. When modifying SP with Admin application on win32 it does not pass curent database so sp is stored with db=null which causes a crash later on show procedure status; --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4bbca55f6ba..03abd98c944 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4099,7 +4099,7 @@ end_with_restore_list: if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0]) { - if (! thd->db) + if (!thd->db || thd->db[0] == 0) { my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); delete lex->sphead; From 1c677f8c559f244b72ff4f6f1c7528889af05f45 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 21:01:48 +0300 Subject: [PATCH 41/48] Fixes bug #14569. When no db is selected as current and we do create procedure db.sp()... we changing current db temporarily and restore it when sp is created. however thd->db in this case becomes empty string rather than NULL and so all checks of thd->db == NULL will be false. So if after this we'll issue create procedure sp2()... without specifying db it will succeed and create sp with db=NULL, which causes mysqldto crash on show procedure status statement. This patch fixes the problem. mysql-test/r/sp-error.result: Result for bug #14569. mysql-test/t/sp-error.test: Test for bug #14569. sql/sql_db.cc: Fixes bug #14569. When no db is selected as current and we do create procedure db.sp()... we changing current db temporarily and restore it when sp is created. however thd->db in this case becomes empty string rather than NULL and so all checks of thd->db == NULL will be false. This patch fixes this issue. sql/sql_parse.cc: Fixes bug #14569. Reverted from initial patch to check thd->db for null values only. --- mysql-test/r/sp-error.result | 13 +++++++++++++ mysql-test/t/sp-error.test | 16 ++++++++++++++++ sql/sql_db.cc | 13 +++++++++++-- sql/sql_parse.cc | 2 +- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 50ff7ea264a..fabbf13a96b 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -916,3 +916,16 @@ ERROR 42S22: Unknown column 'bug13037_foo' in 'field list' DROP PROCEDURE bug13037_p1; DROP PROCEDURE bug13037_p2; DROP PROCEDURE bug13037_p3; +create database mysqltest1; +create database mysqltest2; +use mysqltest1; +drop database mysqltest1; +create procedure mysqltest2.p1() select version(); +create procedure p2() select version(); +ERROR 3D000: No database selected +use mysqltest2; +show procedure status; +Db Name Type Definer Modified Created Security_type Comment +mysqltest2 p1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +drop database mysqltest2; +use test; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index e2343cd905c..3c1efe73c18 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1337,6 +1337,22 @@ DROP PROCEDURE bug13037_p1; DROP PROCEDURE bug13037_p2; DROP PROCEDURE bug13037_p3; +# +# Bug#14569 "editing a stored procedure kills mysqld-nt" +# +create database mysqltest1; +create database mysqltest2; +use mysqltest1; +drop database mysqltest1; +create procedure mysqltest2.p1() select version(); +--error ER_NO_DB_ERROR +create procedure p2() select version(); +use mysqltest2; +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +show procedure status; +drop database mysqltest2; +use test; + # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_db.cc b/sql/sql_db.cc index a5dabc8140c..bde6522a38b 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1163,8 +1163,17 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) } end: x_free(thd->db); - thd->db=dbname; // THD::~THD will free this - thd->db_length=db_length; + if (dbname && dbname[0] == 0) + { + x_free(dbname); + thd->db= NULL; + thd->db_length= 0; + } + else + { + thd->db= dbname; // THD::~THD will free this + thd->db_length= db_length; + } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) sctx->db_access= db_access; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 03abd98c944..b6ff58e1215 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4099,7 +4099,7 @@ end_with_restore_list: if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0]) { - if (!thd->db || thd->db[0] == 0) + if (!thd->db) { my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); delete lex->sphead; From 4e1bc5abd823a9306f89922f69912351832365c1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 22:18:41 +0100 Subject: [PATCH 42/48] Not all RPM builds can use the bundled zlib, due to dependency and link conflicts. Solve this. support-files/mysql.spec.sh: We cannot always use the bundled zlib, as this conflicts with the "shared" build of the "max" binary. The fully static RPM build on "build" also does not work with the bundled zlib. With this change, we use the bundled zlib for "standard" RPMs (unless fully stytic, "build") and the one already installed onm the system for the "max" build which is also labeled "experimental". --- support-files/mysql.spec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 7b2eee5f821..991afd367c0 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -259,7 +259,6 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --includedir=%{_includedir} \ --mandir=%{_mandir} \ --enable-thread-safe-client \ - --with-zlib-dir=bundled \ --with-readline ; \ # Add this for more debugging support # --with-debug @@ -362,8 +361,9 @@ BuildMySQL "--disable-shared \ %if %{STATIC_BUILD} --with-mysqld-ldflags='-all-static' \ --with-client-ldflags='-all-static' \ - --with-zlib-dir=bundled \ $USE_OTHER_LIBC_DIR \ +%else + --with-zlib-dir=bundled \ %endif --with-comment=\"MySQL Community Edition - Standard (GPL)\" \ --with-server-suffix='%{server_suffix}' \ From c2826d723e6581ce18a6e0974b47669b99da1d14 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 01:59:15 +0200 Subject: [PATCH 43/48] mysql-test-run.pl: Corrected search for 'mysqlimport' executable mysql-test/mysql-test-run.pl: Corrected search for 'mysqlimport' executable --- mysql-test/mysql-test-run.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c3025060e37..58308f0ccdd 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -871,7 +871,7 @@ sub executable_setup () { "/usr/bin/false"); } $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); @@ -885,6 +885,7 @@ sub executable_setup () { { $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); From 63bbb1513a73a0a556c8c7873cd6c9f5d610d652 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 04:07:24 +0200 Subject: [PATCH 44/48] config-win.h: Disabled yaSSL support for now include/config-win.h: Disabled yaSSL support for now --- include/config-win.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index fe099c11a2f..5c2f8e00e86 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -392,8 +392,8 @@ inline double ulonglong2double(ulonglong value) #define HAVE_SPATIAL 1 #define HAVE_RTREE_KEYS 1 -#define HAVE_OPENSSL 1 -#define HAVE_YASSL 1 +/* #undef HAVE_OPENSSL */ +/* #undef HAVE_YASSL */ /* Define charsets you want */ /* #undef HAVE_CHARSET_armscii8 */ From 67df0e19e4cd17b7238d8ac2d4944324f889f1ba Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 15:19:52 +0300 Subject: [PATCH 45/48] Fixed number of compiler errors on win32. VC++Files/mysqlbinlog/mysqlbinlog.vcproj: Fixed compiler error for Win32 build. #include "decimal.c" wrere no able to find decimal.c file. sql/ha_innodb.cc: Fixed compiler error for Win32 build. sql/spatial.cc: Fixed compiler error for Win32 build. float8get should be enclosed in {} since it is macro on win32 and might cause unmatching blocks. --- VC++Files/mysqlbinlog/mysqlbinlog.vcproj | 2 +- sql/ha_innodb.cc | 4 ++-- sql/spatial.cc | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/VC++Files/mysqlbinlog/mysqlbinlog.vcproj b/VC++Files/mysqlbinlog/mysqlbinlog.vcproj index 9d5d4db2565..bfe70d6d1af 100644 --- a/VC++Files/mysqlbinlog/mysqlbinlog.vcproj +++ b/VC++Files/mysqlbinlog/mysqlbinlog.vcproj @@ -22,7 +22,7 @@ Name="VCCLCompilerTool" Optimization="0" OptimizeForProcessor="2" - AdditionalIncludeDirectories="../include,../,../sql" + AdditionalIncludeDirectories="../include,../,../sql,../strings" PreprocessorDefinitions="_DEBUG;SAFEMALLOC;SAFE_MUTEX;_CONSOLE;_WINDOWS;MYSQL_SERVER" RuntimeLibrary="1" PrecompiledHeaderFile=".\Debug/mysqlbinlog.pch" diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 61af1afb2be..556186d5584 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3009,8 +3009,8 @@ ha_innobase::store_key_val_for_row( if (key_part->length > 0 && cs->mbmaxlen > 1) { len = (ulint) cs->cset->well_formed_len(cs, - src_start, - src_start + key_part->length, + (const char *) src_start, + (const char *) src_start + key_part->length, key_part->length / cs->mbmaxlen, &error); } else { diff --git a/sql/spatial.cc b/sql/spatial.cc index 5af1bec45ca..ca9615236e0 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -178,7 +178,9 @@ static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo) { double res; if (bo != Geometry::wkb_xdr) + { float8get(res, ptr); + } else { char inv_array[8]; From 303cae4cd86db752a25836bb743796dd7d71dcf2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 16:01:10 +0300 Subject: [PATCH 46/48] Fixes bug #13377. my_open() & my_create() functions changed to use my_sopen() on win32 which allows to use FILE_SHARE_DELETE flag to allow deleting opened files. my_sopen() implementation is added to support this functionality. include/my_global.h: Fixes bug #13377. Added number of constants for share delete file open option. include/my_sys.h: Fixes bug #13377. Added my_sopen function. mysys/my_create.c: Fixes bug #13377. my_create() function changed to use my_sopen() and which allows to use FILE_SHARE_DELETE flag on win32, which helps in deleting opened files. mysys/my_open.c: Fixes bug #13377. my_open() function changed to use my_sopen() on win32 which allows to use FILE_SHARE_DELETE flag to allow deleting opened files. sql/log.cc: Fixes bug #13377. Additional patch - remove reference counting for opened binlog files, introduced in initial patch of #13377. sql/sql_class.h: Fixes bug #13377. Additional patch - remove reference counting for opened binlog files, introduced in initial patch of #13377. sql/sql_repl.cc: Fixes bug #13377. Additional patch - remove reference counting for opened binlog files, introduced in initial patch of #13377. --- include/my_global.h | 9 +++ include/my_sys.h | 1 + mysys/my_create.c | 5 +- mysys/my_open.c | 184 ++++++++++++++++++++++++++++++++++++++++++++ sql/log.cc | 62 +-------------- sql/sql_class.h | 6 +- sql/sql_repl.cc | 39 ++-------- 7 files changed, 207 insertions(+), 99 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index b32a8fe6baa..33cdfa2d03c 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -553,6 +553,15 @@ typedef SOCKET_SIZE_TYPE size_socket; #define O_NOFOLLOW 0 #endif +/* additional file share flags for win32 */ +#ifdef __WIN__ +#define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ +#define _SH_DENYWRD 0x120 /* deny write mode & delete */ +#define _SH_DENYRDD 0x130 /* deny read mode & delete */ +#define _SH_DENYDEL 0x140 /* deny delete only */ +#endif /* __WIN__ */ + + /* #define USE_RECORD_LOCK */ /* Unsigned types supported by the compiler */ diff --git a/include/my_sys.h b/include/my_sys.h index 76031806b82..44fe383bf4f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -601,6 +601,7 @@ extern char *_my_strdup_with_length(const byte *from, uint length, #ifdef __WIN__ extern int my_access(const char *path, int amode); +extern File my_sopen(const char *path, int oflag, int shflag, int pmode); #else #define my_access access #endif diff --git a/mysys/my_create.c b/mysys/my_create.c index 5fa97a9ca78..a85417c7701 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -47,13 +47,16 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, #elif defined(VMS) fd = open((my_string) FileName, access_flags | O_CREAT, 0, "ctx=stm","ctx=bin"); -#elif defined(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2) +#elif defined(MSDOS) || defined(__EMX__) || defined(OS2) if (access_flags & O_SHARE) fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY, SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); else fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY, MY_S_IREAD | MY_S_IWRITE); +#elif defined(__WIN__) + fd= my_sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY, + SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); #else fd = open(FileName, access_flags); #endif diff --git a/mysys/my_open.c b/mysys/my_open.c index 69d63c49554..baca97450b7 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -56,12 +56,18 @@ File my_open(const char *FileName, int Flags, myf MyFlags) DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN, EE_FILENOTFOUND, MyFlags)); } +#ifndef __WIN__ if (Flags & O_SHARE) fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); else fd = open((my_string) FileName, Flags | O_BINARY, MY_S_IREAD | MY_S_IWRITE); +#else + fd= my_sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, + MY_S_IREAD | MY_S_IWRITE); +#endif + #elif !defined(NO_OPEN_3) fd = open(FileName, Flags, my_umask); /* Normal unix */ #else @@ -167,3 +173,181 @@ File my_register_filename(File fd, const char *FileName, enum file_type FileName, my_errno); return(fd); } + +#ifdef __WIN__ + +extern void __cdecl _dosmaperr(unsigned long); + +/* + Open a file with sharing. Similar to _sopen() from libc, but allows managing + share delete on win32 + + SYNOPSIS + my_sopen() + path fully qualified file name + oflag operation flags + shflag share flag + pmode permission flags + + RETURN VALUE + File descriptor of opened file if success + -1 and sets errno if fails. +*/ + +File my_sopen(const char *path, int oflag, int shflag, int pmode) +{ + int fh; /* handle of opened file */ + int mask; + HANDLE osfh; /* OS handle of opened file */ + DWORD fileaccess; /* OS file access (requested) */ + DWORD fileshare; /* OS file sharing mode */ + DWORD filecreate; /* OS method of opening/creating */ + DWORD fileattrib; /* OS file attribute flags */ + SECURITY_ATTRIBUTES SecurityAttributes; + + SecurityAttributes.nLength= sizeof(SecurityAttributes); + SecurityAttributes.lpSecurityDescriptor= NULL; + SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT); + + /* + * decode the access flags + */ + switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: /* read access */ + fileaccess= GENERIC_READ; + break; + case _O_WRONLY: /* write access */ + fileaccess= GENERIC_WRITE; + break; + case _O_RDWR: /* read and write access */ + fileaccess= GENERIC_READ | GENERIC_WRITE; + break; + default: /* error, bad oflag */ + errno= EINVAL; + _doserrno= 0L; /* not an OS error */ + return -1; + } + + /* + * decode sharing flags + */ + switch (shflag) { + case _SH_DENYRW: /* exclusive access except delete */ + fileshare= FILE_SHARE_DELETE; + break; + case _SH_DENYWR: /* share read and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE; + break; + case _SH_DENYRD: /* share write and delete access */ + fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYNO: /* share read, write and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYRWD: /* exclusive access */ + fileshare= 0L; + break; + case _SH_DENYWRD: /* share read access */ + fileshare= FILE_SHARE_READ; + break; + case _SH_DENYRDD: /* share write access */ + fileshare= FILE_SHARE_WRITE; + break; + case _SH_DENYDEL: /* share read and write access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + default: /* error, bad shflag */ + errno= EINVAL; + _doserrno= 0L; /* not an OS error */ + return -1; + } + + /* + * decode open/create method flags + */ + switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: // ignore EXCL w/o CREAT + filecreate= OPEN_EXISTING; + break; + + case _O_CREAT: + filecreate= OPEN_ALWAYS; + break; + + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + filecreate= CREATE_NEW; + break; + + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT + filecreate= TRUNCATE_EXISTING; + break; + + case _O_CREAT | _O_TRUNC: + filecreate= CREATE_ALWAYS; + break; + + default: + // this can't happen ... all cases are covered + errno= EINVAL; + _doserrno= 0L; + return -1; + } + + /* + * decode file attribute flags if _O_CREAT was specified + */ + fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */ + if (oflag & _O_CREAT) + { + _umask((mask= _umask(0))); + + if (!((pmode & ~mask) & _S_IWRITE)) + fileattrib= FILE_ATTRIBUTE_READONLY; + } + + /* + * Set temporary file (delete-on-close) attribute if requested. + */ + if (oflag & _O_TEMPORARY) + { + fileattrib|= FILE_FLAG_DELETE_ON_CLOSE; + fileaccess|= DELETE; + } + + /* + * Set temporary file (delay-flush-to-disk) attribute if requested. + */ + if (oflag & _O_SHORT_LIVED) + fileattrib|= FILE_ATTRIBUTE_TEMPORARY; + + /* + * Set sequential or random access attribute if requested. + */ + if (oflag & _O_SEQUENTIAL) + fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN; + else if (oflag & _O_RANDOM) + fileattrib|= FILE_FLAG_RANDOM_ACCESS; + + /* + * try to open/create the file + */ + if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes, + filecreate, fileattrib, NULL)) == (HANDLE)0xffffffff) + { + /* + * OS call to open/create file failed! map the error, release + * the lock, and return -1. note that it's not necessary to + * call _free_osfhnd (it hasn't been used yet). + */ + _dosmaperr(GetLastError()); /* map error */ + return -1; /* return error to caller */ + } + + fh= _open_osfhandle((long)osfh, oflag & (_O_APPEND | _O_RDONLY | _O_TEXT)); + + return fh; /* return handle */ +} +#endif /* __WIN__ */ diff --git a/sql/log.cc b/sql/log.cc index 4b3d6698051..e42f1def27c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -357,8 +357,7 @@ static int find_uniq_filename(char *name) MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), prepared_xids(0), log_type(LOG_CLOSED), file_id(1), open_count(1), - readers_count(0), reset_pending(FALSE), write_error(FALSE), inited(FALSE), - need_start_event(TRUE), + write_error(FALSE), inited(FALSE), need_start_event(TRUE), description_event_for_exec(0), description_event_for_queue(0) { /* @@ -385,9 +384,7 @@ void MYSQL_LOG::cleanup() delete description_event_for_exec; (void) pthread_mutex_destroy(&LOCK_log); (void) pthread_mutex_destroy(&LOCK_index); - (void) pthread_mutex_destroy(&LOCK_readers); (void) pthread_cond_destroy(&update_cond); - (void) pthread_cond_destroy(&reset_cond); } DBUG_VOID_RETURN; } @@ -432,9 +429,7 @@ void MYSQL_LOG::init_pthread_objects() inited= 1; (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_readers, MY_MUTEX_INIT_SLOW); (void) pthread_cond_init(&update_cond, 0); - (void) pthread_cond_init(&reset_cond, 0); } const char *MYSQL_LOG::generate_name(const char *log_name, @@ -938,12 +933,6 @@ bool MYSQL_LOG::reset_logs(THD* thd) pthread_mutex_lock(&LOCK_log); pthread_mutex_lock(&LOCK_index); - /* - we need one more lock to block attempts to open a log while - we are waiting untill all log files will be closed - */ - pthread_mutex_lock(&LOCK_readers); - /* The following mutex is needed to ensure that no threads call 'delete thd' as we would then risk missing a 'rollback' from this @@ -966,19 +955,6 @@ bool MYSQL_LOG::reset_logs(THD* thd) goto err; } - reset_pending= TRUE; - /* - send update signal just in case so that all reader threads waiting - for log update will leave wait condition - */ - signal_update(); - /* - if there are active readers wait until all of them will - release opened files - */ - while (readers_count) - pthread_cond_wait(&reset_cond, &LOCK_log); - for (;;) { my_delete(linfo.log_file_name, MYF(MY_WME)); @@ -997,10 +973,7 @@ bool MYSQL_LOG::reset_logs(THD* thd) my_free((gptr) save_name, MYF(0)); err: - reset_pending= FALSE; - (void) pthread_mutex_unlock(&LOCK_thread_count); - pthread_mutex_unlock(&LOCK_readers); pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); @@ -2073,12 +2046,6 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) { const char *old_msg; DBUG_ENTER("wait_for_update"); - - if (reset_pending) - { - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; - } old_msg= thd->enter_cond(&update_cond, &LOCK_log, is_slave ? @@ -2330,33 +2297,6 @@ void MYSQL_LOG::signal_update() DBUG_VOID_RETURN; } -void MYSQL_LOG::readers_addref() -{ - /* - There is no necessity for reference counting on *nix, since it allows to - delete opened files, however it is more clean way to wait - untill all files will be closed on *nix as well. - */ - DBUG_ENTER("MYSQL_LOG::reader_addref"); - pthread_mutex_lock(&LOCK_log); - pthread_mutex_lock(&LOCK_readers); - readers_count++; - pthread_mutex_unlock(&LOCK_readers); - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; -} - -void MYSQL_LOG::readers_release() -{ - DBUG_ENTER("MYSQL_LOG::reader_release"); - pthread_mutex_lock(&LOCK_log); - readers_count--; - if (!readers_count) - pthread_cond_broadcast(&reset_cond); - pthread_mutex_unlock(&LOCK_log); - DBUG_VOID_RETURN; -} - #ifdef __NT__ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, uint length, int buffLen) diff --git a/sql/sql_class.h b/sql/sql_class.h index 2d1880a6d9d..eaa8291e697 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -189,11 +189,10 @@ class MYSQL_LOG: public TC_LOG { private: /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ - pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers; + pthread_mutex_t LOCK_log, LOCK_index; pthread_mutex_t LOCK_prep_xids; pthread_cond_t COND_prep_xids; pthread_cond_t update_cond; - pthread_cond_t reset_cond; ulonglong bytes_written; time_t last_time,query_start; IO_CACHE log_file; @@ -335,9 +334,6 @@ public: int purge_logs_before_date(time_t purge_time); int purge_first_log(struct st_relay_log_info* rli, bool included); bool reset_logs(THD* thd); - inline bool is_reset_pending() { return reset_pending; } - void readers_addref(); - void readers_release(); void close(uint exiting); // iterating through the log index file diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index b5865fa8816..cd293fc21c7 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -372,11 +372,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } - /* - Call readers_addref before opening log to track count - of binlog readers - */ - mysql_bin_log.readers_addref(); if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -574,8 +569,7 @@ impossible position"; goto err; if (!(flags & BINLOG_DUMP_NON_BLOCK) && - mysql_bin_log.is_active(log_file_name) && - !mysql_bin_log.is_reset_pending()) + mysql_bin_log.is_active(log_file_name)) { /* Block until there is more data in the log @@ -688,13 +682,7 @@ impossible position"; else { bool loop_breaker = 0; - // need this to break out of the for loop from switch - - // if we are going to switch log file anyway, close current log first - end_io_cache(&log); - (void) my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); + /* need this to break out of the for loop from switch */ thd->proc_info = "Finished reading one binlog; switching to next binlog"; switch (mysql_bin_log.find_next_log(&linfo, 1)) { @@ -704,25 +692,16 @@ impossible position"; case 0: break; default: - // need following call to do release on err label - mysql_bin_log.readers_addref(); errmsg = "could not find next log"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - if (loop_breaker) - { - // need following call to do release on end label - mysql_bin_log.readers_addref(); - break; - } - - /* - Call readers_addref before opening log to track count - of binlog readers - */ - mysql_bin_log.readers_addref(); + if (loop_breaker) + break; + + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); /* Call fake_rotate_event() in case the previous log (the one which @@ -755,8 +734,6 @@ end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); send_eof(thd); thd->proc_info = "Waiting to finalize termination"; @@ -783,8 +760,6 @@ err: pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); - // decrease reference count of binlog readers - mysql_bin_log.readers_release(); my_message(my_errno, errmsg, MYF(0)); DBUG_VOID_RETURN; From 1f7fb05c4c3c105e0494012e756811b9db23bb44 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 16:36:05 +0300 Subject: [PATCH 47/48] Added number of files into ignore list for win32 build within bk tree. --- .bzrignore | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/.bzrignore b/.bzrignore index 388dcac2ca6..25dece78561 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1127,3 +1127,144 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +*.bin +*.exe +*.idb +*.lib +*.map +*.obj +*.pch +*.pdb +*.res +*.sbr +./copy_mysql_files.bat +./fix-project-files +./mysql*.ds? +./mysql.ncb +./mysql.sln +./mysql.suo +./prepare +./README.build-files +bdb/*.ds? +bdb/*.vcproj +client/*.ds? +client/*.vcproj +client/completion_hash.cpp +client/mysql.cpp +client/mysqladmin.cpp +client/mysqlbinlog.cpp +client/readline.cpp +client/sql_string.cpp +client_debug/* +client_release/* +comp_err/*.ds? +comp_err/*.vcproj +contrib/*.ds? +contrib/*.vcproj +dbug/*.ds? +dbug/*.vcproj +examples/*.ds? +examples/*.vcproj +examples/udf_example/udf_example.def +heap/*.ds? +heap/*.vcproj +innobase/*.ds? +innobase/*.vcproj +isam/*.ds? +isam/*.vcproj +isamchk/*.ds? +isamchk/*.vcproj +lib_debug/* +lib_release/* +libmysql/*.ds? +libmysql/*.vcproj +libmysql/debug/libmysql.exp +libmysql/release/libmysql.exp +libmysqld/*.ds? +libmysqld/*.vcproj +libmysqld/emb_qcache.cpp +libmysqld/lib_sql.cpp +libmysqld/sql_yacc.cpp +libmysqld/sql_yacc.h +libmysqltest/*.ds? +libmysqltest/*.vcproj +libmysqltest/mytest.c +merge/*.ds? +merge/*.vcproj +my_print_defaults/*.ds? +my_print_defaults/*.vcproj +myisam/*.ds? +myisam/*.vcproj +myisam_ftdump/*.ds? +myisam_ftdump/*.vcproj +myisamchk/*.ds? +myisamchk/*.vcproj +myisamlog/*.ds? +myisamlog/*.vcproj +myisammrg/*.ds? +myisammrg/*.vcproj +myisampack/*.ds? +myisampack/*.vcproj +mysql-test/*.ds? +mysql-test/*.vcproj +mysql-test/r/*.err +mysql-test/r/*.out +mysqlbinlog/*.ds? +mysqlbinlog/*.vcproj +mysqlcheck/*.ds? +mysqlcheck/*.vcproj +mysqldemb/*.ds? +mysqldemb/*.vcproj +mysqlserver/*.ds? +mysqlserver/*.vcproj +mysys/*.ds? +mysys/*.vcproj +mysys/my_new.cpp +mysys/raid.cpp +pack_isam/*.ds? +perror/*.ds? +perror/*.vcproj +regex/*.ds? +regex/*.vcproj +replace/*.ds? +replace/*.vcproj +server-tools/instance-manager/buffer.cpp +server-tools/instance-manager/command.cpp +server-tools/instance-manager/commands.cpp +server-tools/instance-manager/guardian.cpp +server-tools/instance-manager/instance.cpp +server-tools/instance-manager/instance_map.cpp +server-tools/instance-manager/instance_options.cpp +server-tools/instance-manager/listener.cpp +server-tools/instance-manager/log.cpp +server-tools/instance-manager/manager.cpp +server-tools/instance-manager/messages.cpp +server-tools/instance-manager/mysql_connection.cpp +server-tools/instance-manager/mysqlmanager.cpp +server-tools/instance-manager/options.cpp +server-tools/instance-manager/parse.cpp +server-tools/instance-manager/parse_output.cpp +server-tools/instance-manager/priv.cpp +server-tools/instance-manager/protocol.cpp +server-tools/instance-manager/thread_registry.cpp +server-tools/instance-manager/user_map.cpp +sql/*.cpp +sql/*.ds? +sql/*.vcproj +sql/max/* +sql/message.h +sql/message.mc +sql/message.rc +strings/*.ds? +strings/*.vcproj +test1/* +tests/*.ds? +tests/*.vcproj +thr_insert_test/* +thr_test/* +vio/*.ds? +vio/*.vcproj +vio/viotest-sslconnect.cpp +vio/viotest.cpp +zlib/*.ds? +zlib/*.vcproj From bfef85a188194e865a534a2dc6e095414e14e2d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 16:39:46 +0300 Subject: [PATCH 48/48] Added workaround for rpl_frop_db test to run on win32 properly. --- mysql-test/t/rpl_drop_db.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test index 61354198c83..98afc6e3d02 100644 --- a/mysql-test/t/rpl_drop_db.test +++ b/mysql-test/t/rpl_drop_db.test @@ -13,6 +13,7 @@ insert into mysqltest1.t1 values (1); select * from mysqltest1.t1 into outfile 'mysqltest1/f1.txt'; create table mysqltest1.t2 (n int); create table mysqltest1.t3 (n int); +--replace_result \\ / --error 1010 drop database mysqltest1; use mysqltest1; @@ -29,6 +30,7 @@ while ($1) } --enable_query_log +--replace_result \\ / --error 1010 drop database mysqltest1; use mysqltest1;