List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:August 29 2008 3:17pm
Subject:bzr commit into mysql-5.0 branch (kgeorge:2672) Bug#32124
View as plain text  
#At file:///home/kgeorge/mysql/bzr/B32124-5.0-bugteam/

 2672 Georgi Kodinov	2008-08-29
      Bug #32124: crash if prepared statements refer to variables in the where clause
      
      The code to get read the value of a system variable was extracting its value 
      on PREPARE stage and was substituting the value (as a constant) into the parse tree.
      Note that this must be a reversible transformation, i.e. it must be reversed before
      each re-execution.
      Unfortunately this cannot be reliably done using the current code, because there are 
      other non-reversible source tree transformations that can interfere with this
      reversible transformation.
      Fixed by not resolving the value at PREPARE, but at EXECUTE (as the rest of the 
      functions operate).
      Updated an obsolete related test suite (variables-big) and the code to test the 
      result type of system variables (as per bug 74).
modified:
  mysql-test/r/ps_11bugs.result
  mysql-test/r/variables-big.result
  mysql-test/r/variables.result
  mysql-test/t/ps_11bugs.test
  sql/item_func.cc
  sql/item_func.h
  tests/mysql_client_test.c

per-file messages:
  mysql-test/r/ps_11bugs.result
    Bug#32124: test case
  mysql-test/r/variables-big.result
    Bug#32124: updated an obsolete test case
  mysql-test/r/variables.result
    Bug #32124: no source transformation at prepare anymore : update the test result
  mysql-test/t/ps_11bugs.test
    Bug#32124: test case
  sql/item_func.cc
    Bug #32124: moved the retrieval of system variable's value from 
    PREPARE to EXECUTE
  sql/item_func.h
    Bug #32124: moved the retrieval of system variable's value from 
    PREPARE to EXECUTE
  tests/mysql_client_test.c
    Bug#32124: updated the client test to reflect the changed metadata
    for the system variables.
=== modified file 'mysql-test/r/ps_11bugs.result'
--- a/mysql-test/r/ps_11bugs.result	2006-10-04 15:19:23 +0000
+++ b/mysql-test/r/ps_11bugs.result	2008-08-29 15:16:59 +0000
@@ -162,4 +162,10 @@ a	b
 12	NULL
 drop table t1;
 drop table t2;
+CREATE TABLE t1 (a INT);
+PREPARE stmt FROM 'select 1 from `t1` where `a` = any (select (@@tmpdir))';
+EXECUTE stmt;
+1
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1;
 End of 5.0 tests.

=== modified file 'mysql-test/r/variables-big.result'
--- a/mysql-test/r/variables-big.result	2007-12-21 19:30:23 +0000
+++ b/mysql-test/r/variables-big.result	2008-08-29 15:16:59 +0000
@@ -1,24 +1,20 @@
 set session transaction_prealloc_size=1024*1024*1024*1;
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
-6	root	localhost	test	Query	0	NULL	show processlist
+1	root	localhost	test	Query	0	NULL	show processlist
 set session transaction_prealloc_size=1024*1024*1024*2;
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
-6	root	localhost	test	Query	1	NULL	show processlist
+1	root	localhost	test	Query	0	NULL	show processlist
 set session transaction_prealloc_size=1024*1024*1024*3;
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
-6	root	localhost	test	Query	0	NULL	show processlist
+1	root	localhost	test	Query	1	NULL	show processlist
 set session transaction_prealloc_size=1024*1024*1024*4;
-Warnings:
-Warning	1292	Truncated incorrect transaction_prealloc_size value: '4294967296'
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
-6	root	localhost	test	Query	0	NULL	show processlist
+1	root	localhost	test	Query	0	NULL	show processlist
 set session transaction_prealloc_size=1024*1024*1024*5;
-Warnings:
-Warning	1292	Truncated incorrect transaction_prealloc_size value: '5368709120'
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
-6	root	localhost	test	Query	0	NULL	show processlist
+1	root	localhost	test	Query	0	NULL	show processlist

=== modified file 'mysql-test/r/variables.result'
--- a/mysql-test/r/variables.result	2008-02-17 11:37:39 +0000
+++ b/mysql-test/r/variables.result	2008-08-29 15:16:59 +0000
@@ -143,7 +143,7 @@ explain extended select @@IDENTITY,last_
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
 Warnings:
-Note	1003	select 345 AS `@@IDENTITY`,last_insert_id() AS `last_insert_id()`,345 AS `@@identity`
+Note	1003	select (@@IDENTITY) AS `@@IDENTITY`,last_insert_id() AS `last_insert_id()`,(@@identity) AS `@@identity`
 set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON";
 set global concurrent_insert=2;
 show variables like 'concurrent_insert';

=== modified file 'mysql-test/t/ps_11bugs.test'
--- a/mysql-test/t/ps_11bugs.test	2006-10-04 15:19:23 +0000
+++ b/mysql-test/t/ps_11bugs.test	2008-08-29 15:16:59 +0000
@@ -177,4 +177,15 @@ select * from t2;
 drop table t1;
 drop table t2;
 
