List:Internals« Previous MessageNext Message »
From:Alexander Nozdrin Date:November 10 2005 7:48pm
Subject:bk commit into 5.0 tree (anozdrin:1.1962)
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.1962 05/11/10 22:48:00 anozdrin@stripped +9 -0
  Merge bk-internal.mysql.com:/home/bk/mysql-5.0
  into  mysql.com:/home/alik/MySQL/devel/5.0-wl2818

  mysql-test/r/rpl_sp.result
    1.11 05/11/10 22:47:56 anozdrin@stripped +0 -98
    Manual merge.

  sql/sql_trigger.cc
    1.32 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  sql/sql_parse.cc
    1.511 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  sql/sp.cc
    1.98 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  sql/share/errmsg.txt
    1.56 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  sql/mysql_priv.h
    1.367 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  sql/item_func.cc
    1.267 05/11/10 22:32:38 anozdrin@stripped +0 -0
    Auto merged

  mysql-test/t/mysqldump.test
    1.75 05/11/10 22:32:37 anozdrin@stripped +0 -0
    Auto merged

  mysql-test/r/mysqldump.result
    1.82 05/11/10 22:32:37 anozdrin@stripped +0 -0
    Auto merged

# 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.
# Root:	/home/alik/MySQL/devel/5.0-wl2818/RESYNC

--- 1.266/sql/item_func.cc	2005-11-10 19:50:43 +03:00
+++ 1.267/sql/item_func.cc	2005-11-10 22:32:38 +03:00
@@ -4888,7 +4888,7 @@
 
 
 /*
-  Find the function and chack access rigths to the function
+  Find the function and check access rights to the function
 
   SYNOPSIS
     find_and_check_access()

--- 1.366/sql/mysql_priv.h	2005-11-10 19:50:43 +03:00
+++ 1.367/sql/mysql_priv.h	2005-11-10 22:32:38 +03:00
@@ -522,8 +522,9 @@
 bool insert_precheck(THD *thd, TABLE_LIST *tables);
 bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                            TABLE_LIST *create_table);
-bool default_view_definer(Security_context *sctx, st_lex_user *definer);
 
+bool get_default_definer(THD *thd, LEX_USER *definer);
+LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
 
 enum enum_mysql_completiontype {
   ROLLBACK_RELEASE=-2, ROLLBACK=1,  ROLLBACK_AND_CHAIN=7,
@@ -846,6 +847,10 @@
 bool mysqld_show_column_types(THD *thd);
 bool mysqld_help (THD *thd, const char *text);
 void calc_sum_of_all_status(STATUS_VAR *to);
+
+void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
+                    const LEX_STRING *definer_host);
+
 
 /* information schema */
 extern LEX_STRING information_schema_name;

--- 1.510/sql/sql_parse.cc	2005-11-10 19:50:43 +03:00
+++ 1.511/sql/sql_parse.cc	2005-11-10 22:32:38 +03:00
@@ -5057,7 +5057,7 @@
     the given table list refers to the list for prelocking (contains tables
     of other queries). For simple queries first_not_own_table is 0.
   */
