summaryrefslogtreecommitdiffstats
path: root/sql/item_func.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r--sql/item_func.cc129
1 files changed, 90 insertions, 39 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index dd056ac4..9743c9a2 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -72,6 +72,9 @@ bool check_reserved_words(const LEX_CSTRING *name)
return FALSE;
}
+void pause_execution(THD *thd, double timeout);
+static int do_pause(THD *thd, Interruptible_wait *timed_cond,
+ mysql_cond_t *cond, double timeout);
/**
Test if the sum of arguments overflows the ulonglong range.
@@ -1917,6 +1920,18 @@ void Item_func_abs::fix_length_and_dec_int()
set_handler(type_handler_long_or_longlong());
}
+void Item_func_abs::fix_length_and_dec_sint_ge0()
+{
+ /*
+ We're converting slong_ge0 to slong/slonglong.
+ Add one character for the sign into max_length.
+ */
+ max_length= args[0]->decimal_precision() + 1/*sign*/;
+ DBUG_ASSERT(!args[0]->unsigned_flag);
+ unsigned_flag= false;
+ set_handler(type_handler_long_or_longlong());
+}
+
void Item_func_abs::fix_length_and_dec_double()
{
@@ -2594,6 +2609,22 @@ void Item_func_round::fix_arg_int(const Type_handler *preferred,
}
+void Item_func_round::fix_arg_slong_ge0()
+{
+ DBUG_ASSERT(!args[0]->unsigned_flag);
+ DBUG_ASSERT(args[0]->decimals == 0);
+ Type_std_attributes::set(args[0]);
+ /*
+ We're converting the data type from slong_ge0 to slong/slonglong.
+ Add one character for the sign,
+ to change max_length notation from "max_length digits" to
+ "max_length-1 digits and the sign".
+ */
+ max_length+= 1/*sign*/ + test_if_length_can_increase();
+ set_handler(type_handler_long_or_longlong());
+}
+
+
void Item_func_round::fix_arg_hex_hybrid()
{
DBUG_ASSERT(args[0]->decimals == 0);
@@ -2610,12 +2641,12 @@ void Item_func_round::fix_arg_hex_hybrid()
}
-double my_double_round(double value, longlong dec, bool dec_unsigned,
+double my_double_round(double value, longlong dec_value, bool dec_unsigned,
bool truncate)
{
double tmp;
- bool dec_negative= (dec < 0) && !dec_unsigned;
- ulonglong abs_dec= dec_negative ? -dec : dec;
+ const Longlong_hybrid dec(dec_value, dec_unsigned);
+ const ulonglong abs_dec= dec.abs();
/*
tmp2 is here to avoid return the value with 80 bit precision
This will fix that the test round(0.1,1) = round(0.1,1) is true
@@ -2630,22 +2661,24 @@ double my_double_round(double value, longlong dec, bool dec_unsigned,
volatile double value_div_tmp= value / tmp;
volatile double value_mul_tmp= value * tmp;
- if (!dec_negative && std::isinf(tmp)) // "dec" is too large positive number
+ if (!dec.neg() && std::isinf(tmp)) // "dec" is a too large positive number
return value;
- if (dec_negative && std::isinf(tmp))
- tmp2= 0.0;
- else if (!dec_negative && std::isinf(value_mul_tmp))
+ if (dec.neg() && std::isinf(tmp)) // "dec" is a too small negative number
+ return 0.0;
+
+ // Handle "dec" with a reasonably small absolute value
+ if (!dec.neg() && std::isinf(value_mul_tmp))
tmp2= value;
else if (truncate)
{
if (value >= 0.0)
- tmp2= dec < 0 ? floor(value_div_tmp) * tmp : floor(value_mul_tmp) / tmp;
+ tmp2= dec.neg() ? floor(value_div_tmp) * tmp : floor(value_mul_tmp) / tmp;
else
- tmp2= dec < 0 ? ceil(value_div_tmp) * tmp : ceil(value_mul_tmp) / tmp;
+ tmp2= dec.neg() ? ceil(value_div_tmp) * tmp : ceil(value_mul_tmp) / tmp;
}
else
- tmp2=dec < 0 ? rint(value_div_tmp) * tmp : rint(value_mul_tmp) / tmp;
+ tmp2=dec.neg() ? rint(value_div_tmp) * tmp : rint(value_mul_tmp) / tmp;
return tmp2;
}
@@ -2994,7 +3027,7 @@ double Item_func_min_max::val_real_native()
value=tmp;
}
if ((null_value= args[i]->null_value))
- break;
+ return 0;
}
return value;
}
@@ -3015,7 +3048,7 @@ longlong Item_func_min_max::val_int_native()
value=tmp;
}
if ((null_value= args[i]->null_value))
- break;
+ return 0;
}
return value;
}
@@ -3540,6 +3573,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
initid.const_item=func->const_item_cache;
initid.decimals=func->decimals;
initid.ptr=0;
+ not_original=0;
for (uint i1= 0 ; i1 < arg_count ; i1++)
buffers[i1].set_thread_specific();
@@ -4583,32 +4617,7 @@ longlong Item_func_sleep::val_int()
if (timeout < 0.00001)
return 0;
- timed_cond.set_timeout((ulonglong) (timeout * 1000000000.0));
-
- mysql_cond_init(key_item_func_sleep_cond, &cond, NULL);
- mysql_mutex_lock(&LOCK_item_func_sleep);
-
- THD_STAGE_INFO(thd, stage_user_sleep);
- thd->mysys_var->current_mutex= &LOCK_item_func_sleep;
- thd->mysys_var->current_cond= &cond;
-
- error= 0;
- thd_wait_begin(thd, THD_WAIT_SLEEP);
- while (!thd->killed)
- {
- error= timed_cond.wait(&cond, &LOCK_item_func_sleep);
- if (error == ETIMEDOUT || error == ETIME)
- break;
- error= 0;
- }
- thd_wait_end(thd);
- mysql_mutex_unlock(&LOCK_item_func_sleep);
- mysql_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- mysql_mutex_unlock(&thd->mysys_var->mutex);
-
- mysql_cond_destroy(&cond);
+ error= do_pause(thd, &timed_cond, &cond, timeout);
#ifdef ENABLED_DEBUG_SYNC
DBUG_EXECUTE_IF("sleep_inject_query_done_debug_sync", {
@@ -4793,7 +4802,9 @@ Item_func_set_user_var::fix_length_and_dec(THD *thd)
if (args[0]->collation.derivation == DERIVATION_NUMERIC)
{
collation.set(DERIVATION_NUMERIC);
- fix_length_and_charset(args[0]->max_char_length(), &my_charset_numeric);
+ uint sign_length= args[0]->type_handler() == &type_handler_slong_ge0 ? 1: 0;
+ fix_length_and_charset(args[0]->max_char_length() + sign_length,
+ &my_charset_numeric);
}
else
{
@@ -7327,3 +7338,43 @@ void fix_rownum_pointers(THD *thd, SELECT_LEX *select_lex, ha_rows *ptr)
((Item_func_rownum*) item)->store_pointer_to_row_counter(ptr);
}
}
+
+static int do_pause(THD *thd, Interruptible_wait *timed_cond, mysql_cond_t *cond, double timeout)
+{
+ int error= 0;
+ timed_cond->set_timeout((ulonglong) (timeout * 1000000000.0));
+
+ mysql_cond_init(key_item_func_sleep_cond, cond, NULL);
+ mysql_mutex_lock(&LOCK_item_func_sleep);
+
+ THD_STAGE_INFO(thd, stage_user_sleep);
+ thd->mysys_var->current_mutex= &LOCK_item_func_sleep;
+ thd->mysys_var->current_cond= cond;
+
+ thd_wait_begin(thd, THD_WAIT_SLEEP);
+ while (!thd->killed)
+ {
+ error= timed_cond->wait(cond, &LOCK_item_func_sleep);
+ if (error == ETIMEDOUT || error == ETIME)
+ break;
+ error= 0;
+ }
+ thd_wait_end(thd);
+ mysql_mutex_unlock(&LOCK_item_func_sleep);
+ mysql_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
+
+ mysql_cond_destroy(cond);
+
+ return error;
+}
+
+void pause_execution(THD *thd, double timeout)
+{
+ Interruptible_wait timed_cond(thd);
+ mysql_cond_t cond;
+
+ do_pause(thd, &timed_cond, &cond, timeout);
+}