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.cc432
1 files changed, 239 insertions, 193 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index f1c519896b4..6b1c0e340a5 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -22,6 +22,7 @@
#include "mysql_priv.h"
#include "slave.h" // for wait_for_master_pos
+#include "rpl_mi.h"
#include <m_ctype.h>
#include <hash.h>
#include <time.h>
@@ -35,7 +36,6 @@
#define sp_restore_security_context(A,B) while (0) {}
#endif
-
bool check_reserved_words(LEX_STRING *name)
{
if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") ||
@@ -142,7 +142,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end;
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
- char buff[STACK_BUFF_ALLOC]; // Max argument in function
+ uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
#endif
used_tables_cache= not_null_tables_cache= 0;
@@ -193,14 +193,16 @@ Item_func::fix_fields(THD *thd, Item **ref)
return FALSE;
}
-bool Item_func::walk (Item_processor processor, byte *argument)
+
+bool Item_func::walk(Item_processor processor, bool walk_subquery,
+ uchar *argument)
{
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
{
- if ((*arg)->walk(processor, argument))
+ if ((*arg)->walk(processor, walk_subquery, argument))
return 1;
}
}
@@ -256,7 +258,7 @@ void Item_func::traverse_cond(Cond_traverser traverser,
Item returned as the result of transformation of the root node
*/
-Item *Item_func::transform(Item_transformer transformer, byte *argument)
+Item *Item_func::transform(Item_transformer transformer, uchar *argument)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -309,8 +311,8 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument)
Item returned as the result of transformation of the root node
*/
-Item *Item_func::compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t)
+Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
@@ -323,7 +325,7 @@ Item *Item_func::compile(Item_analyzer analyzer, byte **arg_p,
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
- byte *arg_v= *arg_p;
+ uchar *arg_v= *arg_p;
Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *arg != new_item)
current_thd->change_item_tree(arg, new_item);
@@ -426,43 +428,44 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
}
-Field *Item_func::tmp_table_field(TABLE *t_arg)
+Field *Item_func::tmp_table_field(TABLE *table)
{
- Field *res;
- LINT_INIT(res);
+ Field *field;
+ LINT_INIT(field);
switch (result_type()) {
case INT_RESULT:
if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
- res= new Field_longlong(max_length, maybe_null, name, t_arg,
- unsigned_flag);
+ field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
else
- res= new Field_long(max_length, maybe_null, name, t_arg,
- unsigned_flag);
+ field= new Field_long(max_length, maybe_null, name, unsigned_flag);
break;
case REAL_RESULT:
- res= new Field_double(max_length, maybe_null, name, t_arg, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals);
break;
case STRING_RESULT:
- res= make_string_field(t_arg);
+ return make_string_field(table);
break;
case DECIMAL_RESULT:
- res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
- decimals,
- unsigned_flag),
- maybe_null, name, t_arg, decimals, unsigned_flag);
+ field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
+ decimals,
+ unsigned_flag),
+ maybe_null, name, decimals, unsigned_flag);
break;
case ROW_RESULT:
default:
// This case should never be chosen
DBUG_ASSERT(0);
+ field= 0;
break;
}
- return res;
+ if (field)
+ field->init(table);
+ return field;
}
-bool Item_func::is_expensive_processor(byte *arg)
+bool Item_func::is_expensive_processor(uchar *arg)
{
return is_expensive();
}
@@ -482,7 +485,7 @@ String *Item_real_func::val_str(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set(nr,decimals, &my_charset_bin);
+ str->set_real(nr,decimals, &my_charset_bin);
return str;
}
@@ -630,10 +633,7 @@ String *Item_int_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ str->set_int(nr, unsigned_flag, &my_charset_bin);
return str;
}
@@ -767,10 +767,7 @@ String *Item_func_numhybrid::val_str(String *str)
longlong nr= int_op();
if (null_value)
return 0; /* purecov: inspected */
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ str->set_int(nr, unsigned_flag, &my_charset_bin);
break;
}
case REAL_RESULT:
@@ -778,7 +775,7 @@ String *Item_func_numhybrid::val_str(String *str)
double nr= real_op();
if (null_value)
return 0; /* purecov: inspected */
- str->set(nr,decimals,&my_charset_bin);
+ str->set_real(nr,decimals,&my_charset_bin);
break;
}
case STRING_RESULT:
@@ -2119,6 +2116,18 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
}
+void Item_func_rand::seed_random(Item *arg)
+{
+ /*
+ TODO: do not do reinit 'rand' for every execute of PS/SP if
+ args[0] is a constant.
+ */
+ uint32 tmp= (uint32) arg->val_int();
+ randominit(rand, (uint32) (tmp*0x10001L+55555555L),
+ (uint32) (tmp*0x10000001L));
+}
+
+
bool Item_func_rand::fix_fields(THD *thd,Item **ref)
{
if (Item_real_func::fix_fields(thd, ref))
@@ -2126,11 +2135,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
used_tables_cache|= RAND_TABLE_BIT;
if (arg_count)
{ // Only use argument once in query
- if (!args[0]->const_during_execution())
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND");
- return TRUE;
- }
/*
Allocate rand structure once: we must use thd->stmt_arena
to create rand in proper mem_root if it's a prepared statement or
@@ -2142,20 +2146,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
if (!rand && !(rand= (struct rand_struct*)
thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE;
- /*
- PARAM_ITEM is returned if we're in statement prepare and consequently
- no placeholder value is set yet.
- */
- if (args[0]->type() != PARAM_ITEM)
- {
- /*
- TODO: do not do reinit 'rand' for every execute of PS/SP if
- args[0] is a constant.
- */
- uint32 tmp= (uint32) args[0]->val_int();
- randominit(rand, (uint32) (tmp*0x10001L+55555555L),
- (uint32) (tmp*0x10000001L));
- }
+
+ if (args[0]->const_item())
+ seed_random (args[0]);
}
else
{
@@ -2185,6 +2178,8 @@ void Item_func_rand::update_used_tables()
double Item_func_rand::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (arg_count && !args[0]->const_item())
+ seed_random (args[0]);
return my_rnd(rand);
}
@@ -2313,10 +2308,7 @@ String *Item_func_min_max::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ str->set_int(nr, unsigned_flag, &my_charset_bin);
return str;
}
case DECIMAL_RESULT:
@@ -2332,7 +2324,7 @@ String *Item_func_min_max::val_str(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set(nr,decimals,&my_charset_bin);
+ str->set_real(nr,decimals,&my_charset_bin);
return str;
}
case STRING_RESULT:
@@ -2683,7 +2675,7 @@ void Item_func_find_in_set::fix_length_and_dec()
if (args[0]->const_item() && args[1]->type() == FIELD_ITEM)
{
Field *field= ((Item_field*) args[1])->field;
- if (field->real_type() == FIELD_TYPE_SET)
+ if (field->real_type() == MYSQL_TYPE_SET)
{
String *find=args[0]->val_str(&value);
if (find)
@@ -2813,7 +2805,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
uint arg_count, Item **arguments)
{
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
- char buff[STACK_BUFF_ALLOC]; // Max argument in function
+ uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
#endif
DBUG_ENTER("Item_udf_func::fix_fields");
@@ -2925,7 +2917,8 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
String *res= arguments[i]->val_str(&buffers[i]);
if (arguments[i]->null_value)
continue;
- f_args.args[i]= (char*) res->ptr();
+ f_args.args[i]= (char*) res->c_ptr();
+ f_args.lengths[i]= res->length();
break;
}
case INT_RESULT:
@@ -3131,7 +3124,7 @@ String *Item_func_udf_float::val_str(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set(nr,decimals,&my_charset_bin);
+ str->set_real(nr,decimals,&my_charset_bin);
return str;
}
@@ -3150,10 +3143,7 @@ String *Item_func_udf_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ str->set_int(nr, unsigned_flag, &my_charset_bin);
return str;
}
@@ -3254,26 +3244,26 @@ static HASH hash_user_locks;
class User_level_lock
{
- char *key;
- uint key_length;
+ uchar *key;
+ size_t key_length;
public:
int count;
bool locked;
pthread_cond_t cond;
- pthread_t thread;
- ulong thread_id;
+ my_thread_id thread_id;
+ void set_thread(THD *thd) { thread_id= thd->thread_id; }
- User_level_lock(const char *key_arg,uint length, ulong id)
+ User_level_lock(const uchar *key_arg,uint length, ulong id)
:key_length(length),count(1),locked(1), thread_id(id)
{
- key=(char*) my_memdup((byte*) key_arg,length,MYF(0));
+ key= (uchar*) my_memdup(key_arg,length,MYF(0));
pthread_cond_init(&cond,NULL);
if (key)
{
- if (my_hash_insert(&hash_user_locks,(byte*) this))
+ if (my_hash_insert(&hash_user_locks,(uchar*) this))
{
- my_free((gptr) key,MYF(0));
+ my_free(key,MYF(0));
key=0;
}
}
@@ -3282,22 +3272,22 @@ public:
{
if (key)
{
- hash_delete(&hash_user_locks,(byte*) this);
- my_free((gptr) key,MYF(0));
+ hash_delete(&hash_user_locks,(uchar*) this);
+ my_free(key, MYF(0));
}
pthread_cond_destroy(&cond);
}
inline bool initialized() { return key != 0; }
friend void item_user_lock_release(User_level_lock *ull);
- friend char *ull_get_key(const User_level_lock *ull, uint *length,
- my_bool not_used);
+ friend uchar *ull_get_key(const User_level_lock *ull, size_t *length,
+ my_bool not_used);
};
-char *ull_get_key(const User_level_lock *ull, uint *length,
- my_bool not_used __attribute__((unused)))
+uchar *ull_get_key(const User_level_lock *ull, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
- *length=(uint) ull->key_length;
- return (char*) ull->key;
+ *length= ull->key_length;
+ return ull->key;
}
@@ -3367,8 +3357,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
THD* thd=current_thd;
User_level_lock* ull;
struct timespec abstime;
- int lock_name_len;
- lock_name_len=strlen(lock_name);
+ size_t lock_name_len;
+ lock_name_len= strlen(lock_name);
pthread_mutex_lock(&LOCK_user_locks);
if (thd->ull)
@@ -3383,8 +3373,9 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
this case, we will not be waiting, but rather, just waste CPU and
memory on the whole deal
*/
- if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks, lock_name,
- lock_name_len))))
+ if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
+ (uchar*) lock_name,
+ lock_name_len))))
{
pthread_mutex_unlock(&LOCK_user_locks);
return;
@@ -3415,7 +3406,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
else
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
thd->ull=ull;
}
pthread_mutex_unlock(&LOCK_user_locks);
@@ -3482,10 +3473,11 @@ longlong Item_func_get_lock::val_int()
}
if (!(ull= ((User_level_lock *) hash_search(&hash_user_locks,
- (byte*) res->ptr(),
- res->length()))))
+ (uchar*) res->ptr(),
+ (size_t) res->length()))))
{
- ull=new User_level_lock(res->ptr(),res->length(), thd->thread_id);
+ ull= new User_level_lock((uchar*) res->ptr(), (size_t) res->length(),
+ thd->thread_id);
if (!ull || !ull->initialized())
{
delete ull;
@@ -3493,8 +3485,7 @@ longlong Item_func_get_lock::val_int()
null_value=1; // Probably out of memory
DBUG_RETURN(0);
}
- ull->thread=thd->real_id;
- ull->thread_id=thd->thread_id;
+ ull->set_thread(thd);
thd->ull=ull;
pthread_mutex_unlock(&LOCK_user_locks);
DBUG_PRINT("info", ("made new lock"));
@@ -3541,7 +3532,7 @@ longlong Item_func_get_lock::val_int()
else // We got the lock
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
ull->thread_id= thd->thread_id;
thd->ull=ull;
error=0;
@@ -3586,18 +3577,18 @@ longlong Item_func_release_lock::val_int()
result=0;
pthread_mutex_lock(&LOCK_user_locks);
if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
- (const byte*) res->ptr(),
- res->length()))))
+ (const uchar*) res->ptr(),
+ (size_t) res->length()))))
{
null_value=1;
}
else
{
- DBUG_PRINT("info", ("ull->locked=%d ull->thread=%ld thd=%ld",
+ DBUG_PRINT("info", ("ull->locked=%d ull->thread=%lu thd=%lu",
(int) ull->locked,
- (long)ull->thread,
- (long)thd->real_id));
- if (ull->locked && pthread_equal(thd->real_id,ull->thread))
+ (long)ull->thread_id,
+ (long)thd->thread_id));
+ if (ull->locked && current_thd->thread_id == ull->thread_id)
{
DBUG_PRINT("info", ("release lock"));
result=1; // Release is ok
@@ -3610,35 +3601,6 @@ longlong Item_func_release_lock::val_int()
}
-bool Item_func_last_insert_id::fix_fields(THD *thd, Item **ref)
-{
- DBUG_ASSERT(fixed == 0);
-
- if (Item_int_func::fix_fields(thd, ref))
- return TRUE;
-
- if (arg_count == 0)
- {
- if (!thd->last_insert_id_used)
- {
- /*
- As this statement calls LAST_INSERT_ID(), set
- THD::last_insert_id_used and remember first generated insert
- id of the previous statement in THD::current_insert_id.
- */
- thd->last_insert_id_used= TRUE;
- thd->last_insert_id_used_bin_log= TRUE;
- thd->current_insert_id= thd->last_insert_id;
- }
- null_value= FALSE;
- }
-
- thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
-
- return FALSE;
-}
-
-
longlong Item_func_last_insert_id::val_int()
{
THD *thd= current_thd;
@@ -3646,15 +3608,22 @@ longlong Item_func_last_insert_id::val_int()
if (arg_count)
{
longlong value= args[0]->val_int();
- thd->insert_id(value);
null_value= args[0]->null_value;
+ /*
+ LAST_INSERT_ID(X) must affect the client's mysql_insert_id() as
+ documented in the manual. We don't want to touch
+ first_successful_insert_id_in_cur_stmt because it would make
+ LAST_INSERT_ID(X) take precedence over an generated auto_increment
+ value for this row.
+ */
+ thd->arg_of_last_insert_id_function= TRUE;
+ thd->first_successful_insert_id_in_prev_stmt= value;
return value;
}
-
- return thd->current_insert_id;
+ thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return thd->read_first_successful_insert_id_in_prev_stmt();
}
-
/* This function is just used to test speed of different functions */
longlong Item_func_benchmark::val_int()
@@ -3664,21 +3633,31 @@ longlong Item_func_benchmark::val_int()
String tmp(buff,sizeof(buff), &my_charset_bin);
my_decimal tmp_decimal;
THD *thd=current_thd;
+ ulong loop_count;
+
+ loop_count= (ulong) args[0]->val_int();
+ if (args[0]->null_value)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ null_value=0;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
{
- switch (args[0]->result_type()) {
+ switch (args[1]->result_type()) {
case REAL_RESULT:
- (void) args[0]->val_real();
+ (void) args[1]->val_real();
break;
case INT_RESULT:
- (void) args[0]->val_int();
+ (void) args[1]->val_int();
break;
case STRING_RESULT:
- (void) args[0]->val_str(&tmp);
+ (void) args[1]->val_str(&tmp);
break;
case DECIMAL_RESULT:
- (void) args[0]->val_decimal(&tmp_decimal);
+ (void) args[1]->val_decimal(&tmp_decimal);
break;
case ROW_RESULT:
default:
@@ -3694,13 +3673,9 @@ longlong Item_func_benchmark::val_int()
void Item_func_benchmark::print(String *str)
{
str->append(STRING_WITH_LEN("benchmark("));
- char buffer[20];
- // my_charset_bin is good enough for numbers
- String st(buffer, sizeof(buffer), &my_charset_bin);
- st.set((ulonglong)loop_count, &my_charset_bin);
- str->append(st);
- str->append(',');
args[0]->print(str);
+ str->append(',');
+ args[1]->print(str);
str->append(')');
}
@@ -3753,7 +3728,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
{
user_var_entry *entry;
- if (!(entry = (user_var_entry*) hash_search(hash, (byte*) name.str,
+ if (!(entry = (user_var_entry*) hash_search(hash, (uchar*) name.str,
name.length)) &&
create_if_not_exists)
{
@@ -3783,7 +3758,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->used_query_id=current_thd->query_id;
entry->type=STRING_RESULT;
memcpy(entry->name.str, name.str, name.length+1);
- if (my_hash_insert(hash,(byte*) entry))
+ if (my_hash_insert(hash,(uchar*) entry))
{
my_free((char*) entry,MYF(0));
return 0;
@@ -3845,6 +3820,23 @@ Item_func_set_user_var::fix_length_and_dec()
/*
+ Mark field in read_map
+
+ NOTES
+ This is used by filesort to register used fields in a a temporary
+ column read set or to register used fields in a view
+*/
+
+bool Item_func_set_user_var::register_field_in_read_map(uchar *arg)
+{
+ TABLE *table= (TABLE *) arg;
+ if (result_field->table == table || !table)
+ bitmap_set_bit(result_field->table->read_set, result_field->field_index);
+ return 0;
+}
+
+
+/*
Set value to user variable.
SYNOPSYS
@@ -4013,7 +4005,7 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
switch (type) {
case REAL_RESULT:
- str->set(*(double*) value, decimals, &my_charset_bin);
+ str->set_real(*(double*) value, decimals, &my_charset_bin);
break;
case INT_RESULT:
if (!unsigned_flag)
@@ -4385,11 +4377,11 @@ int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions,
else if (result_type() == DECIMAL_RESULT)
{
my_decimal decimal_value;
- my_decimal *value= entry->val_decimal(&null_value, &decimal_value);
+ my_decimal *val= entry->val_decimal(&null_value, &decimal_value);
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- error=field->store_decimal(value);
+ error=field->store_decimal(val);
}
else
{
@@ -4537,7 +4529,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
> set @a:=1;
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
We have to write to binlog value @a= 1.
-
+
We allocate the user_var_event on user_var_events_alloc pool, not on
the this-statement-execution pool because in SPs user_var_event objects
may need to be valid after current [SP] statement execution pool is
@@ -4547,7 +4539,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
if (!(user_var_event= (BINLOG_USER_VAR_EVENT *)
alloc_root(thd->user_var_events_alloc, size)))
goto err;
-
+
user_var_event->value= (char*) user_var_event +
ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
user_var_event->user_var_event= var_entry;
@@ -4567,9 +4559,9 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
}
/* Mark that this variable has been used by this query */
var_entry->used_query_id= thd->query_id;
- if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
+ if (insert_dynamic(&thd->user_var_events, (uchar*) &user_var_event))
goto err;
-
+
*out_entry= var_entry;
return 0;
@@ -4578,7 +4570,6 @@ err:
return 1;
}
-
void Item_func_get_user_var::fix_length_and_dec()
{
THD *thd=current_thd;
@@ -4589,10 +4580,19 @@ void Item_func_get_user_var::fix_length_and_dec()
error= get_var_with_binlog(thd, thd->lex->sql_command, name, &var_entry);
+ /*
+ If the variable didn't exist it has been created as a STRING-type.
+ 'var_entry' is NULL only if there occured an error during the call to
+ get_var_with_binlog.
+ */
if (var_entry)
{
+ m_cached_result_type= var_entry->type;
+ unsigned_flag= var_entry->unsigned_flag;
+ max_length= var_entry->length;
+
collation.set(var_entry->collation);
- switch (var_entry->type) {
+ switch(m_cached_result_type) {
case REAL_RESULT:
max_length= DBL_DIG + 8;
break;
@@ -4617,6 +4617,8 @@ void Item_func_get_user_var::fix_length_and_dec()
{
collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
null_value= 1;
+ m_cached_result_type= STRING_RESULT;
+ max_length= MAX_BLOB_WIDTH;
}
if (error)
@@ -4634,12 +4636,7 @@ bool Item_func_get_user_var::const_item() const
enum Item_result Item_func_get_user_var::result_type() const
{
- user_var_entry *entry;
- if (!(entry = (user_var_entry*) hash_search(&current_thd->user_vars,
- (byte*) name.str,
- name.length)))
- return STRING_RESULT;
- return entry->type;
+ return m_cached_result_type;
}
@@ -4940,7 +4937,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
return TRUE;
}
table=((Item_field *)item)->field->table;
- if (!(table->file->table_flags() & HA_CAN_FULLTEXT))
+ if (!(table->file->ha_table_flags() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
return 1;
@@ -5059,7 +5056,7 @@ double Item_func_match::val_real()
DBUG_RETURN(-1.0);
if (key != NO_SUCH_KEY && table->null_row) /* NULL row from an outer join */
- return 0.0;
+ DBUG_RETURN(0.0);
if (join_key)
{
@@ -5074,11 +5071,10 @@ double Item_func_match::val_real()
if ((null_value= (a == 0)) || !a->length())
DBUG_RETURN(0);
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
- (byte *)a->ptr(), a->length()));
+ (uchar *)a->ptr(), a->length()));
}
- else
- DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
- table->record[0], 0));
+ DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
+ table->record[0], 0));
}
void Item_func_match::print(String *str)
@@ -5117,7 +5113,7 @@ longlong Item_func_bit_xor::val_int()
thd Thread handler
var_type global / session
name Name of base or system variable
- component Component.
+ component Component
NOTES
If component.str = 0 then the variable name is in 'name'
@@ -5145,7 +5141,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
component_name= &component; // Empty string
}
- if (!(var= find_sys_var(base_name->str, base_name->length)))
+ if (!(var= find_sys_var(thd, base_name->str, base_name->length)))
return 0;
if (component.str)
{
@@ -5190,8 +5186,8 @@ longlong Item_func_is_free_lock::val_int()
}
pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
- res->length());
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 1;
@@ -5209,8 +5205,8 @@ longlong Item_func_is_used_lock::val_int()
return 0;
pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
- res->length());
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 0;
@@ -5236,7 +5232,8 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
{
maybe_null= 1;
m_name->init_qname(current_thd);
- dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+ dummy_table= (TABLE*) sql_calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
+ dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
}
@@ -5246,7 +5243,8 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
{
maybe_null= 1;
m_name->init_qname(current_thd);
- dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+ dummy_table= (TABLE*) sql_calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
+ dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
}
@@ -5259,7 +5257,7 @@ Item_func_sp::cleanup()
sp_result_field= NULL;
}
m_sp= NULL;
- dummy_table->s= NULL;
+ dummy_table->alias= NULL;
Item_func::cleanup();
}
@@ -5307,17 +5305,16 @@ Item_func_sp::func_name() const
@retval TRUE is returned on an error
@retval FALSE is returned on success.
*/
+
bool
Item_func_sp::init_result_field(THD *thd)
{
- DBUG_ENTER("Item_func_sp::init_result_field");
-
- char *empty_name= (char *) "";
+ LEX_STRING empty_name= { C_STRING_WITH_LEN("") };
TABLE_SHARE *share;
+ DBUG_ENTER("Item_func_sp::init_result_field");
DBUG_ASSERT(m_sp == NULL);
DBUG_ASSERT(sp_result_field == NULL);
- DBUG_ASSERT(dummy_table->s == NULL);
if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
&thd->sp_func_cache, TRUE)))
@@ -5332,38 +5329,43 @@ Item_func_sp::init_result_field(THD *thd)
Below we "create" a dummy table by initializing
the needed pointers.
*/
- dummy_table->s= share= &dummy_table->share_not_to_be_used;
- dummy_table->alias = empty_name;
+
+ share= dummy_table->s;
+ dummy_table->alias = "";
dummy_table->maybe_null = maybe_null;
dummy_table->in_use= thd;
dummy_table->copy_blobs= TRUE;
share->table_cache_key = empty_name;
share->table_name = empty_name;
- if (!(sp_result_field= m_sp->create_result_field(max_length, name, dummy_table)))
+ if (!(sp_result_field= m_sp->create_result_field(max_length, name,
+ dummy_table)))
{
DBUG_RETURN(TRUE);
}
if (sp_result_field->pack_length() > sizeof(result_buf))
{
- sp_result_field->move_field(sql_alloc(sp_result_field->pack_length()));
- } else {
- sp_result_field->move_field(result_buf);
+ void *tmp;
+ if (!(tmp= sql_alloc(sp_result_field->pack_length())))
+ DBUG_RETURN(TRUE);
+ sp_result_field->move_field((uchar*) tmp);
}
+ else
+ sp_result_field->move_field(result_buf);
sp_result_field->null_ptr= (uchar *) &null_value;
sp_result_field->null_bit= 1;
-
-
DBUG_RETURN(FALSE);
}
+
/**
@brief Initialize local members with values from the Field interface.
@note called from Item::fix_fields.
*/
+
void Item_func_sp::fix_length_and_dec()
{
DBUG_ENTER("Item_func_sp::fix_length_and_dec");
@@ -5378,6 +5380,7 @@ void Item_func_sp::fix_length_and_dec()
DBUG_VOID_RETURN;
}
+
/**
@brief Execute function & store value in field.
@@ -5391,12 +5394,6 @@ Item_func_sp::execute()
{
THD *thd= current_thd;
- /*
- Get field in virtual tmp table to store result. Create the field if
- invoked first time.
- */
-
-
/* Execute function and store the return value in the field. */
if (execute_impl(thd))
@@ -5448,6 +5445,18 @@ Item_func_sp::execute_impl(THD *thd)
goto error;
/*
+ Throw an error if a non-deterministic function is called while
+ statement-based replication (SBR) is active.
+ */
+ if (!m_sp->m_chistics->detistic && !trust_function_creators &&
+ (mysql_bin_log.is_open() &&
+ thd->variables.binlog_format == BINLOG_FORMAT_STMT))
+ {
+ my_error(ER_BINLOG_ROW_RBR_TO_SBR, MYF(0));
+ goto error;
+ }
+
+ /*
Disable the binlogging if this is not a SELECT statement. If this is a
SELECT, leave binlogging on, so execute_function() code writes the
function call into binlog.
@@ -5580,7 +5589,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
Security_context *save_secutiry_ctx;
res= set_routine_security_ctx(thd, m_sp, false, &save_secutiry_ctx);
if (!res)
- sp_restore_security_context(thd, save_secutiry_ctx);
+ m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -5596,3 +5605,40 @@ void Item_func_sp::update_used_tables()
if (!m_sp->m_chistics->detistic)
used_tables_cache |= RAND_TABLE_BIT;
}
+
+
+/*
+ uuid_short handling.
+
+ The short uuid is defined as a longlong that contains the following bytes:
+
+ Bytes Comment
+ 1 Server_id & 255
+ 4 Startup time of server in seconds
+ 3 Incrementor
+
+ This means that an uuid is guaranteed to be unique
+ even in a replication environment if the following holds:
+
+ - The last byte of the server id is unique
+ - If you between two shutdown of the server don't get more than
+ an average of 2^24 = 16M calls to uuid_short() per second.
+*/
+
+ulonglong uuid_value;
+
+void uuid_short_init()
+{
+ uuid_value= ((((ulonglong) server_id) << 56) +
+ (((ulonglong) server_start_time) << 24));
+}
+
+
+longlong Item_func_uuid_short::val_int()
+{
+ ulonglong val;
+ pthread_mutex_lock(&LOCK_uuid_generator);
+ val= uuid_value++;
+ pthread_mutex_unlock(&LOCK_uuid_generator);
+ return (longlong) val;
+}