-  for (; tables != first_not_own_table; tables= tables->next_global)
+  for (; tables && tables != first_not_own_table; tables= tables->next_global)
   {
     if (tables->schema_table && 
         (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
@@ -7461,32 +7461,81 @@
   return new Item_func_not(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.
+ 
+  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)
+{
+  /* 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;
+}
+
 
 /*
-  Assign as view definer current user
+  Create definer with the given user and host names. Also check that the user
+  and host names satisfy definers requirements.
 
   SYNOPSIS
-    default_view_definer()
-    sctx		current security context
-    definer             structure where it should be assigned
+    create_definer()
+    thd         [in] thread handler
+    user_name   [in] user name
+    host_name   [in] host name
 
   RETURN
-    FALSE   OK
-    TRUE    Error
+    On success, return a valid pointer to the created and initialized
+    LEX_STRING, which contains definer information.
+    On error, return 0.
 */
 
-bool default_view_definer(Security_context *sctx, st_lex_user *definer)
+LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
 {
-  definer->user.str= sctx->priv_user;
-  definer->user.length= strlen(sctx->priv_user);
+  LEX_USER *definer;
+
+  /* Check that specified host name is valid. */
 
-  if (!*sctx->priv_host)
+  if (host_name->length == 0)
   {
-    my_error(ER_NO_VIEW_USER, MYF(0));
-    return TRUE;
+    my_error(ER_MALFORMED_DEFINER, MYF(0));
+    return 0;
   }
 
-  definer->host.str= sctx->priv_host;
-  definer->host.length= strlen(sctx->priv_host);
-  return FALSE;
+  /* Create and initialize. */
+
+  if (! (definer= (LEX_USER*) thd->alloc(sizeof (LEX_USER))))
+    return 0;
+
+  definer->user= *user_name;
+  definer->host= *host_name;
+
+  return definer;
 }

--- 1.55/sql/share/errmsg.txt	2005-11-10 19:50:43 +03:00
+++ 1.56/sql/share/errmsg.txt	2005-11-10 22:32:38 +03:00
@@ -5405,14 +5405,14 @@
         eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner"
 ER_SP_CANT_SET_AUTOCOMMIT
 	eng "Not allowed to set autocommit from a stored function or trigger"
-ER_NO_VIEW_USER
-        eng "View definer is not fully qualified"
+ER_MALFORMED_DEFINER
+	eng "Definer is not fully qualified"
 ER_VIEW_FRM_NO_USER
         eng "View %-.64s.%-.64s has not definer information (old table format). Current user is used as definer. Please recreate view!"
 ER_VIEW_OTHER_USER
-        eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer"
+	eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer"
 ER_NO_SUCH_USER
-        eng "There is not %-.64s@%-.64s registered"
+        eng "There is no '%-.64s'@'%-.64s' registered"
 ER_FORBID_SCHEMA_CHANGE
 	eng "Changing schema from '%-.64s' to '%-.64s' is not allowed."
 ER_ROW_IS_REFERENCED_2 23000
@@ -5421,3 +5421,5 @@
 	eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
 ER_SP_BAD_VAR_SHADOW 42000
 	eng "Variable '%-.64s' must be quoted with `...`, or renamed"
+ER_TRG_NO_DEFINER
+  eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."

--- 1.31/sql/sql_trigger.cc	2005-11-10 19:50:43 +03:00
+++ 1.32/sql/sql_trigger.cc	2005-11-10 22:32:38 +03:00
@@ -32,15 +32,36 @@
 */
 static File_option triggers_file_parameters[]=
 {
-  {{(char*)"triggers", 8},
+  {
+    { (char *) STRING_WITH_LEN("triggers") },
     offsetof(class Table_triggers_list, definitions_list),
-    FILE_OPTIONS_STRLIST},
-  {{(char*)"sql_modes", 13},
+    FILE_OPTIONS_STRLIST
+  },
+  {
+    /*
+      FIXME: Length specified for "sql_modes" key is erroneous, problem caused
+      by this are reported as BUG#14090 and should be fixed ASAP.
+    */
+    { (char *) "sql_modes", 13 },
     offsetof(class Table_triggers_list, definition_modes_list),
-    FILE_OPTIONS_ULLLIST},
-  {{0, 0}, 0, FILE_OPTIONS_STRING}
+    FILE_OPTIONS_ULLLIST
+  },
+  {
+    { (char *) STRING_WITH_LEN("definers") },
+    offsetof(class Table_triggers_list, definers_list),
+    FILE_OPTIONS_STRLIST
+  },
+  { { 0, 0 }, 0, FILE_OPTIONS_STRING }
 };
 
+/*
+  This must be kept up to date whenever a new option is added to the list
+  above, as it specifies the number of required parameters of the trigger in
+  .trg file.
+*/
+
+static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
+static const int TRG_MAX_VERSIONS= 3;
 
 /*
   Structure representing contents of .TRN file which are used to support
@@ -58,9 +79,16 @@
 
 static File_option trigname_file_parameters[]=
 {
-  {{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table),
-   FILE_OPTIONS_ESTRING},
-  {{0, 0}, 0, FILE_OPTIONS_STRING}
+  {
+    /*
+      FIXME: Length specified for "trigger_table" key is erroneous, problem
+      caused by this are reported as BUG#14090 and should be fixed ASAP.
+    */
+    { (char *) "trigger_table", 15 },
+    offsetof(struct st_trigname, trigger_table),
+   FILE_OPTIONS_ESTRING
+  },
+  { { 0, 0 }, 0, FILE_OPTIONS_STRING }
 };
 
 
@@ -104,6 +132,9 @@
 {
   TABLE *table;
   bool result= TRUE;
+  LEX_STRING definer_user;
+  LEX_STRING definer_host;
+
   DBUG_ENTER("mysql_create_or_drop_trigger");
 
   /*
@@ -187,7 +218,7 @@
   }
 
   result= (create ?
-           table->triggers->create_trigger(thd, tables):
+           table->triggers->create_trigger(thd, tables, &definer_user, &definer_host):
            table->triggers->drop_trigger(thd, tables));
 
 end:
@@ -195,17 +226,30 @@
   start_waiting_global_read_lock(thd);
 
   if (!result)
+  {
+    if (mysql_bin_log.is_open())
     {
-      if (mysql_bin_log.is_open())
+      thd->clear_error();
+
+      String log_query(thd->query, thd->query_length, system_charset_info);
+
+      if (create)
       {
-	thd->clear_error();
-	/* Such a statement can always go directly to binlog, no trans cache */
-	Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
-	mysql_bin_log.write(&qinfo);
+        log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */
+
+        log_query.append("CREATE ");
+        append_definer(thd, &log_query, &definer_user, &definer_host);
+        log_query.append(thd->lex->trigger_definition_begin);
       }
-      send_ok(thd);
+
+      /* Such a statement can always go directly to binlog, no trans cache. */
+      Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE);
+      mysql_bin_log.write(&qinfo);
     }
 
