List:Commits« Previous MessageNext Message »
From:marc.alff Date:March 6 2007 6:33pm
Subject:bk commit into 5.1 tree (malff:1.2452)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of marcsql. When marcsql 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@stripped, 2007-03-06 10:33:10-07:00, malff@weblab.(none) +18 -0
  Merge weblab.(none):/home/marcsql/TREE/mysql-5.0-8407_b
  into  weblab.(none):/home/marcsql/TREE/mysql-5.1-8407-merge
  MERGE: 1.1810.2620.1

  mysql-test/r/information_schema_db.result@stripped, 2007-03-06 10:29:51-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.1.1.9

  mysql-test/r/sp-error.result@stripped, 2007-03-06 10:29:58-07:00, malff@weblab.(none) +6 -137
    MERGE: 1.102.1.9

  mysql-test/r/sp.result@stripped, 2007-03-06 10:30:02-07:00, malff@weblab.(none) +2 -40
    MERGE: 1.170.27.5

  mysql-test/r/trigger.result@stripped, 2007-03-06 10:30:05-07:00, malff@weblab.(none) +0 -37
    MERGE: 1.29.13.1

  mysql-test/r/view.result@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.138.30.1

  mysql-test/t/sp-error.test@stripped, 2007-03-06 10:32:16-07:00, malff@weblab.(none) +6 -187
    MERGE: 1.100.1.12

  mysql-test/t/sp.test@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.174.27.4

  mysql-test/t/trigger.test@stripped, 2007-03-06 10:32:20-07:00, malff@weblab.(none) +0 -74
    MERGE: 1.34.16.1

  sql/lock.cc@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.64.1.30

  sql/mysqld.cc@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.439.97.1

  sql/sp_head.cc@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.200.14.1

  sql/sp_head.h@stripped, 2007-03-06 10:29:52-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.79.4.1

  sql/sql_base.cc@stripped, 2007-03-06 10:29:53-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.235.83.1

  sql/sql_class.cc@stripped, 2007-03-06 10:29:53-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.223.21.1

  sql/sql_class.h@stripped, 2007-03-06 10:33:05-07:00, malff@weblab.(none) +0 -67
    MERGE: 1.230.56.1

  sql/sql_update.cc@stripped, 2007-03-06 10:29:53-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.154.29.1

  sql/table.cc@stripped, 2007-03-06 10:29:53-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.160.49.1

  sql/table.h@stripped, 2007-03-06 10:29:53-07:00, malff@weblab.(none) +0 -0
    Auto merged
    MERGE: 1.102.14.1

# 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:	malff
# Host:	weblab.(none)
# Root:	/home/marcsql/TREE/mysql-5.1-8407-merge/RESYNC

