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.cc243
1 files changed, 137 insertions, 106 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0f9ee512be1..bc7c95d8929 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2105,13 +2105,13 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
- entry->type= cached_result_type;
/*
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;
+ entry->update_query_id= thd->query_id;
+ cached_result_type= args[0]->result_type();
return 0;
}
@@ -2122,10 +2122,10 @@ Item_func_set_user_var::fix_length_and_dec()
maybe_null=args[0]->maybe_null;
max_length=args[0]->max_length;
decimals=args[0]->decimals;
- cached_result_type=args[0]->result_type();
}
-void Item_func_set_user_var::update_hash(void *ptr, uint length,
+
+bool Item_func_set_user_var::update_hash(void *ptr, uint length,
Item_result type,
CHARSET_INFO *cs,
Derivation dv)
@@ -2141,6 +2141,8 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length,
}
else
{
+ if (type == STRING_RESULT)
+ length++; // Store strings with end \0
if (length <= extra_size)
{
/* Save value in value struct */
@@ -2165,35 +2167,135 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length,
goto err;
}
}
+ if (type == STRING_RESULT)
+ {
+ length--; // Fix length change above
+ entry->value[length]= 0; // Store end \0
+ }
memcpy(entry->value,ptr,length);
entry->length= length;
entry->type=type;
entry->collation.set(cs, dv);
}
- return;
+ return 0;
err:
current_thd->fatal_error(); // Probably end of memory
- null_value=1;
- return;
+ null_value= 1;
+ return 1;
+}
+
+
+/* Get the value of a variable as a double */
+
+double user_var_entry::val(my_bool *null_value)
+{
+ if ((*null_value= (value == 0)))
+ return 0.0;
+
+ switch (type) {
+ case REAL_RESULT:
+ return *(double*) value;
+ case INT_RESULT:
+ return (double) *(longlong*) value;
+ case STRING_RESULT:
+ return atof(value); // This is null terminated
+ }
+ return 0.0; // Impossible
+}
+
+
+/* Get the value of a variable as an integer */
+
+longlong user_var_entry::val_int(my_bool *null_value)
+{
+ if ((*null_value= (value == 0)))
+ return LL(0);
+
+ switch (type) {
+ case REAL_RESULT:
+ return (longlong) *(double*) value;
+ case INT_RESULT:
+ return *(longlong*) value;
+ case STRING_RESULT:
+ return strtoull(value,NULL,10); // String is null terminated
+ }
+ return LL(0); // Impossible
}
+/* Get the value of a variable as a string */
+
+String *user_var_entry::val_str(my_bool *null_value, String *str,
+ uint decimals)
+{
+ if ((*null_value= (value == 0)))
+ return (String*) 0;
+
+ switch (type) {
+ case REAL_RESULT:
+ str->set(*(double*) value, decimals, &my_charset_bin);
+ break;
+ case INT_RESULT:
+ str->set(*(longlong*) value, &my_charset_bin);
+ break;
+ case STRING_RESULT:
+ if (str->copy(value, length, collation.collation))
+ str= 0; // EOM error
+ }
+ return(str);
+}
+
+
+/*
+ This functions is invoked on SET @variable or @variable:= expression.
+
+ SYNOPSIS
+ Item_func_set_user_var::update()
+
+ NOTES
+ We have to store the expression as such in the variable, independent of
+ the value method used by the user
+
+ RETURN
+ 0 Ok
+ 1 EOM Error
+
+*/
+
bool
Item_func_set_user_var::update()
{
+ bool res;
+ DBUG_ENTER("Item_func_set_user_var::update");
+ LINT_INIT(res);
+
switch (cached_result_type) {
case REAL_RESULT:
- (void) val();
+ {
+ double value=args[0]->val();
+ res= update_hash((void*) &value,sizeof(value), REAL_RESULT,
+ &my_charset_bin, DERIVATION_NONE);
break;
+ }
case INT_RESULT:
- (void) val_int();
+ {
+ longlong value=args[0]->val_int();
+ res= update_hash((void*) &value, sizeof(longlong), INT_RESULT,
+ &my_charset_bin, DERIVATION_NONE);
break;
+ }
+ break;
case STRING_RESULT:
{
- char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer,sizeof(buffer),&my_charset_bin);
- (void) val_str(&tmp);
+ String *tmp;
+ tmp=args[0]->val_str(&value);
+ if (!tmp) // Null value
+ res= update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin,
+ DERIVATION_NONE);
+ else
+ res= update_hash((void*) tmp->ptr(), tmp->length(), STRING_RESULT,
+ tmp->charset(), args[0]->collation.derivation);
break;
}
case ROW_RESULT:
@@ -2202,44 +2304,32 @@ Item_func_set_user_var::update()
DBUG_ASSERT(0);
break;
}
- return current_thd->is_fatal_error;
+ DBUG_RETURN(res);
}
-double
-Item_func_set_user_var::val()
+double Item_func_set_user_var::val()
{
- double value=args[0]->val();
- update_hash((void*) &value,sizeof(value), REAL_RESULT,
- &my_charset_bin, DERIVATION_NONE);
- return value;
+ update(); // Store expression
+ return entry->val(&null_value);
}
-longlong
-Item_func_set_user_var::val_int()
+longlong Item_func_set_user_var::val_int()
{
- longlong value=args[0]->val_int();
- update_hash((void*) &value, sizeof(longlong), INT_RESULT,
- &my_charset_bin, DERIVATION_NONE);
- return value;
+ update(); // Store expression
+ return entry->val_int(&null_value);
}
-String *
-Item_func_set_user_var::val_str(String *str)
+String *Item_func_set_user_var::val_str(String *str)
{
- String *res=args[0]->val_str(str);
- if (!res) // Null value
- update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin, DERIVATION_NONE);
- else
- update_hash((void*) res->ptr(), res->length(), STRING_RESULT,
- res->charset(), args[0]->collation.derivation);
- return res;
+ update(); // Store expression
+ return entry->val_str(&null_value, str, decimals);
}
void Item_func_set_user_var::print(String *str)
{
- str->append('(');
+ str->append("(@@",3);
str->append(name.str,name.length);
str->append(":=",2);
args[0]->print(str);
@@ -2247,89 +2337,29 @@ void Item_func_set_user_var::print(String *str)
}
-user_var_entry *Item_func_get_user_var::get_entry()
-{
- if (!var_entry || ! var_entry->value)
- {
- null_value=1;
- return 0;
- }
- null_value=0;
- return var_entry;
-}
-
-
String *
Item_func_get_user_var::val_str(String *str)
{
- user_var_entry *entry=get_entry();
- if (!entry)
- return NULL;
- switch (entry->type) {
- case REAL_RESULT:
- str->set(*(double*) entry->value,decimals, &my_charset_bin);
- break;
- case INT_RESULT:
- str->set(*(longlong*) entry->value, &my_charset_bin);
- break;
- case STRING_RESULT:
- if (str->copy(entry->value, entry->length, entry->collation.collation))
- {
- null_value=1;
- return NULL;
- }
- break;
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- break;
- }
- return str;
+ DBUG_ENTER("Item_func_get_user_var::val_str");
+ if (!var_entry)
+ return (String*) 0; // No such variable
+ DBUG_RETURN(var_entry->val_str(&null_value, str, decimals));
}
double Item_func_get_user_var::val()
{
- user_var_entry *entry=get_entry();
- if (!entry)
- return 0.0;
- switch (entry->type) {
- case REAL_RESULT:
- return *(double*) entry->value;
- case INT_RESULT:
- return (double) *(longlong*) entry->value;
- case STRING_RESULT:
- return atof(entry->value); // This is null terminated
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- return 0;
- }
- return 0.0; // Impossible
+ if (!var_entry)
+ return 0.0; // No such variable
+ return (var_entry->val(&null_value));
}
longlong Item_func_get_user_var::val_int()
{
- user_var_entry *entry=get_entry();
- if (!entry)
- return LL(0);
- switch (entry->type) {
- case REAL_RESULT:
- return (longlong) *(double*) entry->value;
- case INT_RESULT:
- return *(longlong*) entry->value;
- case STRING_RESULT:
- return strtoull(entry->value,NULL,10); // String is null terminated
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- return 0;
- }
- return LL(0); // Impossible
+ if (!var_entry)
+ return LL(0); // No such variable
+ return (var_entry->val_int(&null_value));
}
@@ -2348,7 +2378,8 @@ void Item_func_get_user_var::fix_length_and_dec()
decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH;
- var_entry= get_variable(&thd->user_vars, name, 0);
+ if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
+ null_value= 1;
if (!(opt_bin_log && is_update_query(thd->lex.sql_command)))
return;