+    send_ok(thd);
+  }
+
   DBUG_RETURN(result);
 }
 
@@ -215,15 +259,26 @@
 
   SYNOPSIS
     create_trigger()
-      thd    - current thread context (including trigger definition in LEX)
-      tables - table list containing one open table for which trigger is
-               created.
+      thd          - current thread context (including trigger definition in
+                     LEX)
+      tables       - table list containing one open table for which the
+                     trigger is created.
+      definer_user - [out] after a call it points to 0-terminated string,
+                     which contains user name part of the actual trigger
+                     definer. The caller is responsible to provide memory for
+                     storing LEX_STRING object.
+      definer_host - [out] after a call it points to 0-terminated string,
+                     which contains host name part of the actual trigger
+                     definer. The caller is responsible to provide memory for
+                     storing LEX_STRING object.
 
   RETURN VALUE
     False - success
     True  - error
 */
-bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
+bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
+                                         LEX_STRING *definer_user,
+                                         LEX_STRING *definer_host)
 {
   LEX *lex= thd->lex;
   TABLE *table= tables->table;
@@ -232,6 +287,8 @@
   LEX_STRING dir, file, trigname_file;
   LEX_STRING *trg_def, *name;
   ulonglong *trg_sql_mode;
+  char trg_definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2];
+  LEX_STRING *trg_definer;
   Item_trigger_field *trg_field;
   struct st_trigname trigname;
 
