List:Internals« Previous MessageNext Message »
From:sanja Date:October 27 2005 11:24pm
Subject:bk commit into 5.0 tree (bell:1.1947)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of bell. When bell 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.1947 05/10/28 00:24:13 bell@stripped +13 -0
  Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0
  into  sanja.is.com.ua:/home/bell/mysql/bk/work-owner7-5.0

  sql/sql_view.cc
    1.72 05/10/28 00:24:04 bell@stripped +0 -0
    Auto merged

  sql/sql_prepare.cc
    1.161 05/10/28 00:24:04 bell@stripped +0 -0
    Auto merged

  sql/sql_parse.cc
    1.510 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/sql_lex.h
    1.204 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/sql_delete.cc
    1.168 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/sql_cache.cc
    1.86 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/sql_base.cc
    1.313 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/sql_acl.cc
    1.177 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/item_func.cc
    1.263 05/10/28 00:24:03 bell@stripped +0 -0
    Auto merged

  sql/item.h
    1.177 05/10/28 00:24:02 bell@stripped +0 -0
    Auto merged

  sql/item.cc
    1.193 05/10/28 00:24:02 bell@stripped +0 -0
    Auto merged

  mysql-test/r/sp.result
    1.168 05/10/28 00:24:02 bell@stripped +0 -0
    Auto merged

  mysql-test/r/information_schema.result
    1.87 05/10/28 00:24:02 bell@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:	bell
# Host:	sanja.is.com.ua
# Root:	/home/bell/mysql/bk/work-owner7-5.0/RESYNC

--- 1.192/sql/item.cc	2005-10-27 00:09:17 +03:00
+++ 1.193/sql/item.cc	2005-10-28 00:24:02 +03:00
@@ -3234,8 +3234,7 @@
                                           context->last_name_resolution_table,
                                           reference,
                                           IGNORE_EXCEPT_NON_UNIQUE,
-                                          !any_privileges &&
-                                          context->check_privileges,
+                                          !any_privileges,
                                           TRUE)) ==
 	not_found_field)
     {
@@ -3297,9 +3296,7 @@
                                                 last_name_resolution_table,
                                               reference,
                                               IGNORE_EXCEPT_NON_UNIQUE,
-                                              outer_context->
-                                              check_privileges,
-                                              TRUE)) !=
+                                              TRUE, TRUE)) !=
             not_found_field)
         {
           if (from_field)
@@ -3374,7 +3371,7 @@
                                context->last_name_resolution_table,
                                reference, REPORT_ALL_ERRORS,
                                !any_privileges &&
-                               context->check_privileges, TRUE);
+                               TRUE, TRUE);
 	}
 	goto error;
       }
@@ -3449,7 +3446,7 @@
       We can leave expression substituted from view for next PS/SP rexecution
       (i.e. do not register this substitution for reverting on cleupup()
       (register_item_tree_changing())), because this subtree will be
-      fix_field'ed during setup_tables()->setup_ancestor() (i.e. before
+      fix_field'ed during setup_tables()->setup_underlying() (i.e. before
       all other expressions of query, and references on tables which do
       not present in query will not make problems.
 
@@ -4544,8 +4541,7 @@
                                              last_name_resolution_table,
                                            reference,
                                            IGNORE_EXCEPT_NON_UNIQUE,
-                                           outer_context->check_privileges,
-                                           TRUE);
+                                           TRUE, TRUE);
           if (! from_field)
             goto error;
           if (from_field == view_ref_found)
@@ -5157,7 +5153,7 @@
     set field_idx properly.
   */
   (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
-                            0, 0, &field_idx);
+                            0, 0, &field_idx, 0);
   thd->set_query_id= save_set_query_id;
   triggers= table->triggers;
 }

--- 1.176/sql/item.h	2005-10-20 09:55:25 +03:00
+++ 1.177/sql/item.h	2005-10-28 00:24:02 +03:00
@@ -294,15 +294,15 @@
   bool resolve_in_select_list;
 
   /*
-    When FALSE we do not check columns right of resolving items, used to
-    prevent rights check on underlying tables of view
+    Security context of this name resolution context. It's used for views
+    and is non-zero only if the view is defined with SQL SECURITY DEFINER.
   */
