summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <konstantin@mysql.com>2005-07-16 03:29:13 +0400
committerunknown <konstantin@mysql.com>2005-07-16 03:29:13 +0400
commite83e10533194cca56596226e5c2c08c7bb6d5b9a (patch)
tree7b2a374b6d05a129d4b7e3e16593f7244bdccf90 /sql
parent0f41fb4234c58d9f17385c8f77fe02aa6a1f5b96 (diff)
downloadmariadb-git-e83e10533194cca56596226e5c2c08c7bb6d5b9a.tar.gz
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. mysql-test/r/ps.result: - test results fixed (Bug#9359). mysql-test/t/ps.test: - add a test case for Bug#9359 "Prepared statements take snapshot of system vars at PREPARE time" sql/item_func.cc: - 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 sql/item_func.h: Add a new item, Item_func_get_system_var sql/mysql_priv.h: Move necessary declarations to make set_var.h objects visible in item_func.h sql/set_var.cc: - 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/set_var.h: - declaration of enum_var_type moved to mysql_priv.h
Diffstat (limited to 'sql')
-rw-r--r--sql/item_func.cc68
-rw-r--r--sql/item_func.h23
-rw-r--r--sql/mysql_priv.h10
-rw-r--r--sql/set_var.cc14
-rw-r--r--sql/set_var.h5
5 files changed, 70 insertions, 50 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0128209cb22..c8f1d209d26 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3031,6 +3031,36 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
}
+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 @@ longlong Item_func_bit_xor::val_int()
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 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
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 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
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);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 6b6e5d4b8ec..5e36f9863bb 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -988,6 +988,29 @@ public:
};
+/* 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:
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 722b76796b2..351f12acad2 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -358,6 +358,11 @@ inline THD *_current_thd(void)
#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 bool sql_cache_init();
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 */
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b0fa61a12bc..f7700d18607 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1551,15 +1551,7 @@ err:
/*
Return an Item for a variable. Used with @@[global.]variable_name
-
If type is not given, return local value if exists, else global
-
- We have to use netprintf() instead of my_error() here as this is
- called on the parsing stage.
-
- TODO:
- With prepared statements/stored procedures this has to be fixed
- to create an item that gets the current value at fix_fields() stage.
*/
Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
@@ -1568,8 +1560,8 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
{
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 +1605,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
return tmp;
}
default:
- net_printf(thd, ER_VAR_CANT_BE_READ, name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
}
return 0;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index d452ba03367..2ac4fc2c260 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -30,11 +30,6 @@ class set_var;
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);