@@ -253,6 +310,31 @@
   }
 
   /*
+    Definer attribute of the Lex instance is always set in sql_yacc.yy when
+    trigger is created.
+  */
+
+  DBUG_ASSERT(lex->definer);
+
+  /*
+    If the specified definer differs from the current user, we should check
+    that the current user has SUPER privilege (in order to create trigger
+    under another user one must have SUPER privilege).
+  */
+  
+  if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+      my_strcasecmp(system_charset_info,
+                    lex->definer->host.str,
+                    thd->security_ctx->priv_host))
+  {
+    if (check_global_access(thd, SUPER_ACL))
+    {
+      my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+      return TRUE;
+    }
+  }
+
+  /*
     Let us check if all references to fields in old/new versions of row in
     this trigger are ok.
 
@@ -321,15 +403,39 @@
       definitions_list.push_back(trg_def, &table->mem_root) ||
       !(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root,
                                              sizeof(ulonglong))) ||
-      definition_modes_list.push_back(trg_sql_mode, &table->mem_root))
+      definition_modes_list.push_back(trg_sql_mode, &table->mem_root) ||
+      !(trg_definer= (LEX_STRING*) alloc_root(&table->mem_root,
+                                              sizeof(LEX_STRING))) ||
+      definers_list.push_back(trg_definer, &table->mem_root))
     goto err_with_cleanup;
 
   trg_def->str= thd->query;
   trg_def->length= thd->query_length;
   *trg_sql_mode= thd->variables.sql_mode;
 
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+  if (!is_acl_user(lex->definer->host.str,
+      lex->definer->user.str))
+  {
+    push_warning_printf(thd,
+                        MYSQL_ERROR::WARN_LEVEL_NOTE,
+                        ER_NO_SUCH_USER,
+                        ER(ER_NO_SUCH_USER),
+                        lex->definer->user.str,
+                        lex->definer->host.str);
+  }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+  *definer_user= lex->definer->user;
+  *definer_host= lex->definer->host;
+
+  trg_definer->str= trg_definer_holder;
+  trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
+                               definer_host->str, NullS) - trg_definer->str;
+
   if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
-                                  (gptr)this, triggers_file_parameters, 3))
+                                  (gptr)this, triggers_file_parameters,
+                                  TRG_MAX_VERSIONS))
     return 0;
 
 err_with_cleanup:
@@ -406,12 +512,14 @@
   List_iterator_fast<LEX_STRING> it_name(names_list);
   List_iterator<LEX_STRING>      it_def(definitions_list);
   List_iterator<ulonglong>       it_mod(definition_modes_list);
+  List_iterator<LEX_STRING>      it_definer(definers_list);
   char path[FN_REFLEN];
 
   while ((name= it_name++))
   {
     it_def++;
     it_mod++;
+    it_definer++;
 
     if (my_strcasecmp(table_alias_charset, lex->spname->m_name.str,
                       name->str) == 0)
@@ -422,6 +530,7 @@
       */
       it_def.remove();
       it_mod.remove();
+      it_definer.remove();
 
       if (definitions_list.is_empty())
       {
@@ -449,7 +558,7 @@
 
         if (sql_create_definition_file(&dir, &file, &triggers_file_type,
                                        (gptr)this, triggers_file_parameters,
-                                       3))
+                                       TRG_MAX_VERSIONS))
           return 1;
       }
 
@@ -571,7 +680,7 @@
     DBUG_RETURN(0);
 
   /*
-    File exists so we got to load triggers
+    File exists so we got to load triggers.
     FIXME: A lot of things to do here e.g. how about other funcs and being
     more paranoical ?
   */
@@ -587,13 +696,16 @@
         DBUG_RETURN(1);
 
       /*
-        We don't have sql_modes in old versions of .TRG file, so we should
-        initialize list for safety.
+        We don't have the following attributes in old versions of .TRG file, so
+        we should initialize the list for safety:
+          - sql_modes;
+          - definers;
       */
       triggers->definition_modes_list.empty();
+      triggers->definers_list.empty();
 
       if (parser->parse((gptr)triggers, &table->mem_root,
-                        triggers_file_parameters, 2))
+                        triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS))
         DBUG_RETURN(1);
 
       List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
@@ -615,7 +727,7 @@
           DBUG_RETURN(1); // EOM
         }
         *trg_sql_mode= global_system_variables.sql_mode;
-        while ((trg_create_str= it++))
+        while (it++)
         {
           if (triggers->definition_modes_list.push_back(trg_sql_mode,
                                                         &table->mem_root))
@@ -626,8 +738,43 @@
         it.rewind();
       }
 
+      if (triggers->definers_list.is_empty() &&
+          !triggers->definitions_list.is_empty())
+      {
+        /*
+          It is old file format => we should fill list of definers.
+
+          If there is no definer information, we should not switch context to
+          definer when checking privileges. I.e. privileges for such triggers
+          are checked for "invoker" rather than for "definer".
+        */
+
+        LEX_STRING *trg_definer;
+
+        if (! (trg_definer= (LEX_STRING*)alloc_root(&table->mem_root,
+                                                    sizeof(LEX_STRING))))
+          DBUG_RETURN(1); // EOM
+
+        trg_definer->str= "";
+        trg_definer->length= 0;
+
+        while (it++)
+        {
+          if (triggers->definers_list.push_back(trg_definer,
+                                                &table->mem_root))
+          {
+            DBUG_RETURN(1); // EOM
+          }
+        }
+
+        it.rewind();
+      }
+
       DBUG_ASSERT(triggers->definition_modes_list.elements ==
                   triggers->definitions_list.elements);
