From e03e5222013a0bbfc17adb37f5201b9f0dbc5327 Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Wed, 1 Mar 2006 14:13:07 +0300 Subject: [PATCH 01/12] Fix for BUG#16266: Definer is not fully qualified error during replication. The idea of the fix is to extend support of non-SUID triggers for backward compatibility. Formerly non-SUID triggers were appeared when "new" server is being started against "old" database. Now, they are also created when "new" slave receives updates from "old" master. --- mysql-test/r/rpl_trigger.result | 41 +++++++++++ mysql-test/std_data/bug16266.000001 | Bin 0 -> 532 bytes mysql-test/t/rpl_trigger.test | 74 +++++++++++++++++++ sql/mysql_priv.h | 1 + sql/sql_parse.cc | 30 +++++++- sql/sql_trigger.cc | 108 +++++++++++++++++++++------- sql/sql_view.cc | 20 ++++++ sql/sql_yacc.yy | 42 ++++------- 8 files changed, 264 insertions(+), 52 deletions(-) create mode 100644 mysql-test/std_data/bug16266.000001 diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index ccd880c1e07..185862097bc 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -855,3 +855,44 @@ f3 drop trigger trg11; drop table t21,t31; drop table t11; +STOP SLAVE; +FLUSH LOGS; +RESET SLAVE; +START SLAVE; +SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; +MASTER_POS_WAIT('master-bin.000001', 513) >= 0 +1 +SHOW TABLES; +Tables_in_test +t1 +t2 +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 INSERT INTO t2 VALUES(CURRENT_USER()) AFTER NULL +SELECT * FROM t1; +c +1 +SELECT * FROM t2; +s +@ +INSERT INTO t1 VALUES(2); +SELECT * FROM t1; +c +1 +2 +SELECT * FROM t2; +s +@ +root@localhost +DROP TRIGGER trg1; +Warnings: +Warning 1454 No definer attribute for trigger 'test'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. +DROP TABLE t1; +DROP TABLE t2; +STOP SLAVE; +RESET SLAVE; +SHOW TABLES; +Tables_in_test +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +RESET MASTER; diff --git a/mysql-test/std_data/bug16266.000001 b/mysql-test/std_data/bug16266.000001 new file mode 100644 index 0000000000000000000000000000000000000000..1b24d231511ff1505b232ef852b6473852afd480 GIT binary patch literal 532 zcmeyDl$p2U!XIaTMg|6kI3P{}Vg?2l22(u)Jwr3yl+>isblsf%bg(d90%VM^1up{! zgAfA?5C}0acr&m_Z3PN5flLnt;_YA)Ks*p&VPKE~QVt9ZFcAhe=HikR77m~x91JC? z#U%{RL9UJ=t_mTJPCl**C59Tw3Z8x;ng?NqMg#Q=fpx=-Al*3hK?)^B>4pl9ZXrOXr(dvZP>6!RAJ7{LZvH_Eu8z(g3PJwi zFd3l7{1r-!6v7;RLS2J3oI`_xT>V1gLxI{fG&Nts+!YRV7b6ppfQK3}UWVEZvBMB% UhoPp&#Xru>AYTdtu?W~$0PX--`v3p{ literal 0 HcmV?d00001 diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index f3db1cb5841..90822e0654c 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -162,6 +162,7 @@ use test; drop table t1,t2; drop database other; + # # Test specific triggers including SELECT into var with replication # BUG#13227: @@ -257,6 +258,79 @@ while ($rnd) } +# +# BUG#16266: Definer is not fully qualified error during replication. +# +# The idea of this test is to emulate replication of a trigger from the old +# master (master w/o "DEFINER in triggers" support) to the new slave and check +# that: +# 1. the trigger on the slave will be replicated w/o errors; +# 2. the trigger on the slave will be non-SUID (will have no DEFINER); +# 3. the trigger can be activated later on the slave w/o errors. +# +# In order to emulate this kind of replication, we make the slave playing the binlog, +# recorded by 5.0.16 master. This binlog contains the following statements: +# CREATE TABLE t1(c INT); +# CREATE TABLE t2(s CHAR(200)); +# CREATE TRIGGER trg1 AFTER INSERT ON t1 +# FOR EACH ROW +# INSERT INTO t2 VALUES(CURRENT_USER()); +# INSERT INTO t1 VALUES(1); +# + +# 1. Check that the trigger's replication is succeeded. + +# Stop the slave. + +connection slave; +STOP SLAVE; + +# Replace master's binlog. + +connection master; +FLUSH LOGS; +exec cp $MYSQL_TEST_DIR/std_data/bug16266.000001 $MYSQLTEST_VARDIR/log/master-bin.000001; + +# Make the slave to replay the new binlog. + +connection slave; +RESET SLAVE; +START SLAVE; + +SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; + +# Check that the replication succeeded. + +SHOW TABLES; +SHOW TRIGGERS; +SELECT * FROM t1; +SELECT * FROM t2; + +# 2. Check that the trigger is non-SUID on the slave; +# 3. Check that the trigger can be activated on the slave. + +INSERT INTO t1 VALUES(2); + +SELECT * FROM t1; +SELECT * FROM t2; + +# That's all, cleanup. + +DROP TRIGGER trg1; +DROP TABLE t1; +DROP TABLE t2; + +STOP SLAVE; +RESET SLAVE; + +# The master should be clean. + +connection master; +SHOW TABLES; +SHOW TRIGGERS; + +RESET MASTER; + # # End of tests diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c817ae54c2..9559b0be76a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -531,6 +531,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); bool get_default_definer(THD *thd, LEX_USER *definer); +LEX_USER *create_default_definer(THD *thd); LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); enum enum_mysql_completiontype { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b2066953cf5..0494ccf985f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7206,6 +7206,34 @@ bool get_default_definer(THD *thd, LEX_USER *definer) } +/* + Create default definer for the specified THD. Also check that the current + user is conformed to the definers requirements. + + SYNOPSIS + create_default_definer() + thd [in] thread handler + + RETURN + On success, return a valid pointer to the created and initialized + LEX_USER, which contains definer information. + On error, return 0. +*/ + +LEX_USER *create_default_definer(THD *thd) +{ + LEX_USER *definer; + + if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + return 0; + + if (get_default_definer(thd, definer)) + return 0; + + return definer; +} + + /* Create definer with the given user and host names. Also check that the user and host names satisfy definers requirements. @@ -7218,7 +7246,7 @@ bool get_default_definer(THD *thd, LEX_USER *definer) RETURN On success, return a valid pointer to the created and initialized - LEX_STRING, which contains definer information. + LEX_USER, which contains definer information. On error, return 0. */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 4c3ae5c032d..9ccc70d8ccd 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -264,7 +264,17 @@ end: log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */ log_query.append(STRING_WITH_LEN("CREATE ")); - append_definer(thd, &log_query, &definer_user, &definer_host); + + if (definer_user.str && definer_host.str) + { + /* + Append definer-clause if the trigger is SUID (a usual trigger in + new MySQL versions). + */ + + append_definer(thd, &log_query, &definer_user, &definer_host); + } + log_query.append(thd->lex->trigger_definition_begin); } @@ -289,17 +299,30 @@ end: 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 + definer_user - [out] after a call it points to 0-terminated string or + contains the NULL-string: + - 0-terminated is returned if the trigger is SUID. The + string contains user name part of the actual trigger + definer. + - NULL-string is returned if the trigger is non-SUID. + Anyway, 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 + definer_host - [out] after a call it points to 0-terminated string or + contains the NULL-string: + - 0-terminated string is returned if the trigger is + SUID. The string contains host name part of the + actual trigger definer. + - NULL-string is returned if the trigger is non-SUID. + Anyway, the caller is responsible to provide memory for storing LEX_STRING object. NOTE - Assumes that trigger name is fully qualified. + - Assumes that trigger name is fully qualified. + - NULL-string means the following LEX_STRING instance: + { str = 0; length = 0 }. + - In other words, definer_user and definer_host should contain + simultaneously NULL-strings (non-SUID/old trigger) or valid strings + (SUID/new trigger). RETURN VALUE False - success @@ -336,12 +359,30 @@ 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. - */ + if (!lex->definer) + { + /* + DEFINER-clause is missing. - DBUG_ASSERT(lex->definer); + If we are in slave thread, this means that we received CREATE TRIGGER + from the master, that does not support definer in triggers. So, we + should mark this trigger as non-SUID. Note that this does not happen + when we parse triggers' definitions during opening .TRG file. + LEX::definer is ignored in that case. + + Otherwise, we should use CURRENT_USER() as definer. + + NOTE: when CREATE TRIGGER statement is allowed to be executed in PS/SP, + it will be required to create the definer below in persistent MEM_ROOT + of PS/SP. + */ + + if (!thd->slave_thread) + { + if (!(lex->definer= create_default_definer(thd))) + return 1; + } + } /* If the specified definer differs from the current user, we should check @@ -349,10 +390,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, 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 (lex->definer && + (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)) { @@ -446,8 +488,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, *trg_sql_mode= thd->variables.sql_mode; #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!is_acl_user(lex->definer->host.str, - lex->definer->user.str)) + if (lex->definer && !is_acl_user(lex->definer->host.str, + lex->definer->user.str)) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, @@ -458,12 +500,30 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - *definer_user= lex->definer->user; - *definer_host= lex->definer->host; + if (lex->definer) + { + /* SUID trigger. */ - trg_definer->str= trg_definer_holder; - trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@", - definer_host->str, NullS) - trg_definer->str; + *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; + } + else + { + /* non-SUID trigger. */ + + definer_user->str= 0; + definer_user->length= 0; + + definer_host->str= 0; + definer_host->length= 0; + + trg_definer->str= (char*) ""; + trg_definer->length= 0; + } if (!sql_create_definition_file(&dir, &file, &triggers_file_type, (gptr)this, triggers_file_parameters, 0)) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 4f62a80cfd4..2178b5d00a8 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -208,6 +208,26 @@ bool mysql_create_view(THD *thd, if (mode != VIEW_CREATE_NEW) sp_cache_invalidate(); + if (!lex->definer) + { + /* + DEFINER-clause is missing; we have to create default definer in + persistent arena to be PS/SP friendly. + */ + + Query_arena original_arena; + Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); + + if (!(lex->definer= create_default_definer(thd))) + res= TRUE; + + if (ps_arena) + thd->restore_active_arena(ps_arena, &original_arena); + + if (res) + goto err; + } + #ifndef NO_EMBEDDED_ACCESS_CHECKS /* check definer of view: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d6d2939bed3..7e93b9c8e73 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -778,7 +778,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 get_definer +%type user grant_user %type opt_collate @@ -8960,41 +8960,29 @@ subselect_end: }; definer: - get_definer + /* empty */ { - THD *thd= YYTHD; - - if (! (thd->lex->definer= create_definer(thd, &$1->user, &$1->host))) - YYABORT; + /* + We have to distinguish missing DEFINER-clause from case when + CURRENT_USER specified as definer explicitly in order to properly + handle CREATE TRIGGER statements which come to replication thread + from older master servers (i.e. to create non-suid trigger in this + case). + */ + YYTHD->lex->definer= 0; } - ; - -get_definer: - opt_current_definer + | DEFINER_SYM EQ CURRENT_USER optional_braces { - THD *thd= YYTHD; - - if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) - YYABORT; - - if (get_default_definer(thd, $$)) - YYABORT; + if (! (YYTHD->lex->definer= create_default_definer(YYTHD))) + YYABORT; } | DEFINER_SYM EQ ident_or_text '@' ident_or_text { - if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user)))) - YYABORT; - - $$->user= $3; - $$->host= $5; + if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5))) + YYABORT; } ; -opt_current_definer: - /* empty */ - | DEFINER_SYM EQ CURRENT_USER optional_braces - ; - /************************************************************************** CREATE VIEW statement options. From 302239f388d0bf28ccbb3a234463f7fdd25da717 Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 2 Mar 2006 14:17:13 +0300 Subject: [PATCH 02/12] Fix for BUG#16777: Can not create trigger nor view w/o definer if --skip-grant-tables specified. The problem is that there is a check that prevents creating a definer with empty host name. In --skip-grant-tables mode this check prevents the user from creating a trigger/view without explicitly specifying its definer. This happens, because in --skip-grant-tables mode CURRENT_USER is ''@''. According to Sanja this check was implemented intentionally. However, according to the MySQL manual it is possible to specify empty host name (as well as empty user name). Moreover, the behaviour for stored routines is different in this aspect -- we allow them to be created with implicit definer. Based on this, we believe it is OK to change the behaviour for views to be similar with the behaviour for stored routines. --- mysql-test/r/skip_grants.result | 21 ++++++++++--- mysql-test/t/skip_grants.test | 53 ++++++++++++++++++++++++++++----- sql/mysql_priv.h | 2 +- sql/sql_parse.cc | 28 +++-------------- sql/sql_view.cc | 3 +- 5 files changed, 68 insertions(+), 39 deletions(-) diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index 5dc770a7363..d8548d84886 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -2,13 +2,26 @@ drop table if exists t1,v1; drop view if exists t1,v1; drop procedure if exists f1; use test; -create table t1 (field1 INT); -CREATE VIEW v1 AS SELECT field1 FROM t1; -ERROR HY000: Definer is not fully qualified -drop table t1; create procedure f1() select 1; drop procedure f1; create table t1 (a int); create definer='user'@'host' sql security definer view v1 as select * from t1; drop view v1; drop table t1; +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(c INT); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 +FOR EACH ROW +SET @a = 1; +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1 +FOR EACH ROW +SET @b = 1; +CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1; +DROP TRIGGER t1_bi; +DROP TRIGGER ti_ai; +DROP VIEW v1; +DROP VIEW v2; +DROP TABLE t1; diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index a0164cb0759..ddf2a7e3fd1 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -8,14 +8,6 @@ drop procedure if exists f1; --enable_warnings use test; -# -# test that we can create VIEW if privileges check switched off -# -create table t1 (field1 INT); --- error ER_MALFORMED_DEFINER -CREATE VIEW v1 AS SELECT field1 FROM t1; -drop table t1; - # # Test that we can create and drop procedure without warnings # see bug#9993 @@ -30,3 +22,48 @@ create table t1 (a int); create definer='user'@'host' sql security definer view v1 as select * from t1; drop view v1; drop table t1; + +# +# BUG#16777: Can not create trigger nor view w/o definer if --skip-grant-tables +# specified +# +# Also, a test that we can create VIEW if privileges check switched off has +# been moved here. +# + +# Prepare. + +--disable_warnings + +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; + +DROP TABLE IF EXISTS t1; + +--enable_warnings + +# Test case. + +CREATE TABLE t1(c INT); + +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 + FOR EACH ROW + SET @a = 1; + +CREATE VIEW v1 AS SELECT * FROM t1; + +CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1 + FOR EACH ROW + SET @b = 1; + +CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1; + +# Cleanup. + +DROP TRIGGER t1_bi; +DROP TRIGGER ti_ai; + +DROP VIEW v1; +DROP VIEW v2; + +DROP TABLE t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9559b0be76a..a43307edf27 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -530,7 +530,7 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); -bool get_default_definer(THD *thd, LEX_USER *definer); +void get_default_definer(THD *thd, LEX_USER *definer); LEX_USER *create_default_definer(THD *thd); LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0494ccf985f..13d814bdf42 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7168,47 +7168,28 @@ Item *negate_expression(THD *thd, Item *expr) /* 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. + the thread. SYNOPSIS get_default_definer() thd [in] thread handler definer [out] definer - - RETURN - error status, that is: - - FALSE -- on success; - - TRUE -- on error (current user can not be a definer). */ -bool get_default_definer(THD *thd, LEX_USER *definer) +void get_default_definer(THD *thd, LEX_USER *definer) { - /* Check that current user has non-empty host name. */ - const Security_context *sctx= thd->security_ctx; - if (sctx->priv_host[0] == 0) - { - my_error(ER_MALFORMED_DEFINER, MYF(0)); - return TRUE; - } - - /* 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 default definer for the specified THD. Also check that the current - user is conformed to the definers requirements. + Create default definer for the specified THD. SYNOPSIS create_default_definer() @@ -7227,8 +7208,7 @@ LEX_USER *create_default_definer(THD *thd) if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) return 0; - if (get_default_definer(thd, definer)) - return 0; + get_default_definer(thd, definer); return definer; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 2178b5d00a8..4f2a9a07705 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -835,8 +835,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 (get_default_definer(thd, &table->definer)) - goto err; + get_default_definer(thd, &table->definer); } /* From fbb59203995255042356ba0fbd681e5afd7ac607 Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 2 Mar 2006 15:18:49 +0300 Subject: [PATCH 03/12] Implementation of WL#2897: Complete definer support in the stored routines. The idea is to add DEFINER-clause in CREATE PROCEDURE and CREATE FUNCTION statements. Almost all support of definer in stored routines had been already done before this patch. NOTE: this patch changes behaviour of dumping stored routines in mysqldump. Before this patch, mysqldump did not dump DEFINER-clause for stored routines and this was documented behaviour. In order to get full information about stored routines, one should have dumped mysql.proc table. This patch changes this behaviour, so that DEFINER-clause is dumped. Since DEFINER-clause is not supported in CREATE PROCEDURE | FUNCTION statements before this patch, the clause is covered by additional version-specific comments. --- client/mysqldump.c | 48 +++++- mysql-test/r/gis.result | 2 +- mysql-test/r/information_schema.result | 4 +- mysql-test/r/mysqldump.result | 14 +- mysql-test/r/rpl_ddl.result | 4 +- mysql-test/r/rpl_sp.result | 30 ++-- mysql-test/r/rpl_trigger.result | 2 +- mysql-test/r/sp-security.result | 52 +++++++ mysql-test/r/sp.result | 28 ++-- mysql-test/r/sql_mode.result | 8 +- mysql-test/t/sp-security.test | 101 +++++++++++++ sql/sp.cc | 55 ++++++- sql/sp_head.cc | 28 ++-- sql/sp_head.h | 1 + sql/sql_lex.h | 14 +- sql/sql_parse.cc | 84 ++++++++++ sql/sql_trigger.cc | 2 +- sql/sql_yacc.yy | 202 ++++++++++++++----------- 18 files changed, 521 insertions(+), 158 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 161197821d6..e0469e00031 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -80,6 +80,7 @@ static char *add_load_option(char *ptr, const char *object, const char *statement); static ulong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, uint *err_len); +static char *alloc_query_str(ulong size); static char *field_escape(char *to,const char *from,uint length); static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, @@ -1304,19 +1305,64 @@ static uint dump_routines_for_db(char *db) routine_name, row[2], strlen(row[2]))); if (strlen(row[2])) { + char *query_str= NULL; + char *definer_begin; + if (opt_drop) fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;;\n", routine_type[i], routine_name); + + /* + Cover DEFINER-clause in version-specific comments. + + TODO: this is definitely a BAD IDEA to parse SHOW CREATE output. + We should user INFORMATION_SCHEMA instead. The only problem is + that now INFORMATION_SCHEMA does not provide information about + routine parameters. + */ + + definer_begin= strstr(row[2], " DEFINER"); + + if (definer_begin) + { + char *definer_end= strstr(definer_begin, " PROCEDURE"); + + if (!definer_end) + definer_end= strstr(definer_begin, " FUNCTION"); + + if (definer_end) + { + char *query_str_tail; + + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(strlen(row[2]) + 23); + + query_str_tail= strnmov(query_str, row[2], + definer_begin - row[2]); + query_str_tail= strmov(query_str_tail, "*/ /*!50019"); + query_str_tail= strnmov(query_str_tail, definer_begin, + definer_end - definer_begin); + query_str_tail= strxmov(query_str_tail, "*/ /*!50003", + definer_end, NullS); + } + } + /* we need to change sql_mode only for the CREATE PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name */; fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n", row[1] /* sql_mode */); - fprintf(sql_file, "/*!50003 %s */;;\n", row[2]); + fprintf(sql_file, "/*!50003 %s */;;\n", + (query_str != NULL ? query_str : row[2])); fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/" ";;\n"); + + my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); } } /* end of routine printing */ } /* end of list of routines */ diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 049ba784dc9..13e2d56d83e 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -680,7 +680,7 @@ drop procedure if exists fn3; create function fn3 () returns point return GeomFromText("point(1 1)"); show create function fn3; Function sql_mode Create Function -fn3 CREATE FUNCTION `fn3`() RETURNS point +fn3 CREATE DEFINER=`root`@`localhost` FUNCTION `fn3`() RETURNS point return GeomFromText("point(1 1)") select astext(fn3()); astext(fn3()) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index d3576e24a44..1c845c73e4b 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -309,7 +309,7 @@ Function sql_mode Create Function sub1 show create function sub2; Function sql_mode Create Function -sub2 CREATE FUNCTION `sub2`(i int) RETURNS int(11) +sub2 CREATE DEFINER=`mysqltest_1`@`localhost` FUNCTION `sub2`(i int) RETURNS int(11) return i+1 show function status like "sub2"; Db Name Type Definer Modified Created Security_type Comment @@ -317,7 +317,7 @@ test sub2 FUNCTION mysqltest_1@localhost # # DEFINER drop function sub2; show create procedure sel2; Procedure sql_mode Create Procedure -sel2 CREATE PROCEDURE `sel2`() +sel2 CREATE DEFINER=`root`@`localhost` PROCEDURE `sel2`() begin select * from t1; select * from t2; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index d156e711167..e6ac9fbc740 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2210,12 +2210,12 @@ UNLOCK TABLES; DELIMITER ;; /*!50003 DROP FUNCTION IF EXISTS `bug9056_func1` */;; /*!50003 SET SESSION SQL_MODE=""*/;; -/*!50003 CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) +/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) RETURN a+b */;; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; /*!50003 DROP FUNCTION IF EXISTS `bug9056_func2` */;; /*!50003 SET SESSION SQL_MODE=""*/;; -/*!50003 CREATE FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1) +/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1) begin set f1= concat( 'hello', f1 ); return f1; @@ -2223,17 +2223,17 @@ end */;; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; /*!50003 DROP PROCEDURE IF EXISTS `a'b` */;; /*!50003 SET SESSION SQL_MODE="REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI"*/;; -/*!50003 CREATE PROCEDURE "a'b"() +/*!50003 CREATE*/ /*!50019 DEFINER="root"@"localhost"*/ /*!50003 PROCEDURE "a'b"() select 1 */;; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; /*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc1` */;; /*!50003 SET SESSION SQL_MODE=""*/;; -/*!50003 CREATE PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT) +/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT) BEGIN SELECT a+b INTO c; end */;; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;; /*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc2` */;; /*!50003 SET SESSION SQL_MODE=""*/;; -/*!50003 CREATE PROCEDURE `bug9056_proc2`(OUT a INT) +/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 PROCEDURE `bug9056_proc2`(OUT a INT) BEGIN select sum(id) from t1 into a; END */;; @@ -2685,11 +2685,11 @@ return 42 */| select 42 */| show create function f; Function sql_mode Create Function -f CREATE FUNCTION `f`() RETURNS bigint(20) +f CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS bigint(20) return 42 show create procedure p; Procedure sql_mode Create Procedure -p CREATE PROCEDURE `p`() +p CREATE DEFINER=`root`@`localhost` PROCEDURE `p`() select 42 drop function f; drop procedure p; diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result index c56c9f20cf8..92e91b31459 100644 --- a/mysql-test/r/rpl_ddl.result +++ b/mysql-test/r/rpl_ddl.result @@ -1133,7 +1133,7 @@ SHOW PROCEDURE STATUS LIKE 'p1'; Db mysqltest1 Name p1 Type PROCEDURE -Definer @ +Definer root@localhost Modified # Created # Security_type DEFINER @@ -1199,7 +1199,7 @@ SHOW PROCEDURE STATUS LIKE 'p1'; Db mysqltest1 Name p1 Type PROCEDURE -Definer @ +Definer root@localhost Modified # Created # Security_type DEFINER diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index a42c33ce333..5dfda16c763 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -31,7 +31,7 @@ declare b int; set b = 8; insert into t1 values (b); insert into t1 values (unix_timestamp()); -end @ # # +end root@localhost # # set timestamp=1000000000; call foo(); select * from t1; @@ -118,7 +118,7 @@ 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 DEFINER begin insert into t2 values(20),(20); -end @ # # +end root@localhost # # drop procedure foo4; 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 @@ -223,13 +223,13 @@ 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 NO_SQL NO DEFINER int(11) begin return unix_timestamp(); -end @ # # +end root@localhost # # mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin return unix_timestamp(); -end @ # # +end zedjzlcsjhd@localhost # # mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin return 0; -end @ # # +end root@localhost # # delete from t2; alter table t2 add unique (a); drop function fn1; @@ -274,7 +274,7 @@ Log_name Pos Event_type Server_id End_log_pos Info 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo() begin declare b int; set b = 8; @@ -284,19 +284,19 @@ 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` procedure foo4() deterministic begin insert into t2 values(3); @@ -311,7 +311,7 @@ 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo4() deterministic begin insert into t2 values(20),(20); @@ -321,7 +321,7 @@ 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) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) returns int deterministic begin @@ -332,7 +332,7 @@ master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2 master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1() returns int no sql begin @@ -340,13 +340,13 @@ 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() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` function fn2() returns int no sql begin return unix_timestamp(); end -master-bin.000001 # Query 1 # use `mysqltest1`; create function fn3() +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn3() returns int not deterministic reads sql data @@ -356,7 +356,7 @@ 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(x int) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) returns int begin insert into t2 values(x),(x); diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index 185862097bc..b9b20b82acd 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -102,7 +102,7 @@ t1_first root@localhost SELECT routine_name, definer FROM information_schema.routines; routine_name definer -bug12480 @ +bug12480 root@localhost SELECT trigger_name, definer FROM information_schema.triggers; trigger_name definer diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index d8abc387677..90466bfcfc4 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -323,3 +323,55 @@ Warning 1287 'SHOW INNODB STATUS' is deprecated; use 'SHOW ENGINE INNODB STATUS' GRANT EXECUTE ON PROCEDURE p1 TO user_bug7787@localhost; DROP DATABASE db_bug7787; use test; + +---> connection: root +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +CREATE USER mysqltest_1@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost; +CREATE USER mysqltest_2@localhost; +GRANT SUPER ON *.* TO mysqltest_2@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost; + +---> connection: mysqltest_2_con +use mysqltest; +CREATE PROCEDURE wl2897_p1() SELECT 1; +CREATE FUNCTION wl2897_f1() RETURNS INT RETURN 1; + +---> connection: mysqltest_1_con +use mysqltest; +CREATE DEFINER=root@localhost PROCEDURE wl2897_p2() SELECT 2; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +CREATE DEFINER=root@localhost FUNCTION wl2897_f2() RETURNS INT RETURN 2; +ERROR 42000: Access denied; you need the SUPER privilege for this operation + +---> connection: mysqltest_2_con +use mysqltest; +CREATE DEFINER='a @ b @ c'@localhost PROCEDURE wl2897_p3() SELECT 3; +Warnings: +Note 1449 There is no 'a @ b @ c'@'localhost' registered +CREATE DEFINER='a @ b @ c'@localhost FUNCTION wl2897_f3() RETURNS INT RETURN 3; +Warnings: +Note 1449 There is no 'a @ b @ c'@'localhost' registered + +---> connection: con1root +use mysqltest; +SHOW CREATE PROCEDURE wl2897_p1; +Procedure sql_mode Create Procedure +wl2897_p1 CREATE DEFINER=`mysqltest_2`@`localhost` PROCEDURE `wl2897_p1`() +SELECT 1 +SHOW CREATE PROCEDURE wl2897_p3; +Procedure sql_mode Create Procedure +wl2897_p3 CREATE DEFINER=`a @ b @ c`@`localhost` PROCEDURE `wl2897_p3`() +SELECT 3 +SHOW CREATE FUNCTION wl2897_f1; +Function sql_mode Create Function +wl2897_f1 CREATE DEFINER=`mysqltest_2`@`localhost` FUNCTION `wl2897_f1`() RETURNS int(11) +RETURN 1 +SHOW CREATE FUNCTION wl2897_f3; +Function sql_mode Create Function +wl2897_f3 CREATE DEFINER=`a @ b @ c`@`localhost` FUNCTION `wl2897_f3`() RETURNS int(11) +RETURN 3 +DROP USER mysqltest_1@localhost; +DROP USER mysqltest_2@localhost; +DROP DATABASE mysqltest; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index a4c920f8e15..3e7c51e9394 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -788,7 +788,7 @@ comment 'Characteristics procedure test' insert into t1 values ("chistics", 1)| show create procedure chistics| Procedure sql_mode Create Procedure -chistics CREATE PROCEDURE `chistics`() +chistics CREATE DEFINER=`root`@`localhost` PROCEDURE `chistics`() MODIFIES SQL DATA COMMENT 'Characteristics procedure test' insert into t1 values ("chistics", 1) @@ -800,7 +800,7 @@ delete from t1| alter procedure chistics sql security invoker| show create procedure chistics| Procedure sql_mode Create Procedure -chistics CREATE PROCEDURE `chistics`() +chistics CREATE DEFINER=`root`@`localhost` PROCEDURE `chistics`() MODIFIES SQL DATA SQL SECURITY INVOKER COMMENT 'Characteristics procedure test' @@ -815,7 +815,7 @@ comment 'Characteristics procedure test' return 42| show create function chistics| Function sql_mode Create Function -chistics CREATE FUNCTION `chistics`() RETURNS int(11) +chistics CREATE DEFINER=`root`@`localhost` FUNCTION `chistics`() RETURNS int(11) DETERMINISTIC SQL SECURITY INVOKER COMMENT 'Characteristics procedure test' @@ -828,7 +828,7 @@ no sql comment 'Characteristics function test'| show create function chistics| Function sql_mode Create Function -chistics CREATE FUNCTION `chistics`() RETURNS int(11) +chistics CREATE DEFINER=`root`@`localhost` FUNCTION `chistics`() RETURNS int(11) NO SQL DETERMINISTIC SQL SECURITY INVOKER @@ -1287,7 +1287,7 @@ end while; end| show create procedure opp| Procedure sql_mode Create Procedure -opp CREATE PROCEDURE `opp`(n bigint unsigned, out pp bool) +opp CREATE DEFINER=`root`@`localhost` PROCEDURE `opp`(n bigint unsigned, out pp bool) begin declare r double; declare b, s bigint unsigned default 0; @@ -1386,7 +1386,7 @@ alter procedure bar comment "3333333333"| alter procedure bar| show create procedure bar| Procedure sql_mode Create Procedure -bar CREATE PROCEDURE `bar`(x char(16), y int) +bar CREATE DEFINER=`root`@`localhost` PROCEDURE `bar`(x char(16), y int) COMMENT '3333333333' insert into test.t1 values (x, y) show procedure status like 'bar'| @@ -1966,13 +1966,13 @@ Db Name Type Definer Modified Created Security_type Comment test bug2267_4 FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call bug2267_3()| Procedure sql_mode Create Procedure -bug2267_1 CREATE PROCEDURE `bug2267_1`() +bug2267_1 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug2267_1`() begin show procedure status; end call bug2267_4()| Function sql_mode Create Function -bug2267_4 CREATE FUNCTION `bug2267_4`() RETURNS int(11) +bug2267_4 CREATE DEFINER=`root`@`localhost` FUNCTION `bug2267_4`() RETURNS int(11) return 100 drop procedure bug2267_1| drop procedure bug2267_2| @@ -2333,20 +2333,20 @@ return x || y$ set @@sql_mode = ''| show create procedure bug2564_1| Procedure sql_mode Create Procedure -bug2564_1 CREATE PROCEDURE `bug2564_1`() +bug2564_1 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug2564_1`() COMMENT 'Joe''s procedure' insert into `t1` values ("foo", 1) show create procedure bug2564_2| Procedure sql_mode Create Procedure -bug2564_2 ANSI_QUOTES CREATE PROCEDURE "bug2564_2"() +bug2564_2 ANSI_QUOTES CREATE DEFINER="root"@"localhost" PROCEDURE "bug2564_2"() insert into "t1" values ('foo', 1) show create function bug2564_3| Function sql_mode Create Function -bug2564_3 CREATE FUNCTION `bug2564_3`(x int, y int) RETURNS int(11) +bug2564_3 CREATE DEFINER=`root`@`localhost` FUNCTION `bug2564_3`(x int, y int) RETURNS int(11) return x || y show create function bug2564_4| Function sql_mode Create Function -bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI CREATE FUNCTION "bug2564_4"(x int, y int) RETURNS int(11) +bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI CREATE DEFINER="root"@"localhost" FUNCTION "bug2564_4"(x int, y int) RETURNS int(11) return x || y drop procedure bug2564_1| drop procedure bug2564_2| @@ -4056,7 +4056,7 @@ return 42; end */;; show create function bug14723;; Function sql_mode Create Function -bug14723 CREATE FUNCTION `bug14723`() RETURNS bigint(20) +bug14723 CREATE DEFINER=`root`@`localhost` FUNCTION `bug14723`() RETURNS bigint(20) main_loop: begin return 42; end @@ -4069,7 +4069,7 @@ select 42; end */;; show create procedure bug14723;; Procedure sql_mode Create Procedure -bug14723 CREATE PROCEDURE `bug14723`() +bug14723 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug14723`() main_loop: begin select 42; end diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 66df424919b..b05680f9c54 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -445,23 +445,23 @@ SET @@SQL_MODE=''; create function `foo` () returns int return 5; show create function `foo`; Function sql_mode Create Function -foo CREATE FUNCTION `foo`() RETURNS int(11) +foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11) return 5 SET @@SQL_MODE='ANSI_QUOTES'; show create function `foo`; Function sql_mode Create Function -foo CREATE FUNCTION `foo`() RETURNS int(11) +foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11) return 5 drop function `foo`; create function `foo` () returns int return 5; show create function `foo`; Function sql_mode Create Function -foo ANSI_QUOTES CREATE FUNCTION "foo"() RETURNS int(11) +foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11) return 5 SET @@SQL_MODE=''; show create function `foo`; Function sql_mode Create Function -foo ANSI_QUOTES CREATE FUNCTION "foo"() RETURNS int(11) +foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11) return 5 drop function `foo`; SET @@SQL_MODE=''; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 19f94a32d9c..b466d2125d4 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -547,4 +547,105 @@ GRANT EXECUTE ON PROCEDURE p1 TO user_bug7787@localhost; DROP DATABASE db_bug7787; use test; + +# +# WL#2897: Complete definer support in the stored routines. +# +# The following cases are tested: +# 1. check that if DEFINER-clause is not explicitly specified, stored routines +# are created with CURRENT_USER privileges; +# 2. check that if DEFINER-clause specifies non-current user, SUPER privilege +# is required to create a stored routine; +# 3. check that if DEFINER-clause specifies non-existent user, a warning is +# emitted. +# 4. check that SHOW CREATE PROCEDURE | FUNCTION works correctly; +# +# The following cases are tested in other test suites: +# - check that mysqldump dumps new attribute correctly; +# - check that slave replicates CREATE-statements with explicitly specified +# DEFINER correctly. +# + +# Setup the environment. + +--echo +--echo ---> connection: root +--connection con1root + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest; +--enable_warnings + +CREATE DATABASE mysqltest; + +CREATE USER mysqltest_1@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost; + +CREATE USER mysqltest_2@localhost; +GRANT SUPER ON *.* TO mysqltest_2@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost; + +--connect (mysqltest_2_con,localhost,mysqltest_2,,mysqltest) +--connect (mysqltest_1_con,localhost,mysqltest_1,,mysqltest) + +# test case (1). + +--echo +--echo ---> connection: mysqltest_2_con +--connection mysqltest_2_con + +use mysqltest; + +CREATE PROCEDURE wl2897_p1() SELECT 1; + +CREATE FUNCTION wl2897_f1() RETURNS INT RETURN 1; + +# test case (2). + +--echo +--echo ---> connection: mysqltest_1_con +--connection mysqltest_1_con + +use mysqltest; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +CREATE DEFINER=root@localhost PROCEDURE wl2897_p2() SELECT 2; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +CREATE DEFINER=root@localhost FUNCTION wl2897_f2() RETURNS INT RETURN 2; + +# test case (3). + +--echo +--echo ---> connection: mysqltest_2_con +--connection mysqltest_2_con + +use mysqltest; + +CREATE DEFINER='a @ b @ c'@localhost PROCEDURE wl2897_p3() SELECT 3; + +CREATE DEFINER='a @ b @ c'@localhost FUNCTION wl2897_f3() RETURNS INT RETURN 3; + +# test case (4). + +--echo +--echo ---> connection: con1root +--connection con1root + +use mysqltest; + +SHOW CREATE PROCEDURE wl2897_p1; +SHOW CREATE PROCEDURE wl2897_p3; + +SHOW CREATE FUNCTION wl2897_f1; +SHOW CREATE FUNCTION wl2897_f3; + +# Cleanup. + +DROP USER mysqltest_1@localhost; +DROP USER mysqltest_2@localhost; + +DROP DATABASE mysqltest; + + # End of 5.0 bugs. diff --git a/sql/sp.cc b/sql/sp.cc index ce0282bf810..e4489af1fdd 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -21,6 +21,8 @@ #include "sp_cache.h" #include "sql_trigger.h" +#include + static bool create_string(THD *thd, String *buf, int sp_type, @@ -28,7 +30,9 @@ create_string(THD *thd, String *buf, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, - st_sp_chistics *chistics); + st_sp_chistics *chistics, + const LEX_STRING *definer_user, + const LEX_STRING *definer_host); static int db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ulong sql_mode, const char *params, const char *returns, @@ -406,6 +410,15 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ulong old_sql_mode= thd->variables.sql_mode; ha_rows old_select_limit= thd->variables.select_limit; sp_rcontext *old_spcont= thd->spcont; + + char definer_user_name_holder[USERNAME_LENGTH + 1]; + LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder, + USERNAME_LENGTH); + + char definer_host_name_holder[HOSTNAME_LENGTH + 1]; + LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder, + HOSTNAME_LENGTH); + int ret; thd->variables.sql_mode= sql_mode; @@ -414,14 +427,25 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, thd->lex= &newlex; newlex.current_select= NULL; + parse_user(definer, strlen(definer), + definer_user_name.str, &definer_user_name.length, + definer_host_name.str, &definer_host_name.length); + defstr.set_charset(system_charset_info); + + /* + We have to add DEFINER clause and provide proper routine characterstics in + routine definition statement that we build here to be able to use this + definition for SHOW CREATE PROCEDURE later. + */ + if (!create_string(thd, &defstr, type, name, params, strlen(params), returns, strlen(returns), body, strlen(body), - &chistics)) + &chistics, &definer_user_name, &definer_host_name)) { ret= SP_INTERNAL_ERROR; goto end; @@ -449,7 +473,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, if (dbchanged && (ret= mysql_change_db(thd, olddb, 1))) goto end; *sphp= newlex.sphead; - (*sphp)->set_definer((char*) definer, (uint) strlen(definer)); + (*sphp)->set_definer(&definer_user_name, &definer_host_name); (*sphp)->set_info(created, modified, &chistics, sql_mode); (*sphp)->optimize(); } @@ -500,8 +524,10 @@ db_create_routine(THD *thd, int type, sp_head *sp) else { restore_record(table, s->default_values); // Get default values for fields - strxmov(definer, thd->security_ctx->priv_user, "@", - thd->security_ctx->priv_host, NullS); + + /* NOTE: all needed privilege checks have been already done. */ + strxmov(definer, thd->lex->definer->user.str, "@", + thd->lex->definer->host.str, NullS); if (table->s->fields != MYSQL_PROC_FIELD_COUNT) { @@ -592,8 +618,17 @@ db_create_routine(THD *thd, int type, sp_head *sp) else if (mysql_bin_log.is_open()) { thd->clear_error(); + + String log_query; + log_query.set_charset(system_charset_info); + log_query.append(STRING_WITH_LEN("CREATE ")); + append_definer(thd, &log_query, &thd->lex->definer->user, + &thd->lex->definer->host); + log_query.append(thd->lex->stmt_definition_begin); + /* Such a statement can always go directly to binlog, no trans cache */ - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, + FALSE); mysql_bin_log.write(&qinfo); } @@ -1723,14 +1758,18 @@ create_string(THD *thd, String *buf, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, - st_sp_chistics *chistics) + st_sp_chistics *chistics, + const LEX_STRING *definer_user, + const LEX_STRING *definer_host) { /* Make some room to begin with */ if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen + - chistics->comment.length)) + chistics->comment.length + 10 /* length of " DEFINER= "*/ + + USER_HOST_BUFF_SIZE)) return FALSE; buf->append(STRING_WITH_LEN("CREATE ")); + append_definer(thd, buf, definer_user, definer_host); if (type == TYPE_ENUM_FUNCTION) buf->append(STRING_WITH_LEN("FUNCTION ")); else diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f7572a374f1..b8b7ee2f78b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1810,19 +1810,27 @@ sp_head::set_info(longlong created, longlong modified, void sp_head::set_definer(const char *definer, uint definerlen) { - uint user_name_len; - char user_name_str[USERNAME_LENGTH + 1]; - uint host_name_len; - char host_name_str[HOSTNAME_LENGTH + 1]; + char user_name_holder[USERNAME_LENGTH + 1]; + LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH); - parse_user(definer, definerlen, user_name_str, &user_name_len, - host_name_str, &host_name_len); + char host_name_holder[HOSTNAME_LENGTH + 1]; + LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH); - m_definer_user.str= strmake_root(mem_root, user_name_str, user_name_len); - m_definer_user.length= user_name_len; + parse_user(definer, definerlen, user_name.str, &user_name.length, + host_name.str, &host_name.length); - m_definer_host.str= strmake_root(mem_root, host_name_str, host_name_len); - m_definer_host.length= host_name_len; + set_definer(&user_name, &host_name); +} + + +void +sp_head::set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name) +{ + m_definer_user.str= strmake_root(mem_root, user_name->str, user_name->length); + m_definer_user.length= user_name->length; + + m_definer_host.str= strmake_root(mem_root, host_name->str, host_name->length); + m_definer_host.length= host_name->length; } diff --git a/sql/sp_head.h b/sql/sp_head.h index a4dd68ee4a3..64d9167fb17 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -302,6 +302,7 @@ public: st_sp_chistics *chistics, ulong sql_mode); void set_definer(const char *definer, uint definerlen); + void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name); void reset_thd_mem_root(THD *thd); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7b2ea359fb2..8db059ae2fa 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -909,12 +909,16 @@ 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. + stmt_definition_begin is intended to point to the next word after + DEFINER-clause in the following statements: + - CREATE TRIGGER (points to "TRIGGER"); + - CREATE PROCEDURE (points to "PROCEDURE"); + - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE"); + + This pointer is required to add possibly omitted DEFINER-clause to the + DDL-statement before dumping it to the binlog. */ - const char *trigger_definition_begin; + const char *stmt_definition_begin; /* If non-0 then indicates that query requires prelocking and points to diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 13d814bdf42..527a6a67811 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4145,6 +4145,90 @@ end_with_restore_list: } #endif + /* + If the definer is not specified, this means that CREATE-statement missed + DEFINER-clause. DEFINER-clause can be missed in two cases: + + - The user submitted a statement w/o the clause. This is a normal + case, we should assign CURRENT_USER as definer. + + - Our slave received an updated from the master, that does not + replicate definer for stored rountines. We should also assign + CURRENT_USER as definer here, but also we should mark this routine + as NON-SUID. This is essential for the sake of backward + compatibility. + + The problem is the slave thread is running under "special" user (@), + that actually does not exist. In the older versions we do not fail + execution of a stored routine if its definer does not exist and + continue the execution under the authorization of the invoker + (BUG#13198). And now if we try to switch to slave-current-user (@), + we will fail. + + Actually, this leads to the inconsistent state of master and + slave (different definers, different SUID behaviour), but it seems, + this is the best we can do. + */ + + if (!lex->definer) + { + bool res= FALSE; + Query_arena original_arena; + Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); + + if (!(lex->definer= create_default_definer(thd))) + res= TRUE; + + if (ps_arena) + thd->restore_active_arena(ps_arena, &original_arena); + + if (res) + { + /* Error has been already reported. */ + delete lex->sphead; + lex->sphead= 0; + goto error; + } + + if (thd->slave_thread) + lex->sphead->m_chistics->suid= SP_IS_NOT_SUID; + } + + /* + If the specified definer differs from the current user, we should check + that the current user has SUPER privilege (in order to create a stored + routine under another user one must have SUPER privilege). + */ + + else 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"); + delete lex->sphead; + lex->sphead= 0; + goto error; + } + } + + /* Check that the specified definer exists. Emit a warning if not. */ + +#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 */ + /* We need to copy name and db in order to use them for check_routine_access which is called after lex->sphead has diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 9ccc70d8ccd..1fe5bf63756 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -275,7 +275,7 @@ end: append_definer(thd, &log_query, &definer_user, &definer_host); } - log_query.append(thd->lex->trigger_definition_begin); + log_query.append(thd->lex->stmt_definition_begin); } /* Such a statement can always go directly to binlog, no trans cache. */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e93b9c8e73..36a684f1d4a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -833,8 +833,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); 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 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 + view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail + view_suid view_tail view_list_opt view_list view_select + view_check_option trigger_tail sp_tail END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -1189,81 +1190,13 @@ create: lex->name=$4.str; lex->create_info.options=$3; } - | CREATE udf_func_type FUNCTION_SYM sp_name - { - LEX *lex=Lex; - lex->spname= $4; - lex->udf.type= $2; - } - create_function_tail - {} - | CREATE PROCEDURE sp_name - { - LEX *lex= Lex; - sp_head *sp; - - if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE"); - YYABORT; - } - /* Order is important here: new - reset - init */ - sp= new sp_head(); - sp->reset_thd_mem_root(YYTHD); - sp->init(lex); - - sp->m_type= TYPE_ENUM_PROCEDURE; - lex->sphead= sp; - /* - * 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); - } - '(' - { - LEX *lex= Lex; - - lex->sphead->m_param_begin= lex->tok_start+1; - } - sp_pdparam_list - ')' - { - LEX *lex= Lex; - - lex->sphead->m_param_end= lex->tok_start; - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - } - sp_c_chistics - { - LEX *lex= Lex; - - lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->m_body_begin= lex->tok_start; - } - sp_proc_stmt - { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - - if (sp->check_backpatch(YYTHD)) - YYABORT; - sp->init_strings(YYTHD, lex, $3); - lex->sql_command= SQLCOM_CREATE_PROCEDURE; - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; - sp->restore_thd_mem_root(YYTHD); - } | CREATE { Lex->create_view_mode= VIEW_CREATE_NEW; Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; Lex->create_view_suid= TRUE; } - view_or_trigger + view_or_trigger_or_sp {} | CREATE USER clear_privileges grant_list { @@ -8959,6 +8892,34 @@ subselect_end: lex->nest_level--; }; +/************************************************************************** + + CREATE VIEW | TRIGGER | PROCEDURE statements. + +**************************************************************************/ + +view_or_trigger_or_sp: + definer view_or_trigger_or_sp_tail + {} + | view_replace_or_algorithm definer view_tail + {} + ; + +view_or_trigger_or_sp_tail: + view_tail + {} + | trigger_tail + {} + | sp_tail + {} + ; + +/************************************************************************** + + DEFINER clause support. + +**************************************************************************/ + definer: /* empty */ { @@ -8985,7 +8946,7 @@ definer: /************************************************************************** - CREATE VIEW statement options. + CREATE VIEW statement parts. **************************************************************************/ @@ -9019,20 +8980,6 @@ view_algorithm_opt: {} ; -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; } @@ -9131,7 +9078,7 @@ trigger_tail: sp->reset_thd_mem_root(YYTHD); sp->init(lex); - lex->trigger_definition_begin= $2; + lex->stmt_definition_begin= $2; lex->ident.str= $7; lex->ident.length= $9 - $7; @@ -9180,6 +9127,87 @@ trigger_tail: } ; +/************************************************************************** + + CREATE FUNCTION | PROCEDURE statements parts. + +**************************************************************************/ + +sp_tail: + udf_func_type remember_name FUNCTION_SYM sp_name + { + LEX *lex=Lex; + lex->udf.type= $1; + lex->stmt_definition_begin= $2; + lex->spname= $4; + } + create_function_tail + {} + | PROCEDURE remember_name sp_name + { + LEX *lex= Lex; + sp_head *sp; + + if (lex->sphead) + { + my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE"); + YYABORT; + } + + lex->stmt_definition_begin= $2; + + /* Order is important here: new - reset - init */ + sp= new sp_head(); + sp->reset_thd_mem_root(YYTHD); + sp->init(lex); + + sp->m_type= TYPE_ENUM_PROCEDURE; + lex->sphead= sp; + /* + * 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); + } + '(' + { + LEX *lex= Lex; + + lex->sphead->m_param_begin= lex->tok_start+1; + } + sp_pdparam_list + ')' + { + LEX *lex= Lex; + + lex->sphead->m_param_end= lex->tok_start; + bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + } + sp_c_chistics + { + LEX *lex= Lex; + + lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->m_body_begin= lex->tok_start; + } + sp_proc_stmt + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + + if (sp->check_backpatch(YYTHD)) + YYABORT; + sp->init_strings(YYTHD, lex, $3); + lex->sql_command= SQLCOM_CREATE_PROCEDURE; + /* Restore flag if it was cleared above */ + if (sp->m_old_cmq) + YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; + sp->restore_thd_mem_root(YYTHD); + } + ; + /*************************************************************************/ xa: XA_SYM begin_or_start xid opt_join_or_resume From c4cbe46bc73b680532f8a6cf2dff20f0e7afa341 Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 2 Mar 2006 16:23:42 +0300 Subject: [PATCH 04/12] Fix for BUG#13198: SP executes if definer does not exist. Basically, this fix contains a test case and removing of a workaround for replication. This fix became possible after pushing WL#2897 (Complete definer support in stored routines). --- mysql-test/r/sp-security.result | 44 +++++++++++++++ mysql-test/t/sp-security.test | 95 +++++++++++++++++++++++++++++++++ sql/sp_head.cc | 15 ------ 3 files changed, 139 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index 90466bfcfc4..896b6fa572c 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -375,3 +375,47 @@ RETURN 3 DROP USER mysqltest_1@localhost; DROP USER mysqltest_2@localhost; DROP DATABASE mysqltest; + +---> connection: root +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +CREATE USER mysqltest_1@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost; +CREATE USER mysqltest_2@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost; + +---> connection: mysqltest_1_con +use mysqltest; +CREATE PROCEDURE bug13198_p1() +SELECT 1; +CREATE FUNCTION bug13198_f1() RETURNS INT +RETURN 1; +CALL bug13198_p1(); +1 +1 +SELECT bug13198_f1(); +bug13198_f1() +1 + +---> connection: mysqltest_2_con +use mysqltest; +CALL bug13198_p1(); +1 +1 +SELECT bug13198_f1(); +bug13198_f1() +1 + +---> connection: root +DROP USER mysqltest_1@localhost; + +---> connection: mysqltest_2_con +use mysqltest; +CALL bug13198_p1(); +ERROR HY000: There is no 'mysqltest_1'@'localhost' registered +SELECT bug13198_f1(); +ERROR HY000: There is no 'mysqltest_1'@'localhost' registered + +---> connection: root +DROP USER mysqltest_2@localhost; +DROP DATABASE mysqltest; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index b466d2125d4..f369dc64b0e 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -647,5 +647,100 @@ DROP USER mysqltest_2@localhost; DROP DATABASE mysqltest; +--disconnect mysqltest_1_con +--disconnect mysqltest_2_con + + +# +# BUG#13198: SP executes if definer does not exist +# + +# Prepare environment. + +--echo +--echo ---> connection: root +--connection con1root + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest; +--enable_warnings + +CREATE DATABASE mysqltest; + +CREATE USER mysqltest_1@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost; + +CREATE USER mysqltest_2@localhost; +GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost; + +--connect (mysqltest_1_con,localhost,mysqltest_1,,mysqltest) +--connect (mysqltest_2_con,localhost,mysqltest_2,,mysqltest) + +# Create a procedure/function under u1. + +--echo +--echo ---> connection: mysqltest_1_con +--connection mysqltest_1_con + +use mysqltest; + +CREATE PROCEDURE bug13198_p1() + SELECT 1; + +CREATE FUNCTION bug13198_f1() RETURNS INT + RETURN 1; + +CALL bug13198_p1(); + +SELECT bug13198_f1(); + +# Check that u2 can call the procedure/function. + +--echo +--echo ---> connection: mysqltest_2_con +--connection mysqltest_2_con + +use mysqltest; + +CALL bug13198_p1(); + +SELECT bug13198_f1(); + +# Drop user u1 (definer of the object); + +--echo +--echo ---> connection: root +--connection con1root + +--disconnect mysqltest_1_con + +DROP USER mysqltest_1@localhost; + +# Check that u2 can not call the procedure/function. + +--echo +--echo ---> connection: mysqltest_2_con +--connection mysqltest_2_con + +use mysqltest; + +--error ER_NO_SUCH_USER +CALL bug13198_p1(); + +--error ER_NO_SUCH_USER +SELECT bug13198_f1(); + +# Cleanup. + +--echo +--echo ---> connection: root +--connection con1root + +--disconnect mysqltest_2_con + +DROP USER mysqltest_2@localhost; + +DROP DATABASE mysqltest; + # End of 5.0 bugs. diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b8b7ee2f78b..c0b566f9b9b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3171,24 +3171,9 @@ sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup) sp->m_definer_host.str, sp->m_db.str)) { -#ifdef NOT_YET_REPLICATION_SAFE - /* - Until we don't properly replicate information about stored routine - definer with stored routine creation statement all stored routines - on slave are created under ''@'' definer. Therefore we won't be able - to run any routine which was replicated from master on slave server - if we emit error here. This will cause big problems for users - who use slave for fail-over. So until we fully implement WL#2897 - "Complete definer support in the stored routines" we run suid - stored routines for which we were unable to find definer under - invoker security context. - */ my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str, sp->m_definer_host.str); return TRUE; -#else - return FALSE; -#endif } *backup= thd->security_ctx; thd->security_ctx= &sp->m_security_ctx; From 615357b96c91e54b2fc9031e16a9182c43b46cf9 Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Wed, 8 Mar 2006 00:13:27 +0300 Subject: [PATCH 05/12] After-merge fix: fix the test case for BUG#16266 to query only its own tables to prevent getting tables from others. --- mysql-test/r/rpl_trigger.result | 8 ++++---- mysql-test/t/rpl_trigger.test | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index b9b20b82acd..3e4a3349e13 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -862,8 +862,8 @@ START SLAVE; SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; MASTER_POS_WAIT('master-bin.000001', 513) >= 0 1 -SHOW TABLES; -Tables_in_test +SHOW TABLES LIKE 't_'; +Tables_in_test (t_) t1 t2 SHOW TRIGGERS; @@ -891,8 +891,8 @@ DROP TABLE t1; DROP TABLE t2; STOP SLAVE; RESET SLAVE; -SHOW TABLES; -Tables_in_test +SHOW TABLES LIKE 't_'; +Tables_in_test (t_) SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer RESET MASTER; diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index 90822e0654c..35f0a0b0a4b 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -301,7 +301,7 @@ SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; # Check that the replication succeeded. -SHOW TABLES; +SHOW TABLES LIKE 't_'; SHOW TRIGGERS; SELECT * FROM t1; SELECT * FROM t2; @@ -326,7 +326,7 @@ RESET SLAVE; # The master should be clean. connection master; -SHOW TABLES; +SHOW TABLES LIKE 't_'; SHOW TRIGGERS; RESET MASTER; From e37f80a1ace70526e29d27e978fdd007891dbb77 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 8 Mar 2006 16:57:42 +0100 Subject: [PATCH 06/12] BUG#17574 Detect cluster start failure and "fail" ndb_* tests - Fix problems that occur when ndbcluster is not supported --- mysql-test/lib/mtr_cases.pl | 7 +++++++ mysql-test/mysql-test-run.pl | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index fc32c56536f..51eed62c1ff 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -258,6 +258,13 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'ndb_test'}= 1; if ( $::opt_skip_ndbcluster ) { + # Skip all ndb tests + $tinfo->{'skip'}= 1; + return; + } + if ( ! $::opt_with_ndbcluster ) + { + # Ndb is not supported, skip them $tinfo->{'skip'}= 1; return; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c105ace789f..75491795a60 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1840,7 +1840,7 @@ sub run_testcase ($) { if ( $tinfo->{'master_restart'} or $master->[0]->{'running_master_is_special'} or # Stop if cluster is started but test cases does not need cluster - ( $tinfo->{'ndb_test'} != $using_ndbcluster_master ) ) + ( $opt_with_ndbcluster && $tinfo->{'ndb_test'} != $using_ndbcluster_master ) ) { stop_masters(); $master->[0]->{'running_master_is_special'}= 0; # Forget why we stopped @@ -1889,7 +1889,7 @@ sub run_testcase ($) { if ( $tinfo->{'component_id'} eq 'mysqld' and ! $opt_local_master ) { - if ( $master->[0]->{'ndbcluster'} ) + if ( $opt_with_ndbcluster and $master->[0]->{'ndbcluster'} ) { # Cluster is not started From be527f3070c67455bc7d7a5e9361ee2b1f09461a Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 9 Mar 2006 03:10:39 +0300 Subject: [PATCH 07/12] Fix for multiple test failures on some platforms. --- sql/sql_lex.cc | 3 ++- sql/sql_show.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1ed8887a878..49b0c70ff03 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -223,7 +223,7 @@ static int find_keyword(LEX *lex, uint len, bool function) SYNOPSIS is_keyword() - name checked name + name checked name (must not be empty) len length of checked name RETURN VALUES @@ -233,6 +233,7 @@ static int find_keyword(LEX *lex, uint len, bool function) bool is_keyword(const char *name, uint len) { + DBUG_ASSERT(len != 0); return get_hash_symbol(name,len,0)!=0; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8920efa87ab..5c9d13cac3e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -713,7 +713,8 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) int get_quote_char_for_identifier(THD *thd, const char *name, uint length) { - if (!is_keyword(name,length) && + if (!length || + !is_keyword(name,length) && !require_quotes(name, length) && !(thd->options & OPTION_QUOTE_SHOW_CREATE)) return EOF; From e517d40a4365c591a52e25ea53fdbde076cb9cc4 Mon Sep 17 00:00:00 2001 From: "jmiller@mysql.com" <> Date: Thu, 9 Mar 2006 03:37:25 +0100 Subject: [PATCH 08/12] New test to satisfy some of the 5.1 CR test plan --- .../include/ndb_restore_slave_eoption.inc | 11 + mysql-test/r/rpl_ndb_dd_advance.result | 421 +++++++++++++ mysql-test/t/rpl_ndb_dd_advance.test | 565 ++++++++++++++++++ 3 files changed, 997 insertions(+) create mode 100644 mysql-test/include/ndb_restore_slave_eoption.inc create mode 100644 mysql-test/r/rpl_ndb_dd_advance.result create mode 100644 mysql-test/t/rpl_ndb_dd_advance.test diff --git a/mysql-test/include/ndb_restore_slave_eoption.inc b/mysql-test/include/ndb_restore_slave_eoption.inc new file mode 100644 index 00000000000..f1f6cf96881 --- /dev/null +++ b/mysql-test/include/ndb_restore_slave_eoption.inc @@ -0,0 +1,11 @@ +###################################################### +# By JBM 2006-03-08 So that the code is not repeated # +# in test cases and can be reused. # +###################################################### + +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT_SLAVE" -p 8 -b $the_backup_id -n 1 -m -r --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT + +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT_SLAVE" -p 8 -b $the_backup_id -n 2 -r -e --print --print_meta $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id >> $NDB_TOOLS_OUTPUT + + + diff --git a/mysql-test/r/rpl_ndb_dd_advance.result b/mysql-test/r/rpl_ndb_dd_advance.result new file mode 100644 index 00000000000..64820b6f9e5 --- /dev/null +++ b/mysql-test/r/rpl_ndb_dd_advance.result @@ -0,0 +1,421 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP TABLE IF EXISTS t1, t2, t3; +***** Test 1 RPL of CDD and Alter ***** +***** Test 1 setup ***** +CREATE LOGFILE GROUP lg1 +ADD UNDOFILE 'undofile.dat' +INITIAL_SIZE 16M +UNDO_BUFFER_SIZE = 1M +ENGINE=NDB; +ALTER LOGFILE GROUP lg1 +ADD UNDOFILE 'undofile02.dat' +INITIAL_SIZE 4M +ENGINE=NDB; +CREATE TABLESPACE ts1 +ADD DATAFILE 'datafile.dat' +USE LOGFILE GROUP lg1 +INITIAL_SIZE 12M +ENGINE=NDB; +ALTER TABLESPACE ts1 +ADD DATAFILE 'datafile02.dat' +INITIAL_SIZE 4M +ENGINE=NDB; +CREATE TABLE t1 +(c1 INT NOT NULL PRIMARY KEY, +c2 INT NOT NULL, +c3 INT NOT NULL) +TABLESPACE ts1 STORAGE DISK +ENGINE=NDB; +***** insert some data ***** +***** Select from Master ***** +SELECT * FROM t1 ORDER BY c1 LIMIT 5; +c1 c2 c3 +1 2 4 +2 4 5 +3 6 6 +4 8 7 +5 10 8 +***** Select from Slave ***** +SELECT * FROM t1 ORDER BY c1 LIMIT 5; +c1 c2 c3 +1 2 4 +2 4 5 +3 6 6 +4 8 7 +5 10 8 +FILE_NAME FILE_TYPE TABLESPACE_NAME LOGFILE_GROUP_NAME +datafile02.dat DATAFILE ts1 lg1 +datafile.dat DATAFILE ts1 lg1 +undofile.dat UNDO LOG ts1 lg1 +undofile02.dat UNDO LOG ts1 lg1 +**** Do First Set of ALTERs in the master table **** +CREATE INDEX t1_i ON t1(c2, c3); +ALTER TABLE t1 ADD c4 TIMESTAMP; +ALTER TABLE t1 ADD c5 DOUBLE; +ALTER TABLE t1 ADD INDEX (c5); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) NOT NULL, + `c3` int(11) NOT NULL, + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`,`c3`), + KEY `c5` (`c5`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +**** Show first set of ALTERs on SLAVE **** +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) NOT NULL, + `c3` int(11) NOT NULL, + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`,`c3`), + KEY `c5` (`c5`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +**** Second set of alters test 1 **** +ALTER TABLE t1 RENAME t2; +ALTER TABLE t2 DROP INDEX c5; +CREATE TABLE t1(c1 INT)ENGINE=NDB; +INSERT INTO t1 VALUES(1); +DROP TABLE t1; +ALTER TABLE t2 RENAME t1; +**** Show second set of ALTERs on MASTER **** +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) NOT NULL, + `c3` int(11) NOT NULL, + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`,`c3`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +**** Show second set of ALTERs on SLAVE **** +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) NOT NULL, + `c3` int(11) NOT NULL, + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`,`c3`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +**** Third and last set of alters for test1 **** +ALTER TABLE t1 CHANGE c1 c1 DOUBLE; +ALTER TABLE t1 CHANGE c2 c2 DECIMAL(10,2); +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t1 CHANGE c4 c4 TEXT CHARACTER SET utf8; +ALTER TABLE t1 CHANGE c4 c4 BLOB; +ALTER TABLE t1 CHANGE c4 c3 BLOB; +set @b1 = 'b1'; +set @b1 = concat(@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1); +UPDATE t1 SET c3=@b1 where c1 = 1; +UPDATE t1 SET c3=@b1 where c1 = 2; +**** Show last set of ALTERs on MASTER **** +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` double NOT NULL DEFAULT '0', + `c2` decimal(10,2) DEFAULT NULL, + `c3` blob, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +SELECT * FROM t1 ORDER BY c1 LIMIT 5; +c1 c2 c3 c5 +1 2.00 b1b1b1b1b1b1b1b1b1b1 NULL +2 4.00 b1b1b1b1b1b1b1b1b1b1 NULL +3 6.00 0000-00-00 00:00:00 NULL +4 8.00 0000-00-00 00:00:00 NULL +5 10.00 0000-00-00 00:00:00 NULL +**** Show last set of ALTERs on SLAVE **** +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` double NOT NULL DEFAULT '0', + `c2` decimal(10,2) DEFAULT NULL, + `c3` blob, + `c5` double DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `t1_i` (`c2`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +SELECT * FROM t1 where c1 = 1; +c1 c2 c3 c5 +1 2.00 b1b1b1b1b1b1b1b1b1b1 NULL +DROP TABLE t1; +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +******** Create additional TABLESPACE test 2 ************** +CREATE TABLESPACE ts2 +ADD DATAFILE 'datafile03.dat' +USE LOGFILE GROUP lg1 +INITIAL_SIZE 12M +ENGINE=NDB; +ALTER TABLESPACE ts2 +ADD DATAFILE 'datafile04.dat' +INITIAL_SIZE 12M +ENGINE=NDB; +DROP DATABASE IF EXISTS tpcb; +Warnings: +Note 1008 Can't drop database 'tpcb'; database doesn't exist +CREATE DATABASE tpcb; +DROP DATABASE IF EXISTS test; +CREATE DATABASE test; +*********** Create TPCB Tables ***************** +CREATE TABLE tpcb.account +(id INT, bid INT, balance DECIMAL(10,2), +filler CHAR(255), PRIMARY KEY(id)) +TABLESPACE ts1 STORAGE DISK +ENGINE=NDB; +CREATE TABLE tpcb.branch +(bid INT, balance DECIMAL(10,2), filler VARCHAR(255), +PRIMARY KEY(bid)) +ENGINE=NDB; +CREATE TABLE tpcb.teller +(tid INT, balance DECIMAL(10,2), filler VARCHAR(255), +PRIMARY KEY(tid)) +TABLESPACE ts2 STORAGE DISK +ENGINE=NDB; +CREATE TABLE tpcb.history +(id MEDIUMINT NOT NULL AUTO_INCREMENT,aid INT, +tid INT, bid INT, amount DECIMAL(10,2), +tdate DATETIME, teller CHAR(20), uuidf LONGBLOB, +filler CHAR(80),PRIMARY KEY (id)) +TABLESPACE ts2 STORAGE DISK +ENGINE=NDB; +********* Create Procedures and Functions ************ +CREATE PROCEDURE tpcb.load() +BEGIN +DECLARE acct INT DEFAULT 1000; +DECLARE brch INT DEFAULT 100; +DECLARE tell INT DEFAULT 1000; +DECLARE tmp INT DEFAULT 100; +WHILE brch > 0 DO +SET tmp = 100; +WHILE tmp > 0 DO +INSERT INTO tpcb.account VALUES (acct, brch, 0.0, "FRESH ACCOUNT"); +SET acct = acct - 1; +SET tmp = tmp -1; +END WHILE; +INSERT INTO tpcb.branch VALUES (brch, 0.0, "FRESH BRANCH"); +SET brch = brch - 1; +END WHILE; +WHILE tell > 0 DO +INSERT INTO tpcb.teller VALUES (tell, 0.0, "FRESH TELLER"); +SET tell = tell - 1; +END WHILE; +END| +CREATE FUNCTION tpcb.account_id () RETURNS INT +BEGIN +DECLARE num INT; +DECLARE ran INT; +SELECT RAND() * 10 INTO ran; +IF (ran < 2) +THEN +SELECT RAND() * 10 INTO num; +ELSEIF (ran < 4) +THEN +SELECT RAND() * 100 INTO num; +ELSE +SELECT RAND() * 1000 INTO num; +END IF; +IF (num < 1) +THEN +RETURN 1; +END IF; +RETURN num; +END| +CREATE FUNCTION tpcb.teller_id () RETURNS INT +BEGIN +DECLARE num INT; +DECLARE ran INT; +SELECT RAND() * 10 INTO ran; +IF (ran < 2) +THEN +SELECT RAND() * 10 INTO num; +ELSEIF (ran < 5) +THEN +SELECT RAND() * 100 INTO num; +ELSE +SELECT RAND() * 1000 INTO num; +END IF; +IF (num < 1) +THEN +RETURN 1; +END IF; +RETURN num; +END| +CREATE PROCEDURE tpcb.trans() +BEGIN +DECLARE acct INT DEFAULT 0; +DECLARE brch INT DEFAULT 0; +DECLARE tell INT DEFAULT 0; +DECLARE bal DECIMAL(10,2) DEFAULT 0.0; +DECLARE amount DECIMAL(10,2) DEFAULT 1.00; +DECLARE test INT DEFAULT 0; +DECLARE bbal DECIMAL(10,2) DEFAULT 0.0; +DECLARE tbal DECIMAL(10,2) DEFAULT 0.0; +DECLARE local_uuid VARCHAR(255); +DECLARE local_user VARCHAR(255); +DECLARE local_time TIMESTAMP; +SELECT RAND() * 10 INTO test; +SELECT tpcb.account_id() INTO acct; +SELECT tpcb.teller_id() INTO tell; +SELECT account.balance INTO bal FROM tpcb.account WHERE id = acct; +SELECT account.bid INTO brch FROM tpcb.account WHERE id = acct; +SELECT teller.balance INTO tbal FROM tpcb.teller WHERE tid = tell; +SELECT branch.balance INTO bbal FROM tpcb.branch WHERE bid = brch; +IF (test < 5) +THEN +SET bal = bal + amount; +SET bbal = bbal + amount; +SET tbal = tbal + amount; +UPDATE tpcb.account SET balance = bal, filler = 'account updated' + WHERE id = acct; +UPDATE tpcb.branch SET balance = bbal, filler = 'branch updated' + WHERE bid = brch; +UPDATE tpcb.teller SET balance = tbal, filler = 'teller updated' + WHERE tid = tell; +ELSE +SET bal = bal - amount; +SET bbal = bbal - amount; +SET tbal = tbal - amount; +UPDATE tpcb.account SET balance = bal, filler = 'account updated' + WHERE id = acct; +UPDATE tpcb.branch SET balance = bbal, filler = 'branch updated' + WHERE bid = brch; +UPDATE tpcb.teller SET balance = tbal, filler = 'teller updated' + WHERE tid = tell; +END IF; +SET local_uuid=UUID(); +SET local_user=USER(); +SET local_time= NOW(); +INSERT INTO tpcb.history VALUES(NULL,acct,tell,brch,amount, local_time,local_user, +local_uuid,'completed trans'); +END| +****** TEST 2 test time ********************************* +USE tpcb; +*********** Load up the database ****************** +CALL tpcb.load(); +********** Check load master and slave ************** +SELECT COUNT(*) FROM account; +COUNT(*) +10000 +USE tpcb; +SELECT COUNT(*) FROM account; +COUNT(*) +10000 +******** Run in some transactions *************** +***** Time to try slave sync *********** +**** Must make sure slave is clean ***** +STOP SLAVE; +RESET SLAVE; +DROP PROCEDURE tpcb.load; +DROP PROCEDURE tpcb.trans; +DROP TABLE tpcb.account; +DROP TABLE tpcb.teller; +DROP TABLE tpcb.branch; +DROP TABLE tpcb.history; +DROP DATABASE tpcb; +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile.dat' +ENGINE=NDB; +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile02.dat' +ENGINE=NDB; +DROP TABLESPACE ts1 ENGINE=NDB; +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile03.dat' +ENGINE=NDB; +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile04.dat' +ENGINE=NDB; +DROP TABLESPACE ts2 ENGINE=NDB; +DROP LOGFILE GROUP lg1 ENGINE=NDB; +********** Take a backup of the Master ************* +SELECT COUNT(*) FROM history; +COUNT(*) +1000 +SELECT COUNT(*) FROM history; +COUNT(*) +2000 +CREATE TEMPORARY TABLE IF NOT EXISTS cluster.backup_info (id INT, backup_id INT) ENGINE = HEAP; +DELETE FROM cluster.backup_info; +LOAD DATA INFILE '../tmp.dat' INTO TABLE cluster.backup_info FIELDS TERMINATED BY ','; +SELECT @the_backup_id:=backup_id FROM cluster.backup_info; +@the_backup_id:=backup_id + +DROP TABLE IF EXISTS cluster.backup_info; +************ Restore the slave ************************ +CREATE DATABASE tpcb; +***** Check a few slave restore values *************** +USE tpcb; +SELECT COUNT(*) FROM account; +COUNT(*) +10000 +***** Add some more records to master ********* +***** Finsh the slave sync process ******* +* 1. * +@the_epoch:=MAX(epoch) + +* 2. * +@the_pos:=Position @the_file:=SUBSTRING_INDEX(FILE, '/', -1) + master-bin.000001 +* 3. * +* 4. * +* 5. * +START SLAVE; +**** We should be ready to continue on ************* +****** Let's make sure we match ******* +***** MASTER ******* +USE tpcb; +SELECT COUNT(*) FROM history; +COUNT(*) +4050 +****** SLAVE ******** +USE tpcb; +SELECT COUNT(*) FROM history; +COUNT(*) +4050 +*** DUMP MASTER & SLAVE FOR COMPARE ******** +*************** TEST 2 CLEANUP SECTION ******************** +DROP PROCEDURE tpcb.load; +DROP PROCEDURE tpcb.trans; +DROP TABLE tpcb.account; +DROP TABLE tpcb.teller; +DROP TABLE tpcb.branch; +DROP TABLE tpcb.history; +DROP DATABASE tpcb; +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile.dat' +ENGINE=NDB; +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile02.dat' +ENGINE=NDB; +DROP TABLESPACE ts1 ENGINE=NDB; +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile03.dat' +ENGINE=NDB; +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile04.dat' +ENGINE=NDB; +DROP TABLESPACE ts2 ENGINE=NDB; +DROP LOGFILE GROUP lg1 ENGINE=NDB; +****** Do dumps compare ************ diff --git a/mysql-test/t/rpl_ndb_dd_advance.test b/mysql-test/t/rpl_ndb_dd_advance.test new file mode 100644 index 00000000000..601ea069203 --- /dev/null +++ b/mysql-test/t/rpl_ndb_dd_advance.test @@ -0,0 +1,565 @@ +############################################### +# Author: JBM # +# Date: 2006-03-07 # +# Purpose: To test advance DD and replication # +############################################### + +#### Include Section #### +--source include/have_ndb.inc +--source include/have_binlog_format_row.inc +#--source include/have_ndb_extra.inc +--source include/master-slave.inc + +#### Test start cleanup section ##### +--disable_warnings +DROP TABLE IF EXISTS t1, t2, t3; +--enable_warnings + +###################################################### +# Requirment: Cluster DD and replication must be able# +# to handle ALTER tables and indexes and must rpl # +# to the slave correctly # +###################################################### + +## Test #1 replication of CDD and Alter Tables ##### +--echo ***** Test 1 RPL of CDD and Alter ***** +--echo ***** Test 1 setup ***** + +CREATE LOGFILE GROUP lg1 +ADD UNDOFILE 'undofile.dat' +INITIAL_SIZE 16M +UNDO_BUFFER_SIZE = 1M +ENGINE=NDB; + +ALTER LOGFILE GROUP lg1 +ADD UNDOFILE 'undofile02.dat' +INITIAL_SIZE 4M +ENGINE=NDB; + +CREATE TABLESPACE ts1 +ADD DATAFILE 'datafile.dat' +USE LOGFILE GROUP lg1 +INITIAL_SIZE 12M +ENGINE=NDB; + +ALTER TABLESPACE ts1 +ADD DATAFILE 'datafile02.dat' +INITIAL_SIZE 4M +ENGINE=NDB; + +CREATE TABLE t1 + (c1 INT NOT NULL PRIMARY KEY, + c2 INT NOT NULL, + c3 INT NOT NULL) + TABLESPACE ts1 STORAGE DISK + ENGINE=NDB; + +--echo ***** insert some data ***** + +let $j= 900; +--disable_query_log +while ($j) +{ + eval INSERT INTO t1 VALUES($j,$j*2,$j+3); + dec $j; +} +--enable_query_log + +--echo ***** Select from Master ***** + +SELECT * FROM t1 ORDER BY c1 LIMIT 5; + +--echo ***** Select from Slave ***** +--sync_slave_with_master +connection slave; +SELECT * FROM t1 ORDER BY c1 LIMIT 5; + +--disable_query_log +SELECT FILE_NAME, FILE_TYPE, TABLESPACE_NAME, LOGFILE_GROUP_NAME + FROM INFORMATION_SCHEMA.FILES + WHERE ENGINE="ndbcluster"; +--enable_query_log + +--echo **** Do First Set of ALTERs in the master table **** +connection master; +CREATE INDEX t1_i ON t1(c2, c3); +#Bug 18039 +#CREATE UNIQUE INDEX t1_i2 ON t1(c2); +ALTER TABLE t1 ADD c4 TIMESTAMP; +ALTER TABLE t1 ADD c5 DOUBLE; +ALTER TABLE t1 ADD INDEX (c5); +SHOW CREATE TABLE t1; + +--echo **** Show first set of ALTERs on SLAVE **** +--sync_slave_with_master +connection slave; +SHOW CREATE TABLE t1; + +--echo **** Second set of alters test 1 **** + +connection master; +ALTER TABLE t1 RENAME t2; +ALTER TABLE t2 DROP INDEX c5; +CREATE TABLE t1(c1 INT)ENGINE=NDB; +INSERT INTO t1 VALUES(1); +DROP TABLE t1; +ALTER TABLE t2 RENAME t1; + +--echo **** Show second set of ALTERs on MASTER **** + +SHOW CREATE TABLE t1; + +--echo **** Show second set of ALTERs on SLAVE **** +--sync_slave_with_master +connection slave; +SHOW CREATE TABLE t1; + +--echo **** Third and last set of alters for test1 **** +connection master; +ALTER TABLE t1 CHANGE c1 c1 DOUBLE; +ALTER TABLE t1 CHANGE c2 c2 DECIMAL(10,2); +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t1 CHANGE c4 c4 TEXT CHARACTER SET utf8; +ALTER TABLE t1 CHANGE c4 c4 BLOB; +ALTER TABLE t1 CHANGE c4 c3 BLOB; +set @b1 = 'b1'; +set @b1 = concat(@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1,@b1); +UPDATE t1 SET c3=@b1 where c1 = 1; +UPDATE t1 SET c3=@b1 where c1 = 2; + +--echo **** Show last set of ALTERs on MASTER **** + +SHOW CREATE TABLE t1; +SELECT * FROM t1 ORDER BY c1 LIMIT 5; + +--echo **** Show last set of ALTERs on SLAVE **** +--sync_slave_with_master +connection slave; +SHOW CREATE TABLE t1; +# Bug 16498 +#SELECT * FROM t1 ORDER BY c1 LIMIT 5; +SELECT * FROM t1 where c1 = 1; + +connection master; +DROP TABLE t1; +--sync_slave_with_master +connection slave; +STOP SLAVE; +RESET SLAVE; +connection master; +RESET MASTER; +connection slave; +START SLAVE; + +################### TEST 2 TPCB for disk data ########################### +# Requirement: To have Stored Procedures and Functions that are used to # +# populate and post transactions to the data base using CDD that span # +# 2 tables spaces and also use a memory only cluster tables. In addition# +# The slave is to be stopped, cleaned and restored and synced with the # +# Master cluster # +######################################################################### + +--echo ******** Create additional TABLESPACE test 2 ************** + +connection master; +CREATE TABLESPACE ts2 +ADD DATAFILE 'datafile03.dat' +USE LOGFILE GROUP lg1 +INITIAL_SIZE 12M +ENGINE=NDB; + +ALTER TABLESPACE ts2 +ADD DATAFILE 'datafile04.dat' +INITIAL_SIZE 12M +ENGINE=NDB; + +###### CLEAN UP SECTION ############## +DROP DATABASE IF EXISTS tpcb; +CREATE DATABASE tpcb; +DROP DATABASE IF EXISTS test; +CREATE DATABASE test; +######## Creat Table Section ######### +--echo *********** Create TPCB Tables ***************** +CREATE TABLE tpcb.account + (id INT, bid INT, balance DECIMAL(10,2), + filler CHAR(255), PRIMARY KEY(id)) + TABLESPACE ts1 STORAGE DISK + ENGINE=NDB; + +CREATE TABLE tpcb.branch + (bid INT, balance DECIMAL(10,2), filler VARCHAR(255), + PRIMARY KEY(bid)) + ENGINE=NDB; + +CREATE TABLE tpcb.teller + (tid INT, balance DECIMAL(10,2), filler VARCHAR(255), + PRIMARY KEY(tid)) + TABLESPACE ts2 STORAGE DISK + ENGINE=NDB; + +CREATE TABLE tpcb.history + (id MEDIUMINT NOT NULL AUTO_INCREMENT,aid INT, + tid INT, bid INT, amount DECIMAL(10,2), + tdate DATETIME, teller CHAR(20), uuidf LONGBLOB, + filler CHAR(80),PRIMARY KEY (id)) + TABLESPACE ts2 STORAGE DISK + ENGINE=NDB; + +--echo ********* Create Procedures and Functions ************ +delimiter |; +CREATE PROCEDURE tpcb.load() +BEGIN + DECLARE acct INT DEFAULT 1000; + DECLARE brch INT DEFAULT 100; + DECLARE tell INT DEFAULT 1000; + DECLARE tmp INT DEFAULT 100; + WHILE brch > 0 DO + SET tmp = 100; + WHILE tmp > 0 DO + INSERT INTO tpcb.account VALUES (acct, brch, 0.0, "FRESH ACCOUNT"); + SET acct = acct - 1; + SET tmp = tmp -1; + END WHILE; + INSERT INTO tpcb.branch VALUES (brch, 0.0, "FRESH BRANCH"); + SET brch = brch - 1; + END WHILE; + WHILE tell > 0 DO + INSERT INTO tpcb.teller VALUES (tell, 0.0, "FRESH TELLER"); + SET tell = tell - 1; + END WHILE; +END| + +CREATE FUNCTION tpcb.account_id () RETURNS INT +BEGIN + DECLARE num INT; + DECLARE ran INT; + SELECT RAND() * 10 INTO ran; + IF (ran < 2) + THEN + SELECT RAND() * 10 INTO num; + ELSEIF (ran < 4) + THEN + SELECT RAND() * 100 INTO num; + ELSE + SELECT RAND() * 1000 INTO num; + END IF; + IF (num < 1) + THEN + RETURN 1; + END IF; + RETURN num; +END| + +CREATE FUNCTION tpcb.teller_id () RETURNS INT +BEGIN + DECLARE num INT; + DECLARE ran INT; + SELECT RAND() * 10 INTO ran; + IF (ran < 2) + THEN + SELECT RAND() * 10 INTO num; + ELSEIF (ran < 5) + THEN + SELECT RAND() * 100 INTO num; + ELSE + SELECT RAND() * 1000 INTO num; + END IF; + IF (num < 1) + THEN + RETURN 1; + END IF; + RETURN num; +END| + +CREATE PROCEDURE tpcb.trans() +BEGIN + DECLARE acct INT DEFAULT 0; + DECLARE brch INT DEFAULT 0; + DECLARE tell INT DEFAULT 0; + DECLARE bal DECIMAL(10,2) DEFAULT 0.0; + DECLARE amount DECIMAL(10,2) DEFAULT 1.00; + DECLARE test INT DEFAULT 0; + DECLARE bbal DECIMAL(10,2) DEFAULT 0.0; + DECLARE tbal DECIMAL(10,2) DEFAULT 0.0; + DECLARE local_uuid VARCHAR(255); + DECLARE local_user VARCHAR(255); + DECLARE local_time TIMESTAMP; + + SELECT RAND() * 10 INTO test; + SELECT tpcb.account_id() INTO acct; + SELECT tpcb.teller_id() INTO tell; + + SELECT account.balance INTO bal FROM tpcb.account WHERE id = acct; + SELECT account.bid INTO brch FROM tpcb.account WHERE id = acct; + SELECT teller.balance INTO tbal FROM tpcb.teller WHERE tid = tell; + SELECT branch.balance INTO bbal FROM tpcb.branch WHERE bid = brch; + + IF (test < 5) + THEN + SET bal = bal + amount; + SET bbal = bbal + amount; + SET tbal = tbal + amount; + UPDATE tpcb.account SET balance = bal, filler = 'account updated' + WHERE id = acct; + UPDATE tpcb.branch SET balance = bbal, filler = 'branch updated' + WHERE bid = brch; + UPDATE tpcb.teller SET balance = tbal, filler = 'teller updated' + WHERE tid = tell; + ELSE + SET bal = bal - amount; + SET bbal = bbal - amount; + SET tbal = tbal - amount; + UPDATE tpcb.account SET balance = bal, filler = 'account updated' + WHERE id = acct; + UPDATE tpcb.branch SET balance = bbal, filler = 'branch updated' + WHERE bid = brch; + UPDATE tpcb.teller SET balance = tbal, filler = 'teller updated' + WHERE tid = tell; + END IF; + + SET local_uuid=UUID(); + SET local_user=USER(); + SET local_time= NOW(); + INSERT INTO tpcb.history VALUES(NULL,acct,tell,brch,amount, local_time,local_user, + local_uuid,'completed trans'); +END| +delimiter ;| + +--echo ****** TEST 2 test time ********************************* +USE tpcb; + +--echo *********** Load up the database ****************** +CALL tpcb.load(); + +--echo ********** Check load master and slave ************** +SELECT COUNT(*) FROM account; +--sync_slave_with_master +connection slave; +USE tpcb; +SELECT COUNT(*) FROM account; + +--echo ******** Run in some transactions *************** + +connection master; +let $j= 1000; +--disable_query_log +while ($j) +{ + CALL tpcb.trans(); + dec $j; +} +--enable_query_log + +--echo ***** Time to try slave sync *********** +--echo **** Must make sure slave is clean ***** +--connection slave +STOP SLAVE; +RESET SLAVE; +DROP PROCEDURE tpcb.load; +DROP PROCEDURE tpcb.trans; +DROP TABLE tpcb.account; +DROP TABLE tpcb.teller; +DROP TABLE tpcb.branch; +DROP TABLE tpcb.history; +DROP DATABASE tpcb; + +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile.dat' +ENGINE=NDB; + +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile02.dat' +ENGINE=NDB; + +DROP TABLESPACE ts1 ENGINE=NDB; + +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile03.dat' +ENGINE=NDB; + +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile04.dat' +ENGINE=NDB; + +DROP TABLESPACE ts2 ENGINE=NDB; + +DROP LOGFILE GROUP lg1 ENGINE=NDB; + +--echo ********** Take a backup of the Master ************* +connection master; + +SELECT COUNT(*) FROM history; + +let $j= 1000; +--disable_query_log +while ($j) +{ + CALL tpcb.trans(); + dec $j; +} +--enable_query_log + +SELECT COUNT(*) FROM history; + +#RESET MASTER; +--exec $NDB_MGM --no-defaults --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -e "start backup" >> $NDB_TOOLS_OUTPUT + +--exec $NDB_TOOLS_DIR/ndb_select_all --ndb-connectstring="localhost:$NDBCLUSTER_PORT" -d sys --delimiter=',' SYSTAB_0 | grep 520093696 > $MYSQLTEST_VARDIR/tmp.dat + +CREATE TEMPORARY TABLE IF NOT EXISTS cluster.backup_info (id INT, backup_id INT) ENGINE = HEAP; + +DELETE FROM cluster.backup_info; + +LOAD DATA INFILE '../tmp.dat' INTO TABLE cluster.backup_info FIELDS TERMINATED BY ','; + +--replace_column 1 + +SELECT @the_backup_id:=backup_id FROM cluster.backup_info; + +let the_backup_id=`select @the_backup_id`; + +DROP TABLE IF EXISTS cluster.backup_info; +#RESET MASTER; + +--echo ************ Restore the slave ************************ +connection slave; +CREATE DATABASE tpcb; +--source include/ndb_restore_slave_eoption.inc + +--echo ***** Check a few slave restore values *************** +connection slave; +USE tpcb; +SELECT COUNT(*) FROM account; + +--echo ***** Add some more records to master ********* +connection master; +let $j= 1000; +--disable_query_log +while ($j) +{ + CALL tpcb.trans(); + dec $j; +} +--enable_query_log + +# +# now setup replication to continue from last epoch +# 1. get apply_status epoch from slave +# 2. get corresponding _next_ binlog postition from master +# 3. change master on slave +# 4. add some transaction for slave to process +# 5. start the replication + +--echo ***** Finsh the slave sync process ******* +# 1. +--echo * 1. * +connection slave; +--disable_query_log +--replace_column 1 +SELECT @the_epoch:=MAX(epoch) FROM cluster.apply_status; +--let $the_epoch= `select @the_epoch` + +# 2. +--echo * 2. * +connection master; +--replace_column 1 +eval SELECT @the_pos:=Position,@the_file:=SUBSTRING_INDEX(FILE, '/', -1) + FROM cluster.binlog_index WHERE epoch > $the_epoch ORDER BY epoch ASC LIMIT 1; +--let $the_pos= `SELECT @the_pos` +--let $the_file= `SELECT @the_file` + +# 3. +--echo * 3. * +connection slave; +eval CHANGE MASTER TO + master_log_file = '$the_file', + master_log_pos = $the_pos; +--enable_query_log + +# 4. +--echo * 4. * +connection master; +let $j= 1000; +--disable_query_log +while ($j) +{ + CALL tpcb.trans(); + dec $j; +} +--enable_query_log + +# 5. +--echo * 5. * +connection slave; +START SLAVE; + +--echo **** We should be ready to continue on ************* + +connection master; +let $j= 50; +--disable_query_log +while ($j) +{ + CALL tpcb.trans(); + dec $j; +} +--enable_query_log + +--echo ****** Let's make sure we match ******* +--echo ***** MASTER ******* +USE tpcb; +SELECT COUNT(*) FROM history; + +--echo ****** SLAVE ******** +--sync_slave_with_master +connection slave; +USE tpcb; +SELECT COUNT(*) FROM history; + +--echo *** DUMP MASTER & SLAVE FOR COMPARE ******** + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert tpcb account teller branch history > $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_M.sql + +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert tpcb account teller branch history > $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_S.sql + +--echo *************** TEST 2 CLEANUP SECTION ******************** +connection master; +DROP PROCEDURE tpcb.load; +DROP PROCEDURE tpcb.trans; +DROP TABLE tpcb.account; +DROP TABLE tpcb.teller; +DROP TABLE tpcb.branch; +DROP TABLE tpcb.history; +DROP DATABASE tpcb; + +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile.dat' +ENGINE=NDB; + +ALTER TABLESPACE ts1 +DROP DATAFILE 'datafile02.dat' +ENGINE=NDB; + +DROP TABLESPACE ts1 ENGINE=NDB; + +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile03.dat' +ENGINE=NDB; + +ALTER TABLESPACE ts2 +DROP DATAFILE 'datafile04.dat' +ENGINE=NDB; + +DROP TABLESPACE ts2 ENGINE=NDB; + +DROP LOGFILE GROUP lg1 ENGINE=NDB; + +--sync_slave_with_master + +connection master; + +--echo ****** Do dumps compare ************ + +--exec diff $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_M.sql $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_S.sql + +# End 5.1 test case From aca1b9d766e69723b5b360ebc4725e943caa6a95 Mon Sep 17 00:00:00 2001 From: "jmiller@mysql.com" <> Date: Thu, 9 Mar 2006 17:14:33 +0100 Subject: [PATCH 09/12] rpl_ndb_dd_advance.result: Updated results rpl_ndb_dd_advance.test: Updated test case from comments in Tomas's review Changes bug number comment --- mysql-test/r/rpl_ndb_dd_advance.result | 2 +- mysql-test/t/rpl_ndb_dd_advance.test | 43 +++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/rpl_ndb_dd_advance.result b/mysql-test/r/rpl_ndb_dd_advance.result index 64820b6f9e5..fd4b80d2066 100644 --- a/mysql-test/r/rpl_ndb_dd_advance.result +++ b/mysql-test/r/rpl_ndb_dd_advance.result @@ -49,8 +49,8 @@ c1 c2 c3 4 8 7 5 10 8 FILE_NAME FILE_TYPE TABLESPACE_NAME LOGFILE_GROUP_NAME -datafile02.dat DATAFILE ts1 lg1 datafile.dat DATAFILE ts1 lg1 +datafile02.dat DATAFILE ts1 lg1 undofile.dat UNDO LOG ts1 lg1 undofile02.dat UNDO LOG ts1 lg1 **** Do First Set of ALTERs in the master table **** diff --git a/mysql-test/t/rpl_ndb_dd_advance.test b/mysql-test/t/rpl_ndb_dd_advance.test index 601ea069203..c3ef6a51228 100644 --- a/mysql-test/t/rpl_ndb_dd_advance.test +++ b/mysql-test/t/rpl_ndb_dd_advance.test @@ -74,13 +74,24 @@ SELECT * FROM t1 ORDER BY c1 LIMIT 5; connection slave; SELECT * FROM t1 ORDER BY c1 LIMIT 5; +################################### +# Just to some File Schema check # +################################### + --disable_query_log -SELECT FILE_NAME, FILE_TYPE, TABLESPACE_NAME, LOGFILE_GROUP_NAME +SELECT DISTINCT FILE_NAME, FILE_TYPE, TABLESPACE_NAME, LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES - WHERE ENGINE="ndbcluster"; + WHERE ENGINE="ndbcluster" ORDER BY FILE_NAME; --enable_query_log --echo **** Do First Set of ALTERs in the master table **** +################################################### +# On this first set of alters I expect: +# 1. To be able to create and index on 2 columns +# 2. To be able to create a unique index +# 3. To be able to add two columns and have +# it all replicated correctly to the slave cluster. +################################################### connection master; CREATE INDEX t1_i ON t1(c2, c3); #Bug 18039 @@ -96,7 +107,17 @@ connection slave; SHOW CREATE TABLE t1; --echo **** Second set of alters test 1 **** - +############################################ +# With this next set of alters we have had +# Some issues with renames of tables. So this +# test renames our main table, drop and index off +# of it, creates another table with then name +# of the orginal table, inserts a row, drops +# the table and renames the orginal table back. +# I want to make sure that 1) the cluster does +# okay with this and 2) that it is replicated +# correctly. +############################################# connection master; ALTER TABLE t1 RENAME t2; ALTER TABLE t2 DROP INDEX c5; @@ -115,6 +136,15 @@ connection slave; SHOW CREATE TABLE t1; --echo **** Third and last set of alters for test1 **** +######################################################### +# In this last set of alters, we are messing with the +# cluster ability to rebuild indexes, drop a column that make up +# an index with another column and change types several times in +# a row. I have choosen the BLOB as it seems to have had many +# issues in this release. I want to make sure that the cluster +# deals with these radical changes and that the replication to +# the slave cluster is dones correctly. +########################################################### connection master; ALTER TABLE t1 CHANGE c1 c1 DOUBLE; ALTER TABLE t1 CHANGE c2 c2 DECIMAL(10,2); @@ -136,7 +166,7 @@ SELECT * FROM t1 ORDER BY c1 LIMIT 5; --sync_slave_with_master connection slave; SHOW CREATE TABLE t1; -# Bug 16498 +# Bug 18094 #SELECT * FROM t1 ORDER BY c1 LIMIT 5; SELECT * FROM t1 where c1 = 1; @@ -562,4 +592,9 @@ connection master; --exec diff $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_M.sql $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_S.sql +## Note: Ths files should only get removed, if the above diff succeeds. + +--exec rm $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_M.sql +--exec rm $MYSQLTEST_VARDIR/tmp/RPL_DD_ADV_S.sql + # End 5.1 test case From 6e07985293d0a26e14dec728414394d7d9e7ea2b Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Thu, 9 Mar 2006 17:16:04 +0100 Subject: [PATCH 10/12] ndb - bug#18067 bug#18075 closes these bugs --- mysql-test/r/rpl_ndb_blob.result | 101 ++++++++++++++----------- mysql-test/t/rpl_ndb_blob.test | 61 +++++++++++++-- storage/ndb/include/ndbapi/NdbBlob.hpp | 1 + storage/ndb/src/ndbapi/NdbBlob.cpp | 12 +++ 4 files changed, 123 insertions(+), 52 deletions(-) diff --git a/mysql-test/r/rpl_ndb_blob.result b/mysql-test/r/rpl_ndb_blob.result index 1419875c743..c11de8c27e3 100644 --- a/mysql-test/r/rpl_ndb_blob.result +++ b/mysql-test/r/rpl_ndb_blob.result @@ -78,49 +78,58 @@ S 7 a6bae0cfe6b45ff8c3c12d2ce577a1cd3931190f 107 39ee712b4b9e47f2cf3ba7c9790b2bf S 8 e139adcb7b2974ee7ff227fd405709e5cb7c896c 108 ba8073b0e1a281d4111bd2d82c7722b01574c00b NULL S 9 1fc5168fe4be566b17b658d94e7813f0b5032cdb NULL NULL NULL drop table t1; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 102 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 102 Query 1 239 use `test`; create table t1 ( -a int not null primary key, -b text not null -) engine=ndb -master-bin.000001 239 Query 1 303 BEGIN -master-bin.000001 303 Table_map 1 53 cluster.apply_status -master-bin.000001 356 Write_rows 1 95 -master-bin.000001 398 Table_map 1 135 test.t1 -master-bin.000001 438 Write_rows 1 806 -master-bin.000001 1109 Write_rows 1 9841 -master-bin.000001 10144 Query 1 10209 COMMIT -master-bin.000001 10209 Query 1 10273 BEGIN -master-bin.000001 10273 Table_map 1 53 cluster.apply_status -master-bin.000001 10326 Write_rows 1 95 -master-bin.000001 10368 Query 1 10433 COMMIT -master-bin.000001 10433 Query 1 10509 use `test`; drop table t1 -master-bin.000001 10509 Query 1 10684 use `test`; create table t1 ( -a int not null primary key, -b text not null, -c int, -d longblob, -e tinyblob -) engine=ndbcluster -master-bin.000001 10684 Query 1 10748 BEGIN -master-bin.000001 10748 Table_map 1 53 cluster.apply_status -master-bin.000001 10801 Write_rows 1 95 -master-bin.000001 10843 Table_map 1 138 test.t1 -master-bin.000001 10886 Write_rows 1 48922 -master-bin.000001 59670 Write_rows 1 124424 -master-bin.000001 135172 Write_rows 1 124530 -master-bin.000001 135278 Write_rows 1 205949 -master-bin.000001 216697 Write_rows 1 224233 -master-bin.000001 234981 Write_rows 1 227511 -master-bin.000001 238259 Write_rows 1 242379 -master-bin.000001 253127 Write_rows 1 254075 -master-bin.000001 264823 Write_rows 1 304323 -master-bin.000001 315071 Write_rows 1 330415 -master-bin.000001 341163 Query 1 341228 COMMIT -master-bin.000001 341228 Query 1 341292 BEGIN -master-bin.000001 341292 Table_map 1 53 cluster.apply_status -master-bin.000001 341345 Write_rows 1 95 -master-bin.000001 341387 Query 1 341452 COMMIT -master-bin.000001 341452 Query 1 341528 use `test`; drop table t1 +CREATE TABLE IF NOT EXISTS t1 ( +db VARBINARY(63) NOT NULL, +name VARBINARY(63) NOT NULL, +slock BINARY(32) NOT NULL, +query BLOB NOT NULL, +node_id INT UNSIGNED NOT NULL, +epoch BIGINT UNSIGNED NOT NULL, +id INT UNSIGNED NOT NULL, +version INT UNSIGNED NOT NULL, +type INT UNSIGNED NOT NULL, +PRIMARY KEY USING HASH (db,name)) +ENGINE=NDB; +insert into t1 values ('test','t1', +'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('test','t2', +'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('test','t3', +'ghi',repeat(@s2,1000),31,32,33,34,35); +insert into t1 values ('testtttttttttt','t1', +'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('testttttttttttt','t1', +'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('testtttttttttttt','t1', +'ghi',repeat(@s2,1000),31,32,33,34,35); +insert into t1 values ('t','t11111111111', +'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('t','t111111111111', +'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('t','t1111111111111', +'ghi',repeat(@s2,1000),31,32,33,34,35); +select 'M', db, name, sha1(query), node_id, epoch, id, version, type +from t1 order by db, name; +M db name sha1(query) node_id epoch id version type +M t t11111111111 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +M t t111111111111 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +M t t1111111111111 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +M test t1 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +M test t2 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +M test t3 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +M testtttttttttt t1 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +M testttttttttttt t1 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +M testtttttttttttt t1 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +select 'S', db, name, sha1(query), node_id, epoch, id, version, type +from t1 order by db, name; +S db name sha1(query) node_id epoch id version type +S t t11111111111 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +S t t111111111111 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +S t t1111111111111 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +S test t1 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +S test t2 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +S test t3 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +S testtttttttttt t1 8fc937d303ee7e4795c0b964d4066cedd6d74cfd 11 12 13 14 15 +S testttttttttttt t1 a5229e9f8977bc99afc3b3627c56f083e97e01bd 21 22 23 24 25 +S testtttttttttttt t1 0820e6ad3eeb06ea60e5e04d0bfe36f286b91098 31 32 33 34 35 +drop table t1; diff --git a/mysql-test/t/rpl_ndb_blob.test b/mysql-test/t/rpl_ndb_blob.test index c31b629b9f8..94af986b222 100644 --- a/mysql-test/t/rpl_ndb_blob.test +++ b/mysql-test/t/rpl_ndb_blob.test @@ -83,11 +83,60 @@ from t1 order by a; drop table t1; --sync_slave_with_master -# -# view the binlog -# +# table with varsize key (future cluster/schema) + +# sql/ha_ndbcluster_binlog.cc +--connection master +CREATE TABLE IF NOT EXISTS t1 ( + db VARBINARY(63) NOT NULL, + name VARBINARY(63) NOT NULL, + slock BINARY(32) NOT NULL, + query BLOB NOT NULL, + node_id INT UNSIGNED NOT NULL, + epoch BIGINT UNSIGNED NOT NULL, + id INT UNSIGNED NOT NULL, + version INT UNSIGNED NOT NULL, + type INT UNSIGNED NOT NULL, + PRIMARY KEY USING HASH (db,name)) +ENGINE=NDB; + +insert into t1 values ('test','t1', + 'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('test','t2', + 'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('test','t3', + 'ghi',repeat(@s2,1000),31,32,33,34,35); +insert into t1 values ('testtttttttttt','t1', + 'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('testttttttttttt','t1', + 'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('testtttttttttttt','t1', + 'ghi',repeat(@s2,1000),31,32,33,34,35); +insert into t1 values ('t','t11111111111', + 'abc',repeat(@s0,10), 11,12,13,14,15); +insert into t1 values ('t','t111111111111', + 'def',repeat(@s1,100), 21,22,23,24,25); +insert into t1 values ('t','t1111111111111', + 'ghi',repeat(@s2,1000),31,32,33,34,35); + +select 'M', db, name, sha1(query), node_id, epoch, id, version, type +from t1 order by db, name; + +--sync_slave_with_master +--sleep 5 +--connection slave +select 'S', db, name, sha1(query), node_id, epoch, id, version, type +from t1 order by db, name; --connection master -let $VERSION=`select version()`; ---replace_result $VERSION VERSION -show binlog events; +drop table t1; +--sync_slave_with_master + +# +# view the binlog - not deterministic (mats) +# + +#--connection master +#let $VERSION=`select version()`; +#--replace_result $VERSION VERSION +#show binlog events; diff --git a/storage/ndb/include/ndbapi/NdbBlob.hpp b/storage/ndb/include/ndbapi/NdbBlob.hpp index 9ae0ba6f023..13bbfa59e50 100644 --- a/storage/ndb/include/ndbapi/NdbBlob.hpp +++ b/storage/ndb/include/ndbapi/NdbBlob.hpp @@ -288,6 +288,7 @@ private: Buf(); ~Buf(); void alloc(unsigned n); + void zerorest(); void copyfrom(const Buf& src); }; Buf theKeyBuf; diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 680f9e5c70e..5fbfd6f5111 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -307,6 +307,13 @@ NdbBlob::Buf::alloc(unsigned n) #endif } +void +NdbBlob::Buf::zerorest() +{ + assert(size <= maxsize); + memset(data + size, 0, maxsize - size); +} + void NdbBlob::Buf::copyfrom(const NdbBlob::Buf& src) { @@ -441,6 +448,7 @@ NdbBlob::packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf) assert(4 * pos == srcBuf.size); assert(4 * pack_pos <= thePackKeyBuf.maxsize); thePackKeyBuf.size = 4 * pack_pos; + thePackKeyBuf.zerorest(); DBUG_RETURN(0); } @@ -1316,6 +1324,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl DBUG_RETURN(-1); } thePackKeyBuf.size = 4 * size; + thePackKeyBuf.zerorest(); if (unpackKeyValue(theTable, theKeyBuf) == -1) DBUG_RETURN(-1); } @@ -1328,6 +1337,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl DBUG_RETURN(-1); } thePackKeyBuf.size = 4 * size; + thePackKeyBuf.zerorest(); if (unpackKeyValue(theAccessTable, theAccessKeyBuf) == -1) DBUG_RETURN(-1); } @@ -1634,6 +1644,7 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) // copy key from first blob theKeyBuf.copyfrom(tFirstBlob->theKeyBuf); thePackKeyBuf.copyfrom(tFirstBlob->thePackKeyBuf); + thePackKeyBuf.zerorest(); } } if (isReadOp()) { @@ -1795,6 +1806,7 @@ NdbBlob::atNextResult() DBUG_RETURN(-1); } thePackKeyBuf.size = 4 * size; + thePackKeyBuf.zerorest(); if (unpackKeyValue(theTable, theKeyBuf) == -1) DBUG_RETURN(-1); } From eabdcb34baddf435606a4c5e30db4195bec89ba2 Mon Sep 17 00:00:00 2001 From: "jmiller@mysql.com" <> Date: Thu, 9 Mar 2006 17:19:39 +0100 Subject: [PATCH 11/12] Cleanup --- mysql-test/t/disabled.def | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 9bd7a42e8de..0751c07847c 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -9,10 +9,10 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -#ndb_alter_table_row : sometimes wrong error 1015!=1046 events_bugs : test case unstable (race conditions). andrey will fix events_stress : test case unstable. andrey will fix events : test case unstable. andrey will fix +#ndb_alter_table_row : sometimes wrong error 1015!=1046 ndb_autodiscover : Needs to be fixed w.r.t binlog ndb_autodiscover2 : Needs to be fixed w.r.t binlog ndb_binlog_basic : Results are not deterministic, Tomas will fix @@ -33,9 +33,9 @@ rpl_ndb_insert_ignore : Bugs: #17431: INSERT IGNORE INTO returns failed: 1296 rpl_ndb_myisam2ndb : Bugs#17400: delete & update of rows in table without pk fails rpl_ndb_log : result not deterministic rpl_ndb_relay_space : Bug#16993 +rpl_ndb_multi_update2 : BUG#17738 In progress rpl_ndb_multi_update3 : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_sp007 : Bug #17290 rpl_sp : Bug#16456 rpl_until : Unstable test case, bug#15886 sp-goto : GOTO is currently is disabled - will be fixed in the future -rpl_ndb_multi_update2 : BUG#17738 In progress From c5895a96868cbfe435d4dc9e7770b16547474a0e Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 9 Mar 2006 21:00:45 +0300 Subject: [PATCH 12/12] After-merge fixes. --- mysql-test/r/trigger-grant.result | 1 + mysql-test/r/view_grant.result | 11 ++++++++--- mysql-test/t/trigger-grant.test | 5 +---- mysql-test/t/view_grant.test | 5 +++-- sql/sql_parse.cc | 11 +---------- sql/sql_show.cc | 2 +- 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result index c3bbc82ef5b..10f1e08eded 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger-grant.result @@ -135,6 +135,7 @@ SET @new_sum = 0; Warnings: Note 1449 There is no 'mysqltest_nonexs'@'localhost' registered INSERT INTO t1 VALUES(6); +ERROR HY000: There is no 'mysqltest_nonexs'@'localhost' registered SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer trg1 INSERT t1 SET @new_sum = 0 BEFORE NULL mysqltest_inv@localhost diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 8da8805b14b..928e3635ec6 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -522,11 +522,16 @@ use test; drop user mysqltest_1@localhost; drop database mysqltest; create definer=some_user@`` sql security invoker view v1 as select 1; -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 no 'some_user'@'' registered +create definer=some_user@localhost sql security invoker view v2 as select 1; Warnings: 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` +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` +show create view v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select 1 AS `1` drop view v1; +drop view v2; diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test index e79abf1b826..67aec1496dd 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger-grant.test @@ -317,10 +317,7 @@ CREATE DEFINER='mysqltest_nonexs'@'localhost' # Check that trg2 will not be activated. -# --error ER_SPECIFIC_ACCESS_DENIED_ERROR -# -# TODO: Due to the BUG#13198(SP executes if definer does not exist) the -# following statement does not fail as it should. +--error ER_NO_SUCH_USER INSERT INTO t1 VALUES(6); # diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index a3a8aa6a4c3..504c4892808 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -712,10 +712,11 @@ connection default; # # DEFINER information check # --- 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; +create definer=some_user@localhost sql security invoker view v2 as select 1; show create view v1; +show create view v2; drop view v1; +drop view v2; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4984443a01d..d48a884173f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7475,8 +7475,7 @@ LEX_USER *create_default_definer(THD *thd) /* - Create definer with the given user and host names. Also check that the user - and host names satisfy definers requirements. + Create definer with the given user and host names. SYNOPSIS create_definer() @@ -7494,14 +7493,6 @@ 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)))) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4eec1a3175b..43b7c494246 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -831,7 +831,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) int get_quote_char_for_identifier(THD *thd, const char *name, uint length) { - if (!length || + if (length && !is_keyword(name,length) && !require_quotes(name, length) && !(thd->options & OPTION_QUOTE_SHOW_CREATE))