-  bool check_privileges;
+  Security_context *security_ctx;
 
   Name_resolution_context()
     :outer_context(0), table_list(0), select_lex(0),
     error_processor_data(0),
-    check_privileges(TRUE)
+    security_ctx(0)
     {}
 
   void init()

--- 1.262/sql/item_func.cc	2005-10-27 22:45:06 +03:00
+++ 1.263/sql/item_func.cc	2005-10-28 00:24:03 +03:00
@@ -4732,6 +4732,7 @@
   if (execute(&it))
   {
     null_value= 1;
+    context->process_error(current_thd);
     return 1;
   }
   if (!(f= *flp))
@@ -4754,9 +4755,17 @@
   THD *thd= current_thd;
   int res= -1;
   Sub_statement_state statement_state;
-  Security_context *save_ctx;
+  Security_context *save_security_ctx= 0, *save_ctx_func;
 
-  if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+  if (context->security_ctx)
+  {
+    /* Set view definer security context */
+    save_security_ctx= thd->security_ctx;
+    thd->security_ctx= context->security_ctx;
+  }
+#endif
+  if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx_func))
     goto error;
 
   /*
@@ -4774,9 +4783,14 @@
     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                  ER_FAILED_ROUTINE_BREAK_BINLOG,
 		 ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
-
-  sp_restore_security_context(thd, save_ctx);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+  sp_restore_security_context(thd, save_ctx_func);
 error:
+  if (save_security_ctx)
+    thd->security_ctx= save_security_ctx;
+#else
+error:
+#endif
   DBUG_RETURN(res);
 }
 
@@ -4957,8 +4971,20 @@
   bool res;
   DBUG_ASSERT(fixed == 0);
   res= Item_func::fix_fields(thd, ref);
-  if (!res)
+  if (!res && thd->lex->view_prepare_mode)
   {
+    /*
+      Here we check privileges of the stored routine only during view
+      creation, in order to validate the view. A runtime check is perfomed
+      in Item_func_sp::execute(), and this method is not called during
+      context analysis. We do not need to restore the security context
+      changed in find_and_check_access because all view structures created
+      in CREATE VIEW are not used for execution.  Notice, that during view
+      creation we do not infer into stored routine bodies and do not check
+      privileges of its statements, which would probably be a good idea
+      especially if the view has SQL SECURITY DEFINER and the used stored
+      procedure has SQL
+    */
     Security_context *save_ctx;
     if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
       sp_restore_security_context(thd, save_ctx);

--- 1.176/sql/sql_acl.cc	2005-10-19 23:47:02 +03:00
+++ 1.177/sql/sql_acl.cc	2005-10-28 00:24:03 +03:00
@@ -934,6 +934,9 @@
   ACL_USER *acl_user= 0;
   DBUG_ENTER("acl_getroot_no_password");
 
+  DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
+                       (host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
+                       (user ? user : "(NULL)"), (db ? db : "(NULL)")));
   sctx->user= user;
   sctx->host= host;
   sctx->ip= ip;