--- 1.103/sql/lock.cc	2007-03-06 10:33:17 -07:00
+++ 1.104/sql/lock.cc	2007-03-06 10:33:17 -07:00
@@ -604,7 +604,7 @@ TABLE_LIST *mysql_lock_have_duplicate(TH
 
   for (; haystack; haystack= haystack->next_global)
   {
-    if (haystack->placeholder() || haystack->schema_table)
+    if (haystack->placeholder())
       continue;
     table2= haystack->table;
     if (table2->s->tmp_table == TMP_TABLE)

--- 1.612/sql/mysqld.cc	2007-03-06 10:33:17 -07:00
+++ 1.613/sql/mysqld.cc	2007-03-06 10:33:17 -07:00
@@ -2553,6 +2553,14 @@ static int my_message_sql(uint error, co
   */
   if ((thd= current_thd))
   {
+    /*
+      TODO: There are two exceptions mechanism (THD and sp_rcontext),
+      this could be improved by having a common stack of handlers.
+    */
+    if (thd->handle_error(error,
+                          MYSQL_ERROR::WARN_LEVEL_ERROR))
+      DBUG_RETURN(0);
+
     if (thd->spcont &&
         thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
     {

--- 1.379/sql/sql_base.cc	2007-03-06 10:33:17 -07:00
+++ 1.380/sql/sql_base.cc	2007-03-06 10:33:17 -07:00
@@ -28,6 +28,59 @@
 #include <io.h>
 #endif
 
+/**
+  This internal handler is used to trap internally
+  errors that can occur when executing open table
+  during the prelocking phase.
+*/
+class Prelock_error_handler : public Internal_error_handler
+{
+public:
+  Prelock_error_handler()
+    : m_handled_errors(0), m_unhandled_errors(0)
+  {}
+
+  virtual ~Prelock_error_handler() {}
+
+  virtual bool handle_error(uint sql_errno,
+                            MYSQL_ERROR::enum_warning_level level,
+                            THD *thd);
+
+  bool safely_trapped_errors();
+
+private:
+  int m_handled_errors;
+  int m_unhandled_errors;
+};
+
+
+bool
+Prelock_error_handler::handle_error(uint sql_errno,
+                                    MYSQL_ERROR::enum_warning_level /* level */,
+                                    THD * /* thd */)
+{
+  if (sql_errno == ER_NO_SUCH_TABLE)
+  {
+    m_handled_errors++;
+    return TRUE;                                // 'TRUE', as per coding style
+  }
+
+  m_unhandled_errors++;
+  return FALSE;                                 // 'FALSE', as per coding style
+}
+
+
+bool Prelock_error_handler::safely_trapped_errors()
+{
+  /*
+    If m_unhandled_errors != 0, something else, unanticipated, happened,
+    so the error is not trapped but returned to the caller.
+    Multiple ER_NO_SUCH_TABLE can be raised in case of views.
+  */
+  return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
+}
+
+
 TABLE *unused_tables;				/* Used by mysql_test */
 HASH open_cache;				/* Used by mysql_test */
 static HASH table_def_cache;
@@ -1977,7 +2030,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *
         VOID(pthread_mutex_unlock(&LOCK_open));
       }
     }
-    my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+    if ((thd->locked_tables) && (thd->locked_tables->lock_count > 0))
+      my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+    else
+      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
     DBUG_RETURN(0);
   }
 
@@ -2860,6 +2916,8 @@ int open_tables(THD *thd, TABLE_LIST **s
   MEM_ROOT new_frm_mem;
   /* Also used for indicating that prelocking is need */
   TABLE_LIST **query_tables_last_own;
+  bool safe_to_ignore_table;
+
   DBUG_ENTER("open_tables");
   /*
     temporary mem_root for new .frm parsing.
@@ -2908,6 +2966,7 @@ int open_tables(THD *thd, TABLE_LIST **s
 
   for (tables= *start; tables ;tables= tables->next_global)
   {
+    safe_to_ignore_table= FALSE;                // 'FALSE', as per coding style
     /*
       Ignore placeholders for derived tables. After derived tables
       processing, link to created temporary table will be put here.
@@ -2927,9 +2986,28 @@ int open_tables(THD *thd, TABLE_LIST **s
       DBUG_RETURN(-1);
     }
     (*counter)++;
-    
-    if (!tables->table &&
-	!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
+
+    if (!tables->table)
+    {
+      if (tables->prelocking_placeholder)
+      {
+        /*
+          For the tables added by the pre-locking code, attempt to open
+          the table but fail silently if the table does not exist.
+          The real failure will occur when/if a statement attempts to use
+          that table.
+        */
+        Prelock_error_handler prelock_handler;
+        thd->push_internal_handler(& prelock_handler);
+        tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+        thd->pop_internal_handler();
+        safe_to_ignore_table= prelock_handler.safely_trapped_errors();
+      }
+      else
+        tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+    }
+
+    if (!tables->table)
     {
       free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
 
@@ -2980,6 +3058,14 @@ int open_tables(THD *thd, TABLE_LIST **s
         close_tables_for_reopen(thd, start);
 	goto restart;
       }
+
+      if (safe_to_ignore_table)
+      {
+        DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
+                            tables->db, tables->alias));
+        continue;
+      }
+
       result= -1;				// Fatal error
       break;
     }