+      DBUG_ASSERT(triggers->definers_list.elements ==
+                  triggers->definitions_list.elements);
+
       table->triggers= triggers;
 
       /*
@@ -650,6 +797,8 @@
 
       char *trg_name_buff;
       List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
+      List_iterator_fast<LEX_STRING> it_definer(triggers->
+                                                definers_list);
       LEX *old_lex= thd->lex, lex;
       ulong save_sql_mode= thd->variables.sql_mode;
 
@@ -662,22 +811,55 @@
       while ((trg_create_str= it++))
       {
         trg_sql_mode= itm++;
+        LEX_STRING *trg_definer= it_definer++;
         thd->variables.sql_mode= (ulong)*trg_sql_mode;
         lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
 
         if (yyparse((void *)thd) || thd->is_fatal_error)
         {
           /*
-            Free lex associated resources
+            Free lex associated resources.
             QQ: Do we really need all this stuff here ?
           */
           delete lex.sphead;
           goto err_with_lex_cleanup;
         }
 
-        lex.sphead->m_sql_mode= *trg_sql_mode;
+        lex.sphead->set_info(0, 0, &lex.sp_chistics, *trg_sql_mode);
+
         triggers->bodies[lex.trg_chistics.event]
                              [lex.trg_chistics.action_time]= lex.sphead;
+
+        if (!trg_definer->length)
+        {
+          /*
+            This trigger was created/imported from the previous version of
+            MySQL, which does not support triggers definers. We should emit
+            warning here.
+          */
+
+          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                              ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
+                              (const char*) db,
+                              (const char*) lex.sphead->m_name.str);
+
+          /*
+            Set definer to the '' to correct displaying in the information
+            schema.
+          */
+
+          lex.sphead->set_definer("", 0);
+
+          /*
+            Triggers without definer information are executed under the
+            authorization of the invoker.
+          */
+
+          lex.sphead->m_chistics->suid= SP_IS_NOT_SUID;
+        }
+        else
+          lex.sphead->set_definer(trg_definer->str, trg_definer->length);
+
         if (triggers->names_list.push_back(&lex.sphead->m_name,
                                            &table->mem_root))
             goto err_with_lex_cleanup;
@@ -704,6 +886,10 @@
              trg_field= trg_field->next_trg_field)
           trg_field->setup_field(thd, table);
 
+        triggers->m_spec_var_used[lex.trg_chistics.event]
+          [lex.trg_chistics.action_time]=
+          lex.trg_table_fields.first ? TRUE : FALSE;
+
         lex_end(&lex);
       }
       thd->db= save_db.str;
@@ -747,6 +933,9 @@
       name      - returns name of trigger
       stmt      - returns statement of trigger
       sql_mode  - returns sql_mode of trigger
+      definer_user - returns definer/creator of trigger. The caller is
+                  responsible to allocate enough space for storing definer
+                  information.
 
   RETURN VALUE
     False - success
@@ -757,7 +946,8 @@
                                            trg_action_time_type time_type,
                                            LEX_STRING *trigger_name,
                                            LEX_STRING *trigger_stmt,
-                                           ulong *sql_mode)
+                                           ulong *sql_mode,
+                                           LEX_STRING *definer)
 {
   sp_head *body;
   DBUG_ENTER("get_trigger_info");
@@ -766,6 +956,18 @@
     *trigger_name= body->m_name;
     *trigger_stmt= body->m_body;
     *sql_mode= body->m_sql_mode;
+
+    if (body->m_chistics->suid == SP_IS_NOT_SUID)
+    {
+      definer->str[0]= 0;
+      definer->length= 0;
+    }
+    else
+    {
+      definer->length= strxmov(definer->str, body->m_definer_user.str, "@",
+                               body->m_definer_host.str, NullS) - definer->str;
+    }
+
     DBUG_RETURN(0);
   }
   DBUG_RETURN(1);