@@ -3512,17 +3515,32 @@
 bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
 		 uint show_table, uint number, bool no_errors)
 {
-  TABLE_LIST *table;
+  TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
   Security_context *sctx= thd->security_ctx;
+  uint i;
   DBUG_ENTER("check_grant");
   DBUG_ASSERT(number > 0);
 
+  /*
+    Iterate tables until first prelocking placeholder (if this query do not
+    have placeholders first_not_own_table is 0)
+  */
+  for (i= 0, table= tables;
+       table && table != first_not_own_table && i < number;
+       table= table->next_global, i++)
+  {
+    /* Remove SHOW_VIEW_ACL, because it will be checked during making view */
+    table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+  }
+
   want_access&= ~sctx->master_access;
   if (!want_access)
     DBUG_RETURN(0);                             // ok
 
   rw_rdlock(&LOCK_grant);
-  for (table= tables; table && number--; table= table->next_global)
+  for (table= tables;
+       table && number-- && table != first_not_own_table;
+       table= table->next_global)
   {
     GRANT_TABLE *grant_table;
     if (!(~table->grant.privilege & want_access) || 
@@ -3532,8 +3550,16 @@
         It is subquery in the FROM clause. VIEW set table->derived after
         table opening, but this function always called before table opening.
       */
-      table->grant.want_privilege= 0;
-      continue;					// Already checked
+      if (!table->referencing_view)
+      {
+        /*
+          If it's a temporary table created for a subquery in the FROM
+          clause, or an INFORMATION_SCHEMA table, drop the request for
+          a privilege.
+        */
+        table->grant.want_privilege= 0;
+      }
+      continue;
     }
     if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
                                          table->db, sctx->priv_user,
@@ -5842,24 +5868,37 @@
                                      const char *db, const char *table)
 {
   Security_context *sctx= thd->security_ctx;
+  DBUG_ENTER("fill_effective_table_privileges");
+  DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`",
+                       sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"),
+                       (sctx->priv_user ? sctx->priv_user : "(NULL)"),
+                       db, table));
   /* --skip-grants */
   if (!initialized)
   {
+    DBUG_PRINT("info", ("skip grants"));
     grant->privilege= ~NO_ACCESS;             // everything is allowed
-    return;
+    DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+    DBUG_VOID_RETURN;
   }
 
   /* global privileges */
   grant->privilege= sctx->master_access;
 
   if (!sctx->priv_user)
-    return;                                   // it is slave
+  {
+    DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+    DBUG_VOID_RETURN;                         // it is slave
+  }
 
   /* db privileges */
   grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
 
   if (!grant_option)
-    return;
+  {
+    DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+    DBUG_VOID_RETURN;
+  }
 
   /* table privileges */
   if (grant->version != grant_version)
@@ -5876,6 +5915,8 @@
   {
     grant->privilege|= grant->grant_table->privs;
   }
+  DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+  DBUG_VOID_RETURN;
 }
 
 #else /* NO_EMBEDDED_ACCESS_CHECKS */

--- 1.312/sql/sql_base.cc	2005-10-25 12:02:41 +03:00
+++ 1.313/sql/sql_base.cc	2005-10-28 00:24:03 +03:00
@@ -1971,11 +1971,11 @@
     derived/information schema tables and views possible. Thus "counter"
     may be still zero for prelocked statement...
 
-    NOTE: The above notes may be out of date. Please wait for psergey to 
+    NOTE: The above notes may be out of date. Please wait for psergey to
           document new prelocked behavior.
   */
-  
-  if (!thd->prelocked_mode && !thd->lex->requires_prelocking()
&& 
+
+  if (!thd->prelocked_mode && !thd->lex->requires_prelocking()
&&
       thd->lex->sroutines_list.elements)
   {
     bool first_no_prelocking, need_prelocking;
@@ -2025,7 +2025,7 @@
         /* VIEW placeholder */
 	(*counter)--;
 
-        /* 
+        /*
           tables->next_global list consists of two parts:
           1) Query tables and underlying tables of views.
           2) Tables used by all stored routines that this statement invokes on
@@ -2677,6 +2677,49 @@
 }
 
 
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/*
+  Check column rights in given security context
+
+  SYNOPSIS
+    check_grant_column_in_sctx()
+    thd                  thread handler
+    grant                grant information structure
+    db                   db name
+    table                table  name
+    name                 column name
+    length               column name length
+    check_grants         need to check grants
+    sctx                 0 or security context
+
+  RETURN
+    FALSE OK
+    TRUE  access denied
+*/
+
+static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
+                                       const char *db, const char *table,
+                                       const char *name, uint length,
+                                       bool check_grants,
+                                       Security_context *sctx)
+{
+  if (!check_grants)
+    return FALSE;
+  Security_context *save_security_ctx= 0;
+  bool res;
+  if (sctx)
+  {
+    save_security_ctx= thd->security_ctx;
+    thd->security_ctx= sctx;
+  }
+  res= check_grant_column(thd, grant, db, table, name, length);
+  if (save_security_ctx)
+    thd->security_ctx= save_security_ctx;
+  return res;
+}
+#endif
+
+
 /*
   Find a field by name in a view that uses merge algorithm.
 
@@ -2727,11 +2770,11 @@
         */
         DBUG_RETURN(((Item_field*) (field_it.item()))->field);
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-      if (check_grants &&
-          check_grant_column(thd, &table_list->grant,
-                             table_list->view_db.str,
-                             table_list->view_name.str,
-                             name, length))
+      if (check_grant_column_in_sctx(thd, &table_list->grant,
+                                     table_list->view_db.str,
+                                     table_list->view_name.str, name, length,
+                                     check_grants,
+                                     table_list->security_ctx))
         DBUG_RETURN(WRONG_GRANT);
 #endif
       // in PS use own arena or data will be freed after prepare
@@ -2900,7 +2943,8 @@
 Field *
 find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
                     bool check_grants, bool allow_rowid,
-                    uint *cached_field_index_ptr)
+                    uint *cached_field_index_ptr,
+                    Security_context *sctx)
 {
   Field **field_ptr, *field;
   uint cached_field_index= *cached_field_index_ptr;
@@ -2909,7 +2953,7 @@
 
   /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
   if (cached_field_index < table->s->fields &&
-      !my_strcasecmp(system_charset_info, 
+      !my_strcasecmp(system_charset_info,
                      table->field[cached_field_index]->field_name, name))
     field_ptr= table->field + cached_field_index;
   else if (table->s->name_hash.records)
@@ -2940,9 +2984,10 @@
   update_field_dependencies(thd, field, table);
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-  if (check_grants && check_grant_column(thd, &table->grant,
-					 table->s->db,
-					 table->s->table_name, name, length))
+  if (check_grant_column_in_sctx(thd, &table->grant,
+                                 table->s->db, table->s->table_name,
+                                 name, length,
+                                 check_grants, sctx))
     field= WRONG_GRANT;
 #endif
   DBUG_RETURN(field);
@@ -3054,7 +3099,8 @@
     DBUG_ASSERT(table_list->table);
     if ((fld= find_field_in_table(thd, table_list->table, name, length,
                                   check_grants_table, allow_rowid,
-                                  cached_field_index_ptr)))
+                                  cached_field_index_ptr,
+                                  table_list->security_ctx)))
       *actual_table= table_list;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
     /* check for views with temporary table algorithm */
@@ -3188,7 +3234,8 @@
                                  test(table_ref->table->
                                       grant.want_privilege) &&
                                  check_privileges,
-                                 1, &(item->cached_field_index));
+                                 1, &(item->cached_field_index),
+                                 table_ref->security_ctx);
     else
       found= find_field_in_table_ref(thd, table_ref, name, item->name,
                                      NULL, NULL, length, ref,
@@ -4324,8 +4371,12 @@
 {
   for (TABLE_LIST *table= tables; table; table= table->next_local)
   {
-    if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE)
-      list= make_leaves_list(list, table->ancestor);
+    if (table->merge_underlying_list)
+    {
+      DBUG_ASSERT(table->view &&
+                  table->effective_algorithm == VIEW_ALGORITHM_MERGE);
+      list= make_leaves_list(list, table->merge_underlying_list);
+    }
     else
     {
       *list= table;
@@ -4425,16 +4476,17 @@
        table_list;
        table_list= table_list->next_local)
   {
-    if (table_list->ancestor)
+    if (table_list->merge_underlying_list)
     {
-      DBUG_ASSERT(table_list->view);
+      DBUG_ASSERT(table_list->view &&
+                  table_list->effective_algorithm == VIEW_ALGORITHM_MERGE);
       Query_arena *arena= thd->stmt_arena, backup;
       bool res;
       if (arena->is_conventional())
         arena= 0;                                   // For easier test
       else
         thd->set_n_backup_active_arena(arena, &backup);
-      res= table_list->setup_ancestor(thd);
+      res= table_list->setup_underlying(thd);
       if (arena)
         thd->restore_active_arena(arena, &backup);
       if (res)

--- 1.85/sql/sql_cache.cc	2005-10-24 09:36:17 +03:00
+++ 1.86/sql/sql_cache.cc	2005-10-28 00:24:03 +03:00
@@ -2208,15 +2208,10 @@
                         tables_used->view_db.length + 1,
                         HA_CACHE_TBL_NONTRANSACT, 0, 0))
         DBUG_RETURN(0);
-      {
-        TABLE_COUNTER_TYPE inc= register_tables_from_list(tables_used->ancestor,
-                                                          n + 1,
-                                                          block_table + 1);
-        if (!inc)
-          DBUG_RETURN(0);
-        n+= inc;
-        block_table+= inc;
-      }
+      /*
+        We do not need to register view tables here because they are already
+        present in the global list.
+      */
     }
     else
     {
@@ -2832,13 +2827,6 @@
                             tables_used->view_name.str,
                             tables_used->view_db.str));
       *tables_type|= HA_CACHE_TBL_NONTRANSACT;
-      {
-        TABLE_COUNTER_TYPE subcount;
-        if (!(subcount= process_and_count_tables(tables_used->ancestor,
-                                                 tables_type)))
-          DBUG_RETURN(0);
-        table_count+= subcount;
-      }
     }
     else
     {

--- 1.167/sql/sql_delete.cc	2005-10-27 15:13:53 +03:00
+++ 1.168/sql/sql_delete.cc	2005-10-28 00:24:03 +03:00
@@ -416,8 +416,9 @@
     if (!(target_tbl->table= target_tbl->correspondent_table->table))
     {
       DBUG_ASSERT(target_tbl->correspondent_table->view &&
-                  target_tbl->correspondent_table->ancestor &&
-                  target_tbl->correspondent_table->ancestor->next_local);
+                  target_tbl->correspondent_table->merge_underlying_list &&
+                  target_tbl->correspondent_table->merge_underlying_list->
+                  next_local);
       my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
                target_tbl->correspondent_table->view_db.str,
                target_tbl->correspondent_table->view_name.str);

--- 1.203/sql/sql_lex.h	2005-10-24 23:53:55 +03:00
+++ 1.204/sql/sql_lex.h	2005-10-28 00:24:03 +03:00
@@ -801,6 +801,11 @@
   */
   uint table_count;
   uint8 describe;
+  /*
+    A flag that indicates what kinds of derived tables are present in the
+    query (0 if no derived tables, otherwise a combination of flags
+    DERIVED_SUBQUERY and DERIVED_VIEW.
+  */
   uint8 derived_tables;
   uint8 create_view_algorithm;
   uint8 create_view_check;

--- 1.509/sql/sql_parse.cc	2005-10-25 19:09:30 +03:00
+++ 1.510/sql/sql_parse.cc	2005-10-28 00:24:03 +03:00
@@ -5026,8 +5026,13 @@
 {
   uint found=0;
   ulong found_access=0;
-  TABLE_LIST *org_tables=tables;
-  for (; tables; tables= tables->next_global)
+  TABLE_LIST *org_tables= tables;
+  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
+  /*
+    Iterate tables until first prelocking placeholder (if this query do not
+    have placeholders first_not_own_table is 0)
+  */
+  for (; tables && tables != first_not_own_table; tables= tables->next_global)
   {
     if (tables->schema_table && 
         (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
@@ -5038,6 +5043,11 @@
                  information_schema_name.str);
       return TRUE;
     }
+    /*
+       Register access for view underlying table.
+       Remove SHOW_VIEW_ACL, because it will be checked during making view
+     */
+    tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
     if (tables->derived || tables->schema_table || tables->belong_to_view ||
         (tables->table && (int)tables->table->s->tmp_table) ||
         my_tz_check_n_skip_implicit_tables(&tables,

--- 1.71/sql/sql_view.cc	2005-10-24 23:53:55 +03:00
+++ 1.72/sql/sql_view.cc	2005-10-28 00:24:04 +03:00
@@ -722,6 +722,7 @@
 }
 
 
+
 /*
   read VIEW .frm and create structures
 
@@ -738,11 +739,26 @@
 my_bool
 mysql_make_view(File_parser *parser, TABLE_LIST *table)
 {
+  THD *thd= current_thd;
   DBUG_ENTER("mysql_make_view");
   DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
 
   if (table->view)
   {
+    /*
+      It's an execution of a PS/SP and the view has already been unfolded
+      into a list of used tables. Now we only need to update the information
+      about granted privileges in the view tables with the actual data
+      stored in MySQL privilege system.  We don't need to restore the
+      required privileges (by calling register_want_access) because they has
+      not changed since PREPARE or the previous execution: the only case
+      when this information is changed is execution of UPDATE on a view, but
+      the original want_access is restored in its end.
+    */
+    if (!table->prelocking_placeholder && table->prepare_security(thd))
+    {
+      DBUG_RETURN(1);
+    }
     DBUG_PRINT("info",
                ("VIEW %s.%s is already processed on previous PS/SP execution",
                 table->view_db.str, table->view_name.str));
@@ -750,7 +766,6 @@
   }
 
   SELECT_LEX *end;
-  THD *thd= current_thd;
   LEX *old_lex= thd->lex, *lex;
   SELECT_LEX *view_select;
   int res= 0;
@@ -769,7 +784,7 @@
   if (!table->timestamp.str)
     table->timestamp.str= table->timestamp_buffer;
   /* prepare default values for old format */
-  table->view_suid= 1;
+  table->view_suid= TRUE;
   table->definer.user.str= table->definer.host.str= 0;
   table->definer.user.length= table->definer.host.length= 0;
 
@@ -880,6 +895,10 @@
         goto err;
     }
 
+
+    if (!(table->view_tables=
+          (List<TABLE_LIST>*) new(thd->mem_root) List<TABLE_LIST>))
+      goto err;
     /*
       mark to avoid temporary table using and put view reference and find
       last view table
@@ -890,6 +909,22 @@
     {
       tbl->skip_temporary= 1;
       tbl->belong_to_view= top_view;
+      tbl->referencing_view= table;
+      /*
+        First we fill want_privilege with SELECT_ACL (this is needed for the
+        tables which belongs to view subqueries and temporary table views,
+        then for the merged view underlying tables we will set wanted
+        privileges of top_view
+      */
+      tbl->grant.want_privilege= SELECT_ACL;
+      /*
+        After unfolding the view we lose the list of tables referenced in it
+        (we will have only a list of underlying tables in case of MERGE
+        algorithm, which does not include the tables referenced from
+        subqueries used in view definition).
+        Let's build a list of all tables referenced in the view.
+      */
+      table->view_tables->push_back(tbl);
     }
 
     /*
@@ -915,16 +950,6 @@
     }
 
     /*
-      Let us set proper lock type for tables of the view's main select
-      since we may want to perform update or insert on view. This won't
-      work for view containing union. But this is ok since we don't
-      allow insert and update on such views anyway.
-    */
-    if (!lex->select_lex.next_select())
-      for (tbl= lex->select_lex.get_table_list(); tbl; tbl= tbl->next_local)
-        tbl->lock_type= table->lock_type;
-
-    /*
       If we are opening this view as part of implicit LOCK TABLES, then
       this view serves as simple placeholder and we should not continue
       further processing.
@@ -932,7 +957,7 @@
     if (table->prelocking_placeholder)
       goto ok2;
 
-    old_lex->derived_tables|= DERIVED_VIEW;
+    old_lex->derived_tables|= (DERIVED_VIEW | lex->derived_tables);
 
     /* move SQL_NO_CACHE & Co to whole query */
     old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
@@ -941,6 +966,37 @@
     if (view_select->options & OPTION_TO_QUERY_CACHE)
       old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
 
+    if (table->view_suid)
+    {
+      /*
+        Prepare a security context to check underlying objects of the view
+      */
+      Security_context *save_security_ctx= thd->security_ctx;
+      if (!(table->view_sctx= (Security_context *)
+            thd->stmt_arena->alloc(sizeof(Security_context))))
+        goto err;
+      /* Assign the context to the tables referenced in the view */
+      for (tbl= view_tables; tbl; tbl= tbl->next_global)
+        tbl->security_ctx= table->view_sctx;
+      /* assign security context to SELECT name resolution contexts of view */
+      for(SELECT_LEX *sl= lex->all_selects_list;
+          sl;
+          sl= sl->next_select_in_list())
+        sl->context.security_ctx= table->view_sctx;
+    }
+
+    /*
+      Setup an error processor to hide error messages issued by stored
+      routines referenced in the view
+    */
+    for (SELECT_LEX *sl= lex->all_selects_list;
+         sl;
+         sl= sl->next_select_in_list())
+    {
+      sl->context.error_processor= &view_error_processor;
+      sl->context.error_processor_data= (void *)table;
+    }
+
     /*
       check MERGE algorithm ability
       - algorithm is not explicit TEMPORARY TABLE
@@ -962,24 +1018,28 @@
       table->updatable= (table->updatable_view != 0);
       table->effective_with_check=
         old_lex->get_effective_with_check(table);
+      table->merge_underlying_list= view_tables;
+      /*
+        Let us set proper lock type for tables of the view's main select
+        since we may want to perform update or insert on view. This won't
+        work for view containing union. But this is ok since we don't
+        allow insert and update on such views anyway.
+
+        Also we fill correct wanted privileges.
+      */
+      for (tbl= table->merge_underlying_list; tbl; tbl= tbl->next_local)
+      {
+        tbl->lock_type= table->lock_type;
+        tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
+      }
 
       /* prepare view context */
-      lex->select_lex.context.resolve_in_table_list_only(table->ancestor=
-                                                         view_tables);
+      lex->select_lex.context.resolve_in_table_list_only(view_tables);
       lex->select_lex.context.outer_context= 0;
       lex->select_lex.context.select_lex= table->select_lex;
       lex->select_lex.select_n_having_items+=
         table->select_lex->select_n_having_items;
 
-      /* do not check privileges & hide errors for view underlyings */
-      for (SELECT_LEX *sl= lex->all_selects_list;
-           sl;
-           sl= sl->next_select_in_list())
-      {
-        sl->context.check_privileges= FALSE;
-        sl->context.error_processor= &view_error_processor;
-        sl->context.error_processor_data= (void *)table;
-      }
       /*
         Tables of the main select of the view should be marked as belonging
         to the same select as original view (again we can use LEX::select_lex
@@ -1012,7 +1072,7 @@
         }
       }
 
-      /* Store WHERE clause for post-processing in setup_ancestor */
+      /* Store WHERE clause for post-processing in setup_underlying */
       table->where= view_select->where;
       /*
         Add subqueries units to SELECT into which we merging current view.
@@ -1078,6 +1138,11 @@
   if (!old_lex->time_zone_tables_used &&
thd->lex->time_zone_tables_used)
     old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
   thd->lex= old_lex;
+  if (!table->prelocking_placeholder && table->prepare_security(thd))
+  {
+    DBUG_RETURN(1);
+  }
+
   DBUG_RETURN(0);
 
 err:

--- 1.86/mysql-test/r/information_schema.result	2005-10-25 15:22:43 +03:00
+++ 1.87/mysql-test/r/information_schema.result	2005-10-28 00:24:02 +03:00
@@ -648,21 +648,21 @@
 where table_schema='test';
 table_name
 Warnings:
-Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s)
-Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s)
+Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
+Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
 select table_name from information_schema.views
 where table_schema='test';
 table_name
 Warnings:
-Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s)
-Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s)
+Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
+Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
 select column_name from information_schema.columns
 where table_schema='test';
 column_name
 f1
 Warnings:
-Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s)
-Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s)
+Warning	1356	View 'test.v2' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
+Warning	1356	View 'test.v3' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
 select index_name from information_schema.statistics where table_schema='test';
 index_name
 f1_key

--- 1.167/mysql-test/r/sp.result	2005-10-24 23:53:55 +03:00
+++ 1.168/mysql-test/r/sp.result	2005-10-28 00:24:02 +03:00
@@ -1032,7 +1032,7 @@
 3	1
 drop function f1|
 select * from v1|
-ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or
definer/invoker of view lack rights to use them
 create function f1() returns int
 return (select sum(data) from t1) + (select sum(data) from v1)|
 drop function f1|

--- 1.160/sql/sql_prepare.cc	2005-10-24 23:53:55 +03:00
+++ 1.161/sql/sql_prepare.cc	2005-10-28 00:24:04 +03:00
@@ -1158,6 +1158,7 @@
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   table_list->grant.want_privilege= want_privilege;
   table_list->table->grant.want_privilege= want_privilege;
+  table_list->register_want_access(want_privilege);
 #endif
   thd->lex->select_lex.no_wrap_view_item= TRUE;
   res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
@@ -1169,6 +1170,7 @@
   table_list->grant.want_privilege=
   table_list->table->grant.want_privilege=
     (SELECT_ACL & ~table_list->table->grant.privilege);
+  table_list->register_want_access(SELECT_ACL);
 #endif
   if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
     goto error;
Thread
bk commit into 5.0 tree (bell:1.1947)sanja27 Oct