MySQL Lists are EOL. Please join:

List:Internals« Previous MessageNext Message »
From:konstantin Date:July 15 2005 7:13pm
Subject:bk commit into 4.1 tree (konstantin:1.2359) BUG#9359
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of kostja. When kostja 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.2359 05/07/15 23:13:29 konstantin@stripped +7 -0
  A fix and a test case for Bug#9359 "Prepared statements take snapshot
   of system vars at PREPARE time": implement a special Item
  to handle system variables. This item substitutes itself with 
  a basic constant containing variable value at fix_fields.

  sql/set_var.h
    1.59 05/07/15 23:13:25 konstantin@stripped +0 -5
    - declaration of enum_var_type moved to mysql_priv.h

  sql/set_var.cc
    1.172 05/07/15 23:13:24 konstantin@stripped +3 -3
    - we should not print to network from get_system_var: if it's called
    from prepared statement prepare, we get packets out of order when using
    the binary protocol. Instead report the error to be sent to the user later.
    This is a backport from 5.0.

  sql/mysql_priv.h
    1.356 05/07/15 23:13:24 konstantin@stripped +6 -4
    Move necessary declarations to make set_var.h objects visible in 
    item_func.h

  sql/item_func.h
    1.125 05/07/15 23:13:24 konstantin@stripped +23 -0
    Add a new item, Item_func_get_system_var

  sql/item_func.cc
    1.254 05/07/15 23:13:24 konstantin@stripped +38 -30
    - implement Item_func_get_system_var: we should not evaluate system
    variables in the parser, but instead should create an item which 
    is evaluated to a constant at execute.
    - remove an unused function

  mysql-test/t/ps.test
    1.41 05/07/15 23:13:24 konstantin@stripped +17 -1
    - add a test case for Bug#9359 "Prepared statements take snapshot
     of system vars at PREPARE time"

  mysql-test/r/ps.result
    1.41 05/07/15 23:13:24 konstantin@stripped +25 -0
    - test results fixed (Bug#9359).

# 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:	konstantin
# Host:	dragonfly.local
# Root:	/opt/local/work/mysql-4.1-root

--- 1.253/sql/item_func.cc	2005-07-14 20:02:29 +04:00
+++ 1.254/sql/item_func.cc	2005-07-15 23:13:24 +04:00
@@ -3031,6 +3031,36 @@
 }
 
 
+Item_func_get_system_var::
+Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+                       LEX_STRING *component_arg, const char *name_arg,
+                       size_t name_len_arg)
+  :var(var_arg), var_type(var_type_arg), component(*component_arg)
+{
+  /* set_name() will allocate the name */
+  set_name(name_arg, name_len_arg, system_charset_info);
+}
+
+
+bool
+Item_func_get_system_var::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+{
+  Item *item= var->item(thd, var_type, &component);
+  DBUG_ENTER("Item_func_get_system_var::fix_fields");
+  /*
+    Evaluate the system variable and substitute the result (a basic constant)
+    instead of this item. If the variable can not be evaluated,
+    the error is reported in sys_var::item().
+  */
+  if (item == 0)
+    DBUG_RETURN(1);                             // Impossible
+  item->set_name(name, 0, system_charset_info); // don't allocate a new name
+  thd->change_item_tree(ref, item);
+
+  DBUG_RETURN(0);
+}
+
+
 longlong Item_func_inet_aton::val_int()
 {
   DBUG_ASSERT(fixed == 1);
@@ -3375,22 +3405,21 @@
     0	error
     #	constant item
 */
-  
+
 
 Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
 		     LEX_STRING component)
 {
+  sys_var *var;
+  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
+  LEX_STRING *base_name, *component_name;
+
   if (component.str == 0 &&
       !my_strcasecmp(system_charset_info, name.str, "VERSION"))
     return new Item_string("@@VERSION", server_version,
 			   (uint) strlen(server_version),
 			   system_charset_info, DERIVATION_SYSCONST);
 
-  Item *item;
-  sys_var *var;
-  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
-  LEX_STRING *base_name, *component_name;
-
   if (component.str)
   {
     base_name= &component;
@@ -3412,9 +3441,8 @@
       return 0;
     }
   }
-  if (!(item=var->item(thd, var_type, component_name)))
-    return 0;					// Impossible
   thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+
   buff[0]='@';
   buff[1]='@';
   pos=buff+2;
@@ -3435,28 +3463,8 @@
   memcpy(pos, base_name->str, base_name->length);
   pos+= base_name->length;
 
-  // set_name() will allocate the name
-  item->set_name(buff,(uint) (pos-buff), system_charset_info);
-  return item;
-}
-
-
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
-		     uint length, const char *item_name)
-{
-  Item *item;
-  sys_var *var;
-  LEX_STRING null_lex_string;
-
-  null_lex_string.str= 0;
-
-  var= find_sys_var(var_name, length);
-  DBUG_ASSERT(var != 0);
-  if (!(item=var->item(thd, var_type, &null_lex_string)))
-    return 0;						// Impossible
-  thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
-  item->set_name(item_name, 0, system_charset_info);	// Will use original name
-  return item;
+  return new Item_func_get_system_var(var, var_type, component_name,
+                                      buff, pos - buff);
 }
 
 