@@ -901,8 +1103,9 @@
                                            bool old_row_is_record1)
 {
   int res= 0;
+  sp_head *sp_trigger= bodies[event][time_type];
 
-  if (bodies[event][time_type])
+  if (sp_trigger)
   {
     Sub_statement_state statement_state;
 
@@ -917,14 +1120,54 @@
       old_field= table->field;
     }
 
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+    Security_context *save_ctx;
+
+    if (sp_change_security_context(thd, sp_trigger, &save_ctx))
+      return TRUE;
+
+    /*
+      NOTE: TRIGGER_ACL should be used below.
+    */
+
+    if (check_global_access(thd, SUPER_ACL))
+    {
+      sp_restore_security_context(thd, save_ctx);
+      return TRUE;
+    }
+
     /*
-      FIXME: We should juggle with security context here (because trigger
-      should be invoked with creator rights).
+      If the trigger uses special variables (NEW/OLD), check that we have
+      SELECT and UPDATE privileges on the subject table.
     */
+    
+    if (is_special_var_used(event, time_type))
+    {
+      TABLE_LIST table_list;
+      bzero((char *) &table_list, sizeof (table_list));
+      table_list.db= (char *) table->s->db;
+      table_list.db_length= strlen(table_list.db);
+      table_list.table_name= (char *) table->s->table_name;
+      table_list.table_name_length= strlen(table_list.table_name);
+      table_list.alias= (char *) table->alias;
+      table_list.table= table;
+
+      if (check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0))
+      {
+        sp_restore_security_context(thd, save_ctx);
+        return TRUE;
+      }
+    }
+    
+#endif // NO_EMBEDDED_ACCESS_CHECKS
 
     thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
-    res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
+    res= sp_trigger->execute_function(thd, 0, 0, 0);
     thd->restore_sub_statement_state(&statement_state);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+    sp_restore_security_context(thd, save_ctx);
+#endif // NO_EMBEDDED_ACCESS_CHECKS
   }
 
   return res;

--- 1.10/mysql-test/r/rpl_sp.result	2005-11-10 19:50:43 +03:00
+++ 1.11/mysql-test/r/rpl_sp.result	2005-11-10 22:47:56 +03:00
@@ -263,104 +263,7 @@
 1
 show binlog events in 'master-bin.000001' from 98;
 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()
-begin
-declare b int;
-set b = 8;
-insert into t1 values (b);
-insert into t1 values (unix_timestamp());
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8))
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values (unix_timestamp())
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create procedure foo2()
-select * from mysqltest1.t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; alter procedure foo2 contains sql
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop table t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create table t1 (a int)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create table t2 like t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create procedure foo3()
-deterministic
-insert into t1 values (15)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create procedure foo4()
-deterministic
-begin
-insert into t2 values(3);
-insert into t1 values (5);
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t2 values(3)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values (15)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t2 values(3)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; alter procedure foo4 sql security invoker
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t2 values(3)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values (5)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t2
-master-bin.000001	#	Query	1	#	use `mysqltest1`; alter table t2 add unique (a)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop procedure foo4
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create procedure foo4()
-deterministic
-begin
-insert into t2 values(20),(20);
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t2 values(20),(20)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop procedure foo4
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop procedure foo
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop procedure foo2
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop procedure foo3
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create function fn1(x int)
-returns int
-deterministic
-begin
-insert into t1 values (x);
-return x+2;
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete t1,t2 from t1,t2
-master-bin.000001	#	Query	1	#	use `mysqltest1`; DO `fn1`(20)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t2 values(fn1(21))
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop function fn1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create function fn1()
-returns int
-no sql
-begin
-return unix_timestamp();
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values(fn1())
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create function fn2()
-returns int
-no sql
-begin
-return unix_timestamp();
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create function fn3()
-returns int
-not deterministic
-reads sql data
-begin
-return 0;
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t2
-master-bin.000001	#	Query	1	#	use `mysqltest1`; alter table t2 add unique (a)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop function fn1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create function fn1()
-returns int
-begin
-insert into t2 values(20),(20);
-return 10;
-end
-master-bin.000001	#	Query	1	#	use `mysqltest1`; DO `fn1`()
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values (1)
-master-bin.000001	#	Query	1	#	use `mysqltest1`; delete from t1
-master-bin.000001	#	Query	1	#	use `mysqltest1`; drop trigger trg
-master-bin.000001	#	Query	1	#	use `mysqltest1`; insert into t1 values (1)
+master-bin.000002	#	Query	1	#	use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10
 select * from t1;
 a
 1

--- 1.97/sql/sp.cc	2005-11-10 19:50:43 +03:00
+++ 1.98/sql/sp.cc	2005-11-10 22:32:38 +03:00
@@ -441,8 +441,8 @@
       if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
 	goto done;
       *sphp= thd->lex->sphead;
