List:Commits« Previous MessageNext Message »
From:tim Date:March 7 2007 6:54am
Subject:bk commit into 5.0 tree (tsmith:1.2466)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of tsmith. When tsmith 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-07 06:54:35+01:00, tsmith@stripped +9 -0
  Merge tsmith@stripped:/home/bk/mysql-5.0-runtime
  into  quadxeon.mysql.com:/benchmarks/ext3/TOSAVE/tsmith/bk/maint/mrg0306/50
  MERGE: 1.2413.3.26

  mysql-test/mysql-test-run.pl@stripped, 2007-03-07 06:54:25+01:00, tsmith@stripped
+0 -0
    Auto merged
    MERGE: 1.196.1.2

  mysql-test/r/sp.result@stripped, 2007-03-07 06:54:26+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.218.1.1

  mysql-test/t/sp.test@stripped, 2007-03-07 06:54:26+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.208.1.1

  sql/item_cmpfunc.cc@stripped, 2007-03-07 06:54:26+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.236.1.1

  sql/item_cmpfunc.h@stripped, 2007-03-07 06:54:27+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.143.1.1

  sql/mysqld.cc@stripped, 2007-03-07 06:54:27+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.592.1.1

  sql/sql_class.cc@stripped, 2007-03-07 06:54:27+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.261.1.2

  sql/sql_class.h@stripped, 2007-03-07 06:54:27+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.321.1.1

  sql/sql_parse.cc@stripped, 2007-03-07 06:54:28+01:00, tsmith@stripped +0 -0
    Auto merged
    MERGE: 1.605.1.2

# 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:	tsmith
# Host:	quadxeon.mysql.com
# Root:	/benchmarks/ext3/TOSAVE/tsmith/bk/maint/mrg0306/50/RESYNC

--- 1.237/sql/item_cmpfunc.cc	2007-03-07 06:54:48 +01:00
+++ 1.238/sql/item_cmpfunc.cc	2007-03-07 06:54:48 +01:00
@@ -793,6 +793,59 @@
 }
 
 
