MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:February 10 2006 11:21am
Subject:bk commit into 5.0 tree (anozdrin:1.2031) BUG#16266
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2031 06/02/10 14:21:07 anozdrin@stripped +8 -0
  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/std_data/bug16266.000001
    1.1 06/02/10 14:21:03 anozdrin@stripped +13 -0
    A new binlog file for testing a patch for BUG#16266.

  mysql-test/std_data/bug16266.000001
    1.0 06/02/10 14:21:03 anozdrin@stripped +0 -0
    BitKeeper file /mnt/hda4/home/alik/MySQL/devel/5.0-bug16266/mysql-test/std_data/bug16266.000001

  sql/sql_yacc.yy
    1.448 06/02/10 14:21:02 anozdrin@stripped +10 -22
    Extended support of non-SUID triggers.

  sql/sql_view.cc
    1.81 06/02/10 14:21:02 anozdrin@stripped +19 -2
    Initialize LEX::definer if DEFINER-clause is missing.

  sql/sql_trigger.cc
    1.42 06/02/10 14:21:02 anozdrin@stripped +80 -24
    Extend support of non-SUID triggers.

  sql/sql_parse.cc
    1.524 06/02/10 14:21:02 anozdrin@stripped +29 -1
    Add a utility operation to be used from sql_yacc.yy.

  sql/mysql_priv.h
    1.373 06/02/10 14:21:02 anozdrin@stripped +1 -0
    Added an utility operation to be used from sql_yacc.yy.

  mysql-test/t/rpl_trigger.test
    1.5 06/02/10 14:21:02 anozdrin@stripped +71 -0
    Added the test case for BUG#16266.

  mysql-test/r/rpl_trigger.result
    1.4 06/02/10 14:21:02 anozdrin@stripped +35 -0
    Updated the result file with the results of the test for BUG#16266.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	anozdrin
# Host:	booka.home
# Root:	/mnt/hda4/home/alik/MySQL/devel/5.0-bug16266

--- 1.372/sql/mysql_priv.h	2005-12-27 12:30:49 +03:00
+++ 1.373/sql/mysql_priv.h	2006-02-10 14:21:02 +03:00
@@ -530,6 +530,7 @@
                            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 {

--- 1.523/sql/sql_parse.cc	2006-01-11 02:10:54 +03:00
+++ 1.524/sql/sql_parse.cc	2006-02-10 14:21:02 +03:00
@@ -7218,6 +7218,34 @@
 
 
 /*
+  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_STRING, 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.
 
@@ -7229,7 +7257,7 @@
 
   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.
 */
 

--- 1.447/sql/sql_yacc.yy	2006-01-13 14:30:19 +03:00
+++ 1.448/sql/sql_yacc.yy	2006-02-10 14:21:02 +03:00
@@ -8906,37 +8906,25 @@
 definer:
 	get_definer
 	{
-	  THD *thd= YYTHD;
-	  
-	  if (! (thd->lex->definer= create_definer(thd, &$1->user, &$1->host)))
-	    YYABORT;
+	  YYTHD->lex->definer= $1;
 	}
 	;
 
 get_definer:
-	opt_current_definer
+	/* empty */
 	{
-	  THD *thd= YYTHD;
-          
-	  if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
-	    YYABORT;
-
-	  if (get_default_definer(thd, $$))
-	    YYABORT;
+          $$= 0;
+	}
+	| DEFINER_SYM EQ CURRENT_USER optional_braces
+	{
+          if (! ($$= 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 (!($$= create_definer(YYTHD, &$3, &$5)))
+            YYABORT;
 	}
-	;
-
-opt_current_definer:
-	/* empty */
-	| DEFINER_SYM EQ CURRENT_USER optional_braces
 	;
 
 /**************************************************************************
--- New file ---
+++ mysql-test/std_data/bug16266.000001	06/02/10 14:21:03

--- 1.80/sql/sql_view.cc	2005-12-02 22:19:21 +03:00
+++ 1.81/sql/sql_view.cc	2006-02-10 14:21:02 +03:00
@@ -209,6 +209,13 @@
     sp_cache_invalidate();
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
+  if (!lex->definer && /* DEFINER-clause is missing. */
+      !(lex->definer= create_default_definer(thd)))
+  {
+    res= TRUE;
+    goto err;
+  }
+    
   /*
     check definer of view:
       - same as current user
@@ -666,8 +673,18 @@
     lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
   }
   view->algorithm= lex->create_view_algorithm;
-  view->definer.user= lex->definer->user;
-  view->definer.host= lex->definer->host;
+  if (lex->definer)
+  {
+    view->definer.user= lex->definer->user;
+    view->definer.host= lex->definer->host;
+  }
+  else
+  {
+    /* DEFINER-clause is missing. */
+
+    if (!get_default_definer(thd, &view->definer))
+      DBUG_RETURN(-1);
+  }
   view->view_suid= lex->create_view_suid;
   view->with_check= lex->create_view_check;
   if ((view->updatable_view= (can_be_merged &&

--- 1.41/sql/sql_trigger.cc	2006-01-11 02:07:35 +03:00
+++ 1.42/sql/sql_trigger.cc	2006-02-10 14:21:02 +03:00
@@ -265,7 +265,17 @@
         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);
       }
 
@@ -290,17 +300,30 @@
                      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
@@ -337,12 +360,26 @@
     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.
+
+      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.
 
-  DBUG_ASSERT(lex->definer);
+      Otherwise, we should use CURRENT_USER() as definer.
+    */
+
+    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
@@ -350,10 +387,11 @@
     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))
     {
@@ -442,8 +480,8 @@
   *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,
@@ -454,12 +492,30 @@
   }
 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
-  *definer_user= lex->definer->user;
-  *definer_host= lex->definer->host;
+  if (lex->definer)
+  {
+    /* SUID trigger. */
+
+    *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;
+    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,

--- 1.3/mysql-test/r/rpl_trigger.result	2005-12-11 17:06:27 +03:00
+++ 1.4/mysql-test/r/rpl_trigger.result	2006-02-10 14:21:02 +03:00
@@ -134,3 +134,38 @@
 use test;
 drop table t1,t2;
 drop database other;
+STOP SLAVE;
+FLUSH LOGS;
+RESET SLAVE;
+START SLAVE;
+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;
+SHOW TABLES;
+Tables_in_test
+SHOW TRIGGERS;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer

--- 1.4/mysql-test/t/rpl_trigger.test	2005-12-11 17:06:27 +03:00
+++ 1.5/mysql-test/t/rpl_trigger.test	2006-02-10 14:21:02 +03:00
@@ -162,6 +162,77 @@
 drop table t1,t2;
 drop database other;
 
+
+#
+# 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 std_data/bug16266.000001 var/log/master-bin.000001;
+save_master_pos;
+
+# Make the slave to replay the new binlog.
+
+connection slave;
+RESET SLAVE;
+START SLAVE;
+
+sync_with_master;
+
+# 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;
+
+# The master should be clean.
+
+connection master;
+SHOW TABLES;
+SHOW TRIGGERS;
+
+
 #
 # End of test
 #
Thread
bk commit into 5.0 tree (anozdrin:1.2031) BUG#16266Alexander Nozdrin10 Feb