-      (*sphp)->set_info((char *)definer, (uint)strlen(definer),
-			created, modified, &chistics, sql_mode);
+      (*sphp)->set_definer((char*) definer, (uint) strlen(definer));
+      (*sphp)->set_info(created, modified, &chistics, sql_mode);
       (*sphp)->optimize();
     }
     thd->lex->sql_command= oldcmd;

--- 1.81/mysql-test/r/mysqldump.result	2005-11-10 17:58:27 +03:00
+++ 1.82/mysql-test/r/mysqldump.result	2005-11-10 22:32:37 +03:00
@@ -1936,23 +1936,23 @@
 end|
 set sql_mode=default|
 show triggers like "t1";
-Trigger	Event	Table	Statement	Timing	Created	sql_mode
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
 trg1	INSERT	t1	
 begin
 if new.a > 10 then
 set new.a := 10;
 set new.a := 11;
 end if;
-end	BEFORE	0000-00-00 00:00:00	
+end	BEFORE	0000-00-00 00:00:00		root@localhost
 trg2	UPDATE	t1	 begin
 if old.a % 2 = 0 then set new.b := 12; end if;
-end	BEFORE	0000-00-00 00:00:00	
+end	BEFORE	0000-00-00 00:00:00		root@localhost
 trg3	UPDATE	t1	
 begin
 if new.a = -1 then
 set @fired:= "Yes";
 end if;
-end	AFTER	0000-00-00 00:00:00	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
+end	AFTER	0000-00-00 00:00:00	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER	root@localhost
 INSERT INTO t1 (a) VALUES (1),(2),(3),(22);
 update t1 set a = 4 where a=3;
 
@@ -2095,29 +2095,29 @@
 t1
 t2
 show triggers;
-Trigger	Event	Table	Statement	Timing	Created	sql_mode
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
 trg1	INSERT	t1	
 begin
 if new.a > 10 then
 set new.a := 10;
 set new.a := 11;
 end if;
-end	BEFORE	#	
+end	BEFORE	#		root@localhost
 trg2	UPDATE	t1	 begin
 if old.a % 2 = 0 then set new.b := 12; end if;
-end	BEFORE	#	
+end	BEFORE	#		root@localhost
 trg3	UPDATE	t1	
 begin
 if new.a = -1 then
 set @fired:= "Yes";
 end if;
-end	AFTER	#	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
+end	AFTER	#	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER	root@localhost
 trg4	INSERT	t2	
 begin
 if new.a > 10 then
 set @fired:= "No";
 end if;
-end	BEFORE	#	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
+end	BEFORE	#	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER	root@localhost
 DROP TABLE t1, t2;
 --port=1234
 --port=1234
@@ -2140,9 +2140,9 @@
 a2
 1
 SHOW TRIGGERS;
-Trigger	Event	Table	Statement	Timing	Created	sql_mode
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer
 testref	INSERT	test1	 BEGIN
-INSERT INTO test2 SET a2 = NEW.a1; END	BEFORE	NULL	
+INSERT INTO test2 SET a2 = NEW.a1; END	BEFORE	NULL		root@localhost
 SELECT * FROM `test1`;
 a1
 1
@@ -2157,6 +2157,7 @@
 DROP FUNCTION IF EXISTS bug9056_func2;
 DROP PROCEDURE IF EXISTS bug9056_proc1;
 DROP PROCEDURE IF EXISTS bug9056_proc2;
+DROP PROCEDURE IF EXISTS `a'b`;
 CREATE TABLE t1 (id int);
 INSERT INTO t1 VALUES(1), (2), (3), (4), (5);
 CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11) RETURN a+b //

--- 1.74/mysql-test/t/mysqldump.test	2005-11-10 17:58:27 +03:00
+++ 1.75/mysql-test/t/mysqldump.test	2005-11-10 22:32:37 +03:00
@@ -882,6 +882,7 @@
 DROP FUNCTION IF EXISTS bug9056_func2;
 DROP PROCEDURE IF EXISTS bug9056_proc1;
 DROP PROCEDURE IF EXISTS bug9056_proc2;
+DROP PROCEDURE IF EXISTS `a'b`;
 --enable_warnings
 
 CREATE TABLE t1 (id int);
Thread
bk commit into 5.0 tree (anozdrin:1.1962)Alexander Nozdrin10 Nov