+void Item_func_truth::fix_length_and_dec()
+{
+  maybe_null= 0;
+  null_value= 0;
+  decimals= 0;
+  max_length= 1;
+}
+
+
+void Item_func_truth::print(String *str)
+{
+  str->append('(');
+  args[0]->print(str);
+  str->append(STRING_WITH_LEN(" is "));
+  if (! affirmative)
+    str->append(STRING_WITH_LEN("not "));
+  if (value)
+    str->append(STRING_WITH_LEN("true"));
+  else
+    str->append(STRING_WITH_LEN("false"));
+  str->append(')');
+}
+
+
+bool Item_func_truth::val_bool()
+{
+  bool val= args[0]->val_bool();
+  if (args[0]->null_value)
+  {
+    /*
+      NULL val IS {TRUE, FALSE} --> FALSE
+      NULL val IS NOT {TRUE, FALSE} --> TRUE
+    */
+    return (! affirmative);
+  }
+
+  if (affirmative)
+  {
+    /* {TRUE, FALSE} val IS {TRUE, FALSE} value */
+    return (val == value);
+  }
+
+  /* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
+  return (val != value);
+}
+
+
+longlong Item_func_truth::val_int()
+{
+  return (val_bool() ? 1 : 0);
+}
+
+
 bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
 {
   if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
@@ -1529,6 +1582,7 @@
 {
   maybe_null=args[1]->maybe_null || args[2]->maybe_null;
   decimals= max(args[1]->decimals, args[2]->decimals);
+  unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
 
   enum Item_result arg1_type=args[1]->result_type();
   enum Item_result arg2_type=args[2]->result_type();
@@ -1558,12 +1612,20 @@
       collation.set(&my_charset_bin);	// Number
     }
   }
-  max_length=
-    (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
-    (max(args[1]->max_length - args[1]->decimals,
-         args[2]->max_length - args[2]->decimals) + decimals +
-         (unsigned_flag ? 0 : 1) ) :
-    max(args[1]->max_length, args[2]->max_length);
+
+  if ((cached_result_type == DECIMAL_RESULT )
+      || (cached_result_type == INT_RESULT))
+  {
+    int len1= args[1]->max_length - args[1]->decimals
+      - (args[1]->unsigned_flag ? 0 : 1);
+
+    int len2= args[2]->max_length - args[2]->decimals
+      - (args[2]->unsigned_flag ? 0 : 1);
+
+    max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
+  }
+  else
+    max_length= max(args[1]->max_length, args[2]->max_length);
 }
 
 

--- 1.144/sql/item_cmpfunc.h	2007-03-07 06:54:48 +01:00
+++ 1.145/sql/item_cmpfunc.h	2007-03-07 06:54:48 +01:00
@@ -101,6 +101,92 @@
   uint decimal_precision() const { return 1; }
 };
 
+
+/**
+  Abstract Item class, to represent <code>X IS [NOT] (TRUE | FALSE)</code>
+  boolean predicates.
+*/
+
+class Item_func_truth : public Item_bool_func
+{
+public:
+  virtual bool val_bool();
+  virtual longlong val_int();
+  virtual void fix_length_and_dec();
+  virtual void print(String *str);
+
+protected:
+  Item_func_truth(Item *a, bool a_value, bool a_affirmative)
+  : Item_bool_func(a), value(a_value), affirmative(a_affirmative)
+  {}
+
+  ~Item_func_truth()
+  {}
+private:
+  /**
+    True for <code>X IS [NOT] TRUE</code>,
+    false for <code>X IS [NOT] FALSE</code> predicates.
+  */
+  const bool value;
+  /**
+    True for <code>X IS Y</code>, false for <code>X IS NOT
Y</code> predicates.
+  */
+  const bool affirmative;
+};
+
+
+/**
+  This Item represents a <code>X IS TRUE</code> boolean predicate.
+*/
+
+class Item_func_istrue : public Item_func_truth
+{
+public:
+  Item_func_istrue(Item *a) : Item_func_truth(a, true, true) {}
+  ~Item_func_istrue() {}
+  virtual const char* func_name() const { return "istrue"; }
+};
+
+
+/**
+  This Item represents a <code>X IS NOT TRUE</code> boolean predicate.
+*/
+
+class Item_func_isnottrue : public Item_func_truth
+{
+public:
+  Item_func_isnottrue(Item *a) : Item_func_truth(a, true, false) {}
+  ~Item_func_isnottrue() {}
+  virtual const char* func_name() const { return "isnottrue"; }
+};
+
+
+/**
+  This Item represents a <code>X IS FALSE</code> boolean predicate.
+*/
+
+class Item_func_isfalse : public Item_func_truth
+{
+public:
+  Item_func_isfalse(Item *a) : Item_func_truth(a, false, true) {}
+  ~Item_func_isfalse() {}
+  virtual const char* func_name() const { return "isfalse"; }
+};
+
+
+/**
+  This Item represents a <code>X IS NOT FALSE</code> boolean predicate.
+*/
+
+class Item_func_isnotfalse : public Item_func_truth
+{
+public:
+  Item_func_isnotfalse(Item *a) : Item_func_truth(a, false, false) {}
+  ~Item_func_isnotfalse() {}
+  virtual const char* func_name() const { return "isnotfalse"; }
+};
+
+
 class Item_cache;
 #define UNKNOWN ((my_bool)-1)
 

--- 1.594/sql/mysqld.cc	2007-03-07 06:54:48 +01:00
+++ 1.595/sql/mysqld.cc	2007-03-07 06:54:48 +01:00
@@ -2448,6 +2448,14 @@
   */
   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.263/sql/sql_class.cc	2007-03-07 06:54:48 +01:00
+++ 1.264/sql/sql_class.cc	2007-03-07 06:54:48 +01:00
@@ -277,6 +277,38 @@
   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;
 }
 
 
