summaryrefslogtreecommitdiff
path: root/sql/item_func.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r--sql/item_func.cc424
1 files changed, 399 insertions, 25 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b3c50718273..87d15c7968d 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3803,6 +3803,25 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
return entry;
}
+
+bool Item_func_set_user_var::set_entry(THD *thd, bool create_if_not_exists)
+{
+ if (thd == entry_thd && entry)
+ goto end; // update entry->update_query_id for PS
+ entry_thd= thd;
+ if (!(entry= get_variable(&thd->user_vars, name, create_if_not_exists)))
+ return TRUE;
+ /*
+ Remember the last query which updated it, this way a query can later know
+ if this variable is a constant item in the query (it is if update_query_id
+ is different from query_id).
+ */
+end:
+ entry->update_query_id= thd->query_id;
+ return FALSE;
+}
+
+
/*
When a user variable is updated (in a SET command or a query like
SELECT @a:= ).
@@ -3812,15 +3831,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
/* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
- if (Item_func::fix_fields(thd, ref) ||
- !(entry= get_variable(&thd->user_vars, name, 1)))
+ if (Item_func::fix_fields(thd, ref) || set_entry(thd, TRUE))
return TRUE;
- /*
- Remember the last query which updated it, this way a query can later know
- if this variable is a constant item in the query (it is if update_query_id
- is different from query_id).
- */
- entry->update_query_id= thd->query_id;
/*
As it is wrong and confusing to associate any
character set with NULL, @a should be latin2
@@ -4791,36 +4803,398 @@ 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)
+ :var(var_arg), var_type(var_type_arg), orig_var_type(var_type_arg),
+ component(*component_arg), cache_present(0)
{
/* 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, Item **ref)
+bool Item_func_get_system_var::is_written_to_binlog()
{
- Item *item;
- DBUG_ENTER("Item_func_get_system_var::fix_fields");
+ return var->is_written_to_binlog(var_type);
+}
- /*
- 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);
- DBUG_RETURN(0);
+void Item_func_get_system_var::fix_length_and_dec()
+{
+ maybe_null=0;
+
+ 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:
+ case SHOW_HA_ROWS:
+ unsigned_flag= TRUE;
+ max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+ decimals=0;
+ break;
+ case SHOW_LONGLONG:
+ unsigned_flag= FALSE;
+ max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+ decimals=0;
+ break;
+ case SHOW_CHAR:
+ case SHOW_CHAR_PTR:
+ collation.set(system_charset_info, DERIVATION_SYSCONST);
+ max_length= MAX_BLOB_WIDTH;
+ decimals=NOT_FIXED_DEC;
+ break;
+ case SHOW_MY_BOOL:
+ unsigned_flag= FALSE;
+ max_length= 1;
+ decimals=0;
+ break;
+ case SHOW_DOUBLE:
+ unsigned_flag= FALSE;
+ decimals= 6;
+ max_length= DBL_DIG + 6;
+ break;
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ break;
+ }
}
-bool Item_func_get_system_var::is_written_to_binlog()
+void Item_func_get_system_var::print(String *str, enum_query_type query_type)
{
- return var->is_written_to_binlog(var_type);
+ str->append(name, name_length);
+}
+
+
+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:
+ case SHOW_CHAR_PTR:
+ return STRING_RESULT;
+ case SHOW_DOUBLE:
+ return REAL_RESULT;
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ return STRING_RESULT; // keep the compiler happy
+ }
+}
+
+
+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:
+ case SHOW_CHAR_PTR:
+ return MYSQL_TYPE_VARCHAR;
+ case SHOW_DOUBLE:
+ return MYSQL_TYPE_DOUBLE;
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ return MYSQL_TYPE_VARCHAR; // keep the compiler happy
+ }
+}
+
+
+#define get_sys_var_safe(type) \
+do { \
+ type value; \
+ pthread_mutex_lock(&LOCK_global_system_variables); \
+ value= *(type*) var->value_ptr(thd, var_type, &component); \
+ pthread_mutex_unlock(&LOCK_global_system_variables); \
+ cache_present |= GET_SYS_VAR_CACHE_LONG; \
+ used_query_id= thd->query_id; \
+ cached_llval= null_value ? 0 : (longlong) value; \
+ cached_null_value= null_value; \
+ return cached_llval; \
+} while (0)
+
+
+longlong Item_func_get_system_var::val_int()
+{
+ THD *thd= current_thd;
+
+ if (cache_present && thd->query_id == used_query_id)
+ {
+ if (cache_present & GET_SYS_VAR_CACHE_LONG)
+ {
+ null_value= cached_null_value;
+ return cached_llval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_DOUBLE)
+ {
+ null_value= cached_null_value;
+ cached_llval= (longlong) cached_dval;
+ cache_present|= GET_SYS_VAR_CACHE_LONG;
+ return cached_llval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_STRING)
+ {
+ null_value= cached_null_value;
+ if (!null_value)
+ cached_llval= longlong_from_string_with_check (cached_strval.charset(),
+ cached_strval.c_ptr(),
+ cached_strval.c_ptr() +
+ cached_strval.length());
+ else
+ cached_llval= 0;
+ cache_present|= GET_SYS_VAR_CACHE_LONG;
+ return cached_llval;
+ }
+ }
+
+ switch (var->show_type())
+ {
+ case SHOW_INT: get_sys_var_safe (uint);
+ case SHOW_LONG: get_sys_var_safe (ulong);
+ case SHOW_LONGLONG: get_sys_var_safe (longlong);
+ case SHOW_HA_ROWS: get_sys_var_safe (ha_rows);
+ case SHOW_MY_BOOL: get_sys_var_safe (my_bool);
+ case SHOW_DOUBLE:
+ {
+ double dval= val_real();
+
+ used_query_id= thd->query_id;
+ cached_llval= (longlong) dval;
+ cache_present|= GET_SYS_VAR_CACHE_LONG;
+ return cached_llval;
+ }
+ case SHOW_CHAR:
+ case SHOW_CHAR_PTR:
+ {
+ String *str_val= val_str(NULL);
+
+ if (str_val && str_val->length())
+ cached_llval= longlong_from_string_with_check (system_charset_info,
+ str_val->c_ptr(),
+ str_val->c_ptr() +
+ str_val->length());
+ else
+ {
+ null_value= TRUE;
+ cached_llval= 0;
+ }
+
+ cache_present|= GET_SYS_VAR_CACHE_LONG;
+ return cached_llval;
+ }
+
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ return 0; // keep the compiler happy
+ }
+}
+
+
+String* Item_func_get_system_var::val_str(String* str)
+{
+ THD *thd= current_thd;
+
+ if (cache_present && thd->query_id == used_query_id)
+ {
+ if (cache_present & GET_SYS_VAR_CACHE_STRING)
+ {
+ null_value= cached_null_value;
+ return null_value ? NULL : &cached_strval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_LONG)
+ {
+ null_value= cached_null_value;
+ if (!null_value)
+ cached_strval.set (cached_llval, collation.collation);
+ cache_present|= GET_SYS_VAR_CACHE_STRING;
+ return null_value ? NULL : &cached_strval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_DOUBLE)
+ {
+ null_value= cached_null_value;
+ if (!null_value)
+ cached_strval.set_real (cached_dval, decimals, collation.collation);
+ cache_present|= GET_SYS_VAR_CACHE_STRING;
+ return null_value ? NULL : &cached_strval;
+ }
+ }
+
+ str= &cached_strval;
+ switch (var->show_type())
+ {
+ case SHOW_CHAR:
+ case SHOW_CHAR_PTR:
+ {
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ char *cptr= var->show_type() == SHOW_CHAR_PTR ?
+ *(char**) var->value_ptr(thd, var_type, &component) :
+ (char*) var->value_ptr(thd, var_type, &component);
+ if (cptr)
+ {
+ if (str->copy(cptr, strlen(cptr), collation.collation))
+ {
+ null_value= TRUE;
+ str= NULL;
+ }
+ }
+ else
+ {
+ null_value= TRUE;
+ str= NULL;
+ }
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ break;
+ }
+
+ case SHOW_INT:
+ case SHOW_LONG:
+ case SHOW_LONGLONG:
+ case SHOW_HA_ROWS:
+ case SHOW_MY_BOOL:
+ str->set (val_int(), collation.collation);
+ break;
+ case SHOW_DOUBLE:
+ str->set_real (val_real(), decimals, collation.collation);
+ break;
+
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ str= NULL;
+ break;
+ }
+
+ cache_present|= GET_SYS_VAR_CACHE_STRING;
+ used_query_id= thd->query_id;
+ cached_null_value= null_value;
+ return str;
+}
+
+
+double Item_func_get_system_var::val_real()
+{
+ THD *thd= current_thd;
+
+ if (cache_present && thd->query_id == used_query_id)
+ {
+ if (cache_present & GET_SYS_VAR_CACHE_DOUBLE)
+ {
+ null_value= cached_null_value;
+ return cached_dval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_LONG)
+ {
+ null_value= cached_null_value;
+ cached_dval= (double)cached_llval;
+ cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
+ return cached_dval;
+ }
+ else if (cache_present & GET_SYS_VAR_CACHE_STRING)
+ {
+ null_value= cached_null_value;
+ if (!null_value)
+ cached_dval= double_from_string_with_check (cached_strval.charset(),
+ cached_strval.c_ptr(),
+ cached_strval.c_ptr() +
+ cached_strval.length());
+ else
+ cached_dval= 0;
+ cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
+ return cached_dval;
+ }
+ }
+
+ switch (var->show_type())
+ {
+ case SHOW_DOUBLE:
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ cached_dval= *(double*) var->value_ptr(thd, var_type, &component);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ used_query_id= thd->query_id;
+ cached_null_value= null_value;
+ if (null_value)
+ cached_dval= 0;
+ cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
+ return cached_dval;
+ case SHOW_CHAR:
+ case SHOW_CHAR_PTR:
+ {
+ char *cptr;
+
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ cptr= var->show_type() == SHOW_CHAR ?
+ (char*) var->value_ptr(thd, var_type, &component) :
+ *(char**) var->value_ptr(thd, var_type, &component);
+ if (cptr)
+ cached_dval= double_from_string_with_check (system_charset_info,
+ cptr, cptr + strlen (cptr));
+ else
+ {
+ null_value= TRUE;
+ cached_dval= 0;
+ }
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ used_query_id= thd->query_id;
+ cached_null_value= null_value;
+ cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
+ return cached_dval;
+ }
+ case SHOW_INT:
+ case SHOW_LONG:
+ case SHOW_LONGLONG:
+ case SHOW_HA_ROWS:
+ case SHOW_MY_BOOL:
+ cached_dval= (double) val_int();
+ cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
+ used_query_id= thd->query_id;
+ cached_null_value= null_value;
+ return cached_dval;
+ default:
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ return 0;
+ }
+}
+
+
+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);
+}
+
+
+void Item_func_get_system_var::cleanup()
+{
+ Item_func::cleanup();
+ cache_present= 0;
+ var_type= orig_var_type;
+ cached_strval.free();
}