--- 1.124/sql/item_func.h	2005-05-09 13:33:15 +04:00
+++ 1.125/sql/item_func.h	2005-07-15 23:13:24 +04:00
@@ -988,6 +988,29 @@
 };
 
 
+/* A system variable */
+
+class Item_func_get_system_var :public Item_func
+{
+  sys_var *var;
+  enum_var_type var_type;
+  LEX_STRING component;
+public:
+  Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+                           LEX_STRING *component_arg, const char *name_arg,
+                           size_t name_len_arg);
+  bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+  /*
+    Stubs for pure virtual methods. Should never be called: this
+    item is always substituted with a constant in fix_fields().
+  */
+  double val()              { DBUG_ASSERT(0); return 0.0; }
+  longlong val_int()        { DBUG_ASSERT(0); return 0; }
+  String* val_str(String*)  { DBUG_ASSERT(0); return 0; }
+  void fix_length_and_dec() { DBUG_ASSERT(0); }
+};
+
+
 class Item_func_inet_aton : public Item_int_func
 {
 public:

--- 1.355/sql/mysql_priv.h	2005-07-13 17:39:43 +04:00
+++ 1.356/sql/mysql_priv.h	2005-07-15 23:13:24 +04:00
@@ -358,6 +358,11 @@
 #include "protocol.h"
 #include "sql_udf.h"
 class user_var_entry;
+enum enum_var_type
+{
+  OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL
+};
+class sys_var;
 #include "item.h"
 typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
 /* sql_parse.cc */
@@ -1119,12 +1124,9 @@
 extern void sql_cache_free();
 extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
 
-/* item.cc */
+/* item_func.cc */
 Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
 		     LEX_STRING component);
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
-		     uint length, const char *item_name);
-/* item_func.cc */
 int get_var_with_binlog(THD *thd, LEX_STRING &name,
                         user_var_entry **out_entry);
 /* log.cc */

--- 1.171/sql/set_var.cc	2005-06-21 19:18:50 +04:00
+++ 1.172/sql/set_var.cc	2005-07-15 23:13:24 +04:00
@@ -1568,8 +1568,8 @@
   {
     if (var_type != OPT_DEFAULT)
     {
-      net_printf(thd, ER_INCORRECT_GLOBAL_LOCAL_VAR,
-		 name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
+      my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0),
+               name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
       return 0;
     }
     /* As there was no local variable, return the global value */
@@ -1613,7 +1613,7 @@
     return tmp;
   }
   default:
-    net_printf(thd, ER_VAR_CANT_BE_READ, name);
+    my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
   }
   return 0;
 }

--- 1.58/sql/set_var.h	2005-05-04 17:05:53 +04:00
+++ 1.59/sql/set_var.h	2005-07-15 23:13:25 +04:00
@@ -30,11 +30,6 @@
 typedef struct system_variables SV;
 extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
 
-enum enum_var_type
-{
-  OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL
-};
-
 typedef int (*sys_check_func)(THD *,  set_var *);
 typedef bool (*sys_update_func)(THD *, set_var *);
 typedef void (*sys_after_update_func)(THD *,enum_var_type);

--- 1.40/mysql-test/r/ps.result	2005-07-15 00:01:41 +04:00
+++ 1.41/mysql-test/r/ps.result	2005-07-15 23:13:24 +04:00
@@ -676,3 +676,28 @@
 select ? from t1;
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1
 drop table t1;
+prepare stmt from "select @@time_zone";
+execute stmt;
+@@time_zone
+SYSTEM
+set @@time_zone:='Japan';
+execute stmt;
+@@time_zone
+Japan
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+set transaction isolation level read committed;
+execute stmt;
+@@tx_isolation
+READ-COMMITTED
+set transaction isolation level serializable;
+execute stmt;
+@@tx_isolation
+SERIALIZABLE
+set @@tx_isolation=default;
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+deallocate prepare stmt;

--- 1.40/mysql-test/t/ps.test	2005-07-15 02:11:00 +04:00
+++ 1.41/mysql-test/t/ps.test	2005-07-15 23:13:24 +04:00
@@ -702,4 +702,20 @@
 select ? from t1;
 --enable_ps_protocol
 drop table t1;
-# 
+#
+# Bug#9359 "Prepared statements take snapshot of system vars at PREPARE
+# time"
+#
+prepare stmt from "select @@time_zone";
+execute stmt;
+set @@time_zone:='Japan';
+execute stmt;
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+set transaction isolation level read committed;
+execute stmt;
+set transaction isolation level serializable;
+execute stmt;
+set @@tx_isolation=default;
+execute stmt;
+deallocate prepare stmt;
Thread
bk commit into 4.1 tree (konstantin:1.2359) BUG#9359konstantin15 Jul