@@ -321,6 +353,7 @@
 
 void THD::init_for_queries()
 {
+  set_time(); 
   ha_enable_transaction(this,TRUE);
 
   reset_root_defaults(mem_root, variables.query_alloc_block_size,

--- 1.322/sql/sql_class.h	2007-03-07 06:54:49 +01:00
+++ 1.323/sql/sql_class.h	2007-03-07 06:54:49 +01:00
@@ -1071,6 +1071,48 @@
   SAVEPOINT *savepoints;
 };
 
+/**
+  This class represents the interface for internal error handlers.
+  Internal error handlers are exception handlers used by the server
+  implementation.
+*/
+class Internal_error_handler
+{
+protected:
+  Internal_error_handler() {}
+  virtual ~Internal_error_handler() {}
+
+public:
+  /**
+    Handle an error condition.
+    This method can be implemented by a subclass to achieve any of the
+    following:
+    - mask an error internally, prevent exposing it to the user,
+    - mask an error and throw another one instead.
+    When this method returns true, the error condition is considered
+    'handled', and will not be propagated to upper layers.
+    It is the responsability of the code installing an internal handler
+    to then check for trapped conditions, and implement logic to recover
+    from the anticipated conditions trapped during runtime.
+
+    This mechanism is similar to C++ try/throw/catch:
+    - 'try' correspond to <code>THD::push_internal_handler()</code>,
+    - 'throw' correspond to <code>my_error()</code>,
+    which invokes <code>my_message_sql()</code>,
+    - 'catch' correspond to checking how/if an internal handler was invoked,
+    before removing it from the exception stack with
+    <code>THD::pop_internal_handler()</code>.
+
+    @param sql_errno the error number
+    @param level the error level
+    @param thd the calling thread
+    @return true if the error is handled
+  */
+  virtual bool handle_error(uint sql_errno,
+                            MYSQL_ERROR::enum_warning_level level,
+                            THD *thd) = 0;
+};
+
 
 /*
   For each client connection we create a separate thread with THD serving as
@@ -1659,6 +1701,31 @@
       *p_db_length= db_length;
     return FALSE;
   }
+
+public:
+  /**
+    Add an internal error handler to the thread execution context.
+    @param handler the exception handler to add
+  */
+  void push_internal_handler(Internal_error_handler *handler);
+
+  /**
+    Handle an error condition.
+    @param sql_errno the error number
+    @param level the error level
+    @return true if the error is handled
+  */
+  virtual bool handle_error(uint sql_errno,
+                            MYSQL_ERROR::enum_warning_level level);
+
+  /**
+    Remove the error handler last pushed.
+  */
+  void pop_internal_handler();
+
+private:
+  /** The current internal error handler for this thread, or NULL. */
+  Internal_error_handler *m_internal_handler;
 };
 
 

--- 1.606/sql/sql_parse.cc	2007-03-07 06:54:49 +01:00
+++ 1.607/sql/sql_parse.cc	2007-03-07 06:54:49 +01:00
@@ -1162,7 +1162,6 @@
     thd->version= refresh_version;
     thd->proc_info= 0;
     thd->command= COM_SLEEP;
-    thd->set_time();
     thd->init_for_queries();
 
     if (sys_init_connect.value_length && !(sctx->master_access &
SUPER_ACL))
@@ -1178,7 +1177,6 @@
         sql_print_warning("%s", net->last_error);
       }
       thd->proc_info=0;
-      thd->set_time();
       thd->init_for_queries();
     }
 
@@ -1313,6 +1311,7 @@
       mode we have only one thread.
     */
     thd->query_id=next_query_id();
+    thd->set_time();
     mysql_parse(thd,thd->query,length);
     close_thread_tables(thd);			// Free tables
 

--- 1.206/mysql-test/mysql-test-run.pl	2007-03-07 06:54:49 +01:00
+++ 1.207/mysql-test/mysql-test-run.pl	2007-03-07 06:54:49 +01:00
@@ -3043,6 +3043,7 @@
 character-sets-dir  = $path_charsetsdir
 basedir             = $path_my_basedir
 server_id           = $server_id
+shutdown-delay      = 10
 skip-stack-trace
 skip-innodb
 skip-ndbcluster

--- 1.219/mysql-test/r/sp.result	2007-03-07 06:54:49 +01:00
+++ 1.220/mysql-test/r/sp.result	2007-03-07 06:54:49 +01:00
@@ -1155,9 +1155,13 @@
 return (select count(*) from t3)|
 drop temporary table t3|
 select f12_1()|
-ERROR 42S02: Table 'test.t3' doesn't exist
+f12_1()
+3
+Warnings:
+Note	1051	Unknown table 't3'
 select f12_1() from t1 limit 1|
-ERROR 42S02: Table 'test.t3' doesn't exist
+f12_1()
+3
 drop function f0|
 drop function f1|
 drop function f2|
@@ -5727,4 +5731,38 @@
 CALL bug24117()|
 DROP PROCEDURE bug24117|
 DROP TABLE t3|
+drop function if exists func_8407_a|
+drop function if exists func_8407_b|
+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()|
+func_8407_a()
+NULL
+select func_8407_b()|
+func_8407_b()
+1500
+drop function func_8407_a|
+drop function func_8407_b|
 drop table t1,t2;

--- 1.209/mysql-test/t/sp.test	2007-03-07 06:54:49 +01:00
+++ 1.210/mysql-test/t/sp.test	2007-03-07 06:54:49 +01:00
@@ -1370,7 +1370,7 @@
 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;
@@ -1380,11 +1380,9 @@
 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
@@ -6692,6 +6690,53 @@
 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 `;`
Thread
bk commit into 5.0 tree (tsmith:1.2466)tim7 Mar