+#
+# Bug #32124: crash if prepared statements refer to variables in the where
+# clause
+#
+
+CREATE TABLE t1 (a INT);
+PREPARE stmt FROM 'select 1 from `t1` where `a` = any (select (@@tmpdir))';
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1;
+
 --echo End of 5.0 tests.

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2008-07-30 11:07:37 +0000
+++ b/sql/item_func.cc	2008-08-29 15:16:59 +0000
@@ -4785,23 +4785,193 @@ Item_func_get_system_var(sys_var *var_ar
 }
 
 
-bool
-Item_func_get_system_var::fix_fields(THD *thd, Item **ref)
+void Item_func_get_system_var::fix_length_and_dec()
 {
-  Item *item;
-  DBUG_ENTER("Item_func_get_system_var::fix_fields");
+  maybe_null=0;
+  decimals=NOT_FIXED_DEC;
+  max_length=MAX_BLOB_WIDTH;
 
-  /*
-    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= var->item(thd, var_type, &component)))
-    DBUG_RETURN(1);                             // Impossible
-  item->set_name(name, 0, system_charset_info); // don't allocate a new name
-  thd->change_item_tree(ref, item);
+  if (var->check_type(var_type))
+  {
+    if (var_type != OPT_DEFAULT)
+    {
+      my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0),
+               var->name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
+      return;
+    }
+    /* As there was no local variable, return the global value */
+    var_type= OPT_GLOBAL;
+  }
+
+  switch (var->show_type())
+  {
+    case SHOW_LONG:
+    case SHOW_INT:
+      unsigned_flag= TRUE;
+      max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+      decimals=0;
+      break;
+    case SHOW_HA_ROWS:
+    case SHOW_LONGLONG:
+      unsigned_flag= FALSE;
+      max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+      decimals=0;
+      break;
+    case SHOW_CHAR:
+      max_length= MAX_BLOB_WIDTH;
+      collation.set(system_charset_info, DERIVATION_SYSCONST);
+      break;
+    case SHOW_MY_BOOL:
+      unsigned_flag= TRUE;
+      max_length= 1;
+      decimals=0;
+      break;
+    default:
+      my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
+      break;
+  }
+}
+
+
+void Item_func_get_system_var::print(String *str)
+
+{
+  str->append('(');
+  str->append(name, name_length);
+  str->append(')');
+}
+
+
+enum Item_result Item_func_get_system_var::result_type() const
+{
+  switch (var->show_type())
+  {
+    case SHOW_MY_BOOL:
+    case SHOW_INT:
+    case SHOW_LONG:
+    case SHOW_LONGLONG:
+    case SHOW_HA_ROWS:
+      return INT_RESULT;
+    case SHOW_CHAR: return STRING_RESULT;
+    default:
+      my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
+      break;
+  }
+}
+
+
+enum_field_types Item_func_get_system_var::field_type() const
+{
+  switch (var->show_type())
+  {
+    case SHOW_MY_BOOL:
+    case SHOW_INT:
+    case SHOW_LONG:
+    case SHOW_LONGLONG:
+    case SHOW_HA_ROWS:
+      return MYSQL_TYPE_LONGLONG;
+    case SHOW_CHAR: return MYSQL_TYPE_VARCHAR;
+    default:
+      my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
+      break;
+  }
+}
+
+
+double Item_func_get_system_var::val_real()
+{
+  return (double) val_int();
+}
 
-  DBUG_RETURN(0);
+
+longlong Item_func_get_system_var::val_int()
+{
+  THD *thd= current_thd;
+  switch (var->show_type())
+  {
+    case SHOW_INT:
+      {
+        uint value;
+        pthread_mutex_lock(&LOCK_global_system_variables);
+        value= *(uint*) var->value_ptr(thd, var_type, &component);
+        pthread_mutex_unlock(&LOCK_global_system_variables);
+        return (longlong)(ulonglong) value;
+      }
+    case SHOW_LONG:
+      {
+        ulong value;
+        pthread_mutex_lock(&LOCK_global_system_variables);
+        value= *(ulong*) var->value_ptr(thd, var_type, &component);
+        pthread_mutex_unlock(&LOCK_global_system_variables);
+        return (longlong)(ulonglong) value;
+      }
+    case SHOW_LONGLONG:
+      {
+        longlong value;
+        pthread_mutex_lock(&LOCK_global_system_variables);
+        value= *(longlong*) var->value_ptr(thd, var_type, &component);
+        pthread_mutex_unlock(&LOCK_global_system_variables);
+        return value;
+      }
+    case SHOW_HA_ROWS:
+      {
+        ha_rows value;
+        pthread_mutex_lock(&LOCK_global_system_variables);
+        value= *(ha_rows*) var->value_ptr(thd, var_type, &component);
+        pthread_mutex_unlock(&LOCK_global_system_variables);
+        return (longlong) value;
+      }
+    case SHOW_MY_BOOL:
+      return (longlong) (int32) *(my_bool*) 
+        var->value_ptr(thd, var_type, &component);
+    default:
+      my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
+      break;
+  }
+}
+
+
+String* Item_func_get_system_var::val_str(String* str)
+{
+  THD *thd= current_thd;
+  switch (var->show_type())
+  {
+    case SHOW_CHAR:
+    {
+      pthread_mutex_lock(&LOCK_global_system_variables);
+      char *cptr= (char*) var->value_ptr(thd, var_type, &component);
+      if (cptr)
+      {
+        if (str->copy(cptr, strlen(cptr), system_charset_info))
+          str= NULL;
+      }
+      else
+      {
+        null_value= TRUE;
+        str= NULL;
+      }
+      pthread_mutex_unlock(&LOCK_global_system_variables);
+      return str;
+    }
+    default:
+      my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
+      break;
+  }
+  return str;
+}
+
+
+bool Item_func_get_system_var::eq(const Item *item, bool binary_cmp) const
+{
+  /* Assume we don't have rtti */
+  if (this == item)
+    return 1;					// Same item is same.
+  /* Check if other type is also a get_user_var() object */
+  if (item->type() != FUNC_ITEM ||
+      ((Item_func*) item)->functype() != functype())
+    return 0;
+  Item_func_get_system_var *other=(Item_func_get_system_var*) item;
+  return (var == other->var && var_type == other->var_type);
 }
 
 

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2008-02-28 13:23:22 +0000
+++ b/sql/item_func.h	2008-08-29 15:16:59 +0000
@@ -55,7 +55,7 @@ public:
                   NOW_FUNC, TRIG_COND_FUNC,
                   SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
                   EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