@@ -3283,7 +3369,7 @@ bool open_normal_and_derived_tables(THD 
 static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
 {
   for (; table; table= table->next_global)
-    if (!table->placeholder() && !table->schema_table)
+    if (!table->placeholder())
       table->table->query_id= 0;
 }
 
@@ -3356,7 +3442,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
       DBUG_RETURN(-1);
     for (table= tables; table; table= table->next_global)
     {
-      if (!table->placeholder() && !table->schema_table)
+      if (!table->placeholder())
 	*(ptr++)= table->table;
     }
 
@@ -3409,7 +3495,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
 
       for (table= tables; table != first_not_own; table= table->next_global)
       {
-        if (!table->placeholder() && !table->schema_table)
+        if (!table->placeholder())
         {
           table->table->query_id= thd->query_id;
           if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
@@ -3436,7 +3522,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
     TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
     for (table= tables; table != first_not_own; table= table->next_global)
     {
-      if (!table->placeholder() && !table->schema_table &&
+      if (!table->placeholder() &&
 	  check_lock_and_start_stmt(thd, table->table, table->lock_type))
       {
 	ha_rollback_stmt(thd);

--- 1.315/sql/sql_class.cc	2007-03-06 10:33:17 -07:00
+++ 1.316/sql/sql_class.cc	2007-03-06 10:33:17 -07:00
@@ -309,6 +309,38 @@ THD::THD()
   substitute_null_with_insert_id = FALSE;
   thr_lock_info_init(&lock_info); /* safety: will be reset after start */
   thr_lock_owner_init(&main_lock_id, &lock_info);
+
+  m_internal_handler= NULL;
+}
+
+
+void THD::push_internal_handler(Internal_error_handler *handler)
+{
+  /*
+    TODO: The current implementation is limited to 1 handler at a time only.
+    THD and sp_rcontext need to be modified to use a common handler stack.
+  */
+  DBUG_ASSERT(m_internal_handler == NULL);
+  m_internal_handler= handler;
+}
+
+
+bool THD::handle_error(uint sql_errno,
+                       MYSQL_ERROR::enum_warning_level level)
+{
+  if (m_internal_handler)
+  {
+    return m_internal_handler->handle_error(sql_errno, level, this);
+  }
+
+  return FALSE;                                 // 'FALSE', as per coding style
+}
+
+
+void THD::pop_internal_handler()
+{
+  DBUG_ASSERT(m_internal_handler != NULL);
+  m_internal_handler= NULL;
 }
 
 

--- 1.227/sql/sql_update.cc	2007-03-06 10:33:17 -07:00
+++ 1.228/sql/sql_update.cc	2007-03-06 10:33:17 -07:00
@@ -907,7 +907,7 @@ reopen_tables:
       tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
       tl->updating= 0;
       /* Update TABLE::lock_type accordingly. */
-      if (!tl->placeholder() && !tl->schema_table && !using_lock_tables)
+      if (!tl->placeholder() && !using_lock_tables)
         tl->table->reginfo.lock_type= tl->lock_type;
     }
   }

--- 1.277/sql/table.cc	2007-03-06 10:33:17 -07:00
+++ 1.278/sql/table.cc	2007-03-06 10:33:17 -07:00
@@ -2890,7 +2890,9 @@ void st_table_list::hide_view_error(THD 
       thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
       thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
       thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
-      thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR)
+      thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR ||
+      thd->net.last_errno == ER_TABLE_NOT_LOCKED ||
+      thd->net.last_errno == ER_NO_SUCH_TABLE)
   {
     TABLE_LIST *top= top_table();
     thd->clear_error();

--- 1.163/sql/table.h	2007-03-06 10:33:17 -07:00
+++ 1.164/sql/table.h	2007-03-06 10:33:17 -07:00
@@ -856,7 +856,7 @@ typedef struct st_table_list
   int view_check_option(THD *thd, bool ignore_failure);
   bool setup_underlying(THD *thd);
   void cleanup_items();
-  bool placeholder() {return derived || view; }
+  bool placeholder() {return derived || view || schema_table || !table; }
   void print(THD *thd, String *str);
   bool check_single_table(st_table_list **table, table_map map,
                           st_table_list *view);

--- 1.209/mysql-test/r/view.result	2007-03-06 10:33:17 -07:00
+++ 1.210/mysql-test/r/view.result	2007-03-06 10:33:17 -07:00
@@ -1935,11 +1935,11 @@ create function f1 () returns int return
 DROP TABLE t1;
 CHECK TABLE v1, v2, v3, v4, v5, v6;
 Table	Op	Msg_type	Msg_text
-test.v1	check	error	View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+test.v1	check	status	OK
 test.v2	check	status	OK
-test.v3	check	error	View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+test.v3	check	status	OK
 test.v4	check	status	OK
-test.v5	check	error	View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+test.v5	check	status	OK
 test.v6	check	status	OK
 drop function f1;
 drop function f2;

--- 1.18/mysql-test/r/information_schema_db.result	2007-03-06 10:33:17 -07:00
+++ 1.19/mysql-test/r/information_schema_db.result	2007-03-06 10:33:17 -07:00
@@ -98,13 +98,13 @@ where table_schema='test';
 table_name	table_type	table_comment
 t1	BASE TABLE	
 v1	VIEW	VIEW
-v2	VIEW	View 'test.v2' references invalid table(s) or column(s) or function(s) or define
+v2	VIEW	VIEW
 drop table t1;
 select table_name, table_type, table_comment from information_schema.tables
 where table_schema='test';
 table_name	table_type	table_comment
-v1	VIEW	View 'test.v1' references invalid table(s) or column(s) or function(s) or define
-v2	VIEW	View 'test.v2' references invalid table(s) or column(s) or function(s) or define
+v1	VIEW	VIEW
+v2	VIEW	VIEW
 drop function f1;
 drop function f2;
 drop view v1, v2;

--- 1.216/mysql-test/t/sp.test	2007-03-06 10:33:17 -07:00
+++ 1.217/mysql-test/t/sp.test	2007-03-06 10:33:17 -07:00
@@ -1369,7 +1369,7 @@ end|
 select f11()|
 --error ER_CANT_REOPEN_TABLE
 select f11() from t1|
-# We don't handle temporary tables used by nested functions well
+# Test that using a single table instance at a time works
 create function f12_1() returns int
 begin
   drop temporary table if exists t3;
@@ -1379,11 +1379,9 @@ begin
 end|
 create function f12_2() returns int
   return (select count(*) from t3)|
-# We need clean start to get error
+
 drop temporary table t3|
---error ER_NO_SUCH_TABLE
 select f12_1()|
---error ER_NO_SUCH_TABLE
 select f12_1() from t1 limit 1|
 
 # Cleanup
@@ -6801,6 +6799,53 @@ END|
 CALL bug24117()|
 DROP PROCEDURE bug24117|
 DROP TABLE t3|
+
+#
+# Bug#8407(Stored functions/triggers ignore exception handler)
+#
+
+--disable_warnings
+drop function if exists func_8407_a|
+drop function if exists func_8407_b|
+--enable_warnings
+
+create function func_8407_a() returns int
+begin
+  declare x int;
+
+  declare continue handler for sqlexception
+  begin
+  end;
+
+  select 1 from no_such_view limit 1 into x;
+
+  return x;
+end|
+
+create function func_8407_b() returns int
+begin
+  declare x int default 0;
+
+  declare continue handler for sqlstate '42S02'
+  begin
+    set x:= x+1000;
+  end;
+
+  case (select 1 from no_such_view limit 1)
+    when 1 then set x:= x+1;
+    when 2 then set x:= x+2;
+    else set x:= x+100;
+  end case;
+  set x:=x + 500;
+  
+  return x;
+end|
+
+select func_8407_a()|
+select func_8407_b()|
+
+drop function func_8407_a|
+drop function func_8407_b|
 
 #
 # NOTE: The delimiter is `|`, and not `;`. It is changed to `;`

--- 1.254/sql/sp_head.cc	2007-03-06 10:33:17 -07:00
+++ 1.255/sql/sp_head.cc	2007-03-06 10:33:17 -07:00
@@ -2444,16 +2444,11 @@ sp_lex_keeper::reset_lex_and_exec_core(T
       m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last);
     }
   }
-    
+
   reinit_stmt_before_use(thd, m_lex);
-  /*
-    If requested check whenever we have access to tables in LEX's table list
-    and open and lock them before executing instructtions core function.
-  */
-  if (open_tables &&
-      (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
-       open_and_lock_tables(thd, m_lex->query_tables)))
-      res= -1;
+
+  if (open_tables)
+    res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables, nextp);
 
   if (!res)
   {
@@ -2505,6 +2500,33 @@ sp_lex_keeper::reset_lex_and_exec_core(T
   sp_instr class functions
 */
 
+int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+                                        uint *nextp)
+{
+  int result;
+
+  /*
+    Check whenever we have access to tables for this statement
+    and open and lock them before executing instructions core function.
+  */
+  if (check_table_access(thd, SELECT_ACL, tables, 0)
+      || open_and_lock_tables(thd, tables))
+  {
+    get_cont_dest(nextp);
+    result= -1;
+  }
+  else
+    result= 0;
+
+  return result;
+}
+
+void sp_instr::get_cont_dest(uint *nextp)
+{
+  *nextp= m_ip+1;
+}
+
+
 int sp_instr::exec_core(THD *thd, uint *nextp)
 {
   DBUG_ASSERT(0);
@@ -2688,6 +2710,15 @@ sp_instr_set_trigger_field::print(String
   trigger_field->print(str);
   str->append(STRING_WITH_LEN(":="));
   value->print(str);
+}
+
+/*
+  sp_instr_opt_meta
+*/
+
+void sp_instr_opt_meta::get_cont_dest(uint *nextp)
+{
+  *nextp= m_cont_dest;
 }
 
 

--- 1.96/sql/sp_head.h	2007-03-06 10:33:17 -07:00
+++ 1.97/sql/sp_head.h	2007-03-06 10:33:17 -07:00
@@ -477,6 +477,28 @@ public:
   
   virtual int execute(THD *thd, uint *nextp) = 0;
 
+  /**
+    Execute <code>open_and_lock_tables()</code> for this statement.
+    Open and lock the tables used by this statement, as a pre-requisite
+    to execute the core logic of this instruction with
+    <code>exec_core()</code>.
+    If this statement fails, the next instruction to execute is also returned.
+    This is useful when a user defined SQL continue handler needs to be
+    executed.
+    @param thd the current thread
+    @param tables the list of tables to open and lock
+    @param nextp the continuation instruction, returned to the caller if this
+    method fails.
+    @return zero on success, non zero on failure.
+  */
+  int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, uint *nextp);
+
+  /**
+    Get the continuation destination of this instruction.
+    @param nextp the continuation destination (output)
+  */
+  virtual void get_cont_dest(uint *nextp);
+
   /*
     Execute core function of instruction after all preparations (e.g.
     setting of proper LEX, saving part of the thread context have been
@@ -740,6 +762,8 @@ public:
 
   virtual void set_destination(uint old_dest, uint new_dest)
     = 0;
+
+  virtual void get_cont_dest(uint *nextp);
 
 protected:
 
Thread
bk commit into 5.1 tree (malff:1.2452)marc.alff6 Mar