-                  NEG_FUNC };
+                  NEG_FUNC, GSYSVAR_FUNC };
   enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
                        OPTIMIZE_EQUAL };
   enum Type type() const { return FUNC_ITEM; }
@@ -1401,17 +1401,19 @@ 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, Item **ref);
-  /*
-    Stubs for pure virtual methods. Should never be called: this
-    item is always substituted with a constant in fix_fields().
-  */
-  double val_real()         { 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); }
+  enum Functype functype() const { return GSYSVAR_FUNC; }
+  void fix_length_and_dec();
+  void print(String *str);
+  bool const_item() const { return true; }
+  table_map used_tables() const { return 0; }
+  enum Item_result result_type() const;
+  enum_field_types field_type() const;
+  double val_real();
+  longlong val_int();
+  String* val_str(String*);
   /* TODO: fix to support views */
   const char *func_name() const { return "get_system_var"; }
+  bool eq(const Item *item, bool binary_cmp) const;
 };
 
 

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2008-08-20 09:49:28 +0000
+++ b/tests/mysql_client_test.c	2008-08-29 15:16:59 +0000
@@ -37,6 +37,7 @@
 #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
 #define MAX_KEY MAX_INDEXES
 #define MAX_SERVER_ARGS 64
+#define MAX_BLOB_WIDTH 8192
 
 /* set default options */
 static int   opt_testcase = 0;
@@ -6934,6 +6935,9 @@ static void test_field_misc()
   char        table_type[NAME_LEN];
   ulong       type_length;
   int         rc;
+  MYSQL_FIELD *field;
+  CHARSET_INFO *cs;
+
 
   myheader("test_field_misc");
 
@@ -7012,12 +7016,21 @@ static void test_field_misc()
 
   DIE_UNLESS(1 == my_process_stmt_result(stmt));
 
+  if (!(field= mysql_fetch_field_direct(result, 0)))
+  {
+    fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***");
+    exit(1);
+  }
+  cs= get_charset(field->charsetnr, 0);
+  DIE_UNLESS(cs);
+
   verify_prepare_field(result, 0,
                        "@@table_type", "",   /* field and its org name */
                        mysql_get_server_version(mysql) <= 50000 ?
                        MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
                        "", "",              /* table and its org name */
-                       "", type_length, 0);   /* db name, length */
+                       /* db name, length */
+                       "", MAX_BLOB_WIDTH/cs->mbmaxlen, 0);
 
   mysql_free_result(result);
   mysql_stmt_close(stmt);
@@ -7038,7 +7051,8 @@ static void test_field_misc()
                        "@@max_error_count", "",   /* field and its org name */
                        MYSQL_TYPE_LONGLONG, /* field type */
                        "", "",              /* table and its org name */
-                       "", 10, 0);            /* db name, length */
+                       /* db name, length */
+                       "", MY_INT64_NUM_DECIMAL_DIGITS , 0);
 
   mysql_free_result(result);
   mysql_stmt_close(stmt);
@@ -7058,7 +7072,8 @@ static void test_field_misc()
                        "@@max_allowed_packet", "", /* field and its org name */
                        MYSQL_TYPE_LONGLONG, /* field type */
                        "", "",              /* table and its org name */
-                       "", 10, 0);          /* db name, length */
+                       /* db name, length */
+                       "", MY_INT64_NUM_DECIMAL_DIGITS, 0);
 
   mysql_free_result(result);
   mysql_stmt_close(stmt);

Thread
bzr commit into mysql-5.0 branch (kgeorge:2672) Bug#32124Georgi Kodinov29 Aug
  • Re: bzr commit into mysql-5.0 branch (kgeorge:2672) Bug#32124Sergei Golubchik1 Sep