1
0
Files
irix-657m-src/eoe/cmd/sss/ssdb/ssdbserver/sql/item_func.cc
2022-09-29 17:59:04 +03:00

1426 lines
30 KiB
C++

/* Copyright (C) 1979-1996 TcX AB & Monty Program KB & Detron HB
This software is distributed with NO WARRANTY OF ANY KIND. No author or
distributor accepts any responsibility for the consequences of using it, or
for whether it serves any particular purpose or works at all, unless he or
she says so in writing. Refer to the Free Public License (the "License")
for full details.
Every copy of this file must include a copy of the License, normally in a
plain ASCII text file named PUBLIC. The License grants you the right to
copy, modify and redistribute this file, but only under certain conditions
described in the License. Among other things, the License requires that
the copyright notice and this notice be preserved on all copies. */
/* This file defines all numerical functions */
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#include <m_ctype.h>
#include <hash.h>
#include <time.h>
#include <errno.h>
/* return TRUE if item is a constant */
bool
eval_const_cond(COND *cond)
{
return ((Item_func*) cond)->val_int() ? TRUE : FALSE;
}
Item_func::Item_func(List<Item> &list)
{
arg_count=list.elements;
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
uint i=0;
List_iterator<Item> li(list);
Item *item;
while ((item=li++))
{
args[i++]= item;
with_sum_func|=item->with_sum_func;
}
}
list.empty(); // Fields are used
}
Item_func::~Item_func()
{
/* Nothing to do; Items are freed automaticly */
}
bool
Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
{
Item **arg,**arg_end;
char buff[sizeof(double)]; // Max argument in function
binary=0;
used_tables_cache=0;
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set!
if (arg_count)
{ // Print purify happy
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
if ((*arg)->fix_fields(thd,tables))
return 1; /* purecov: inspected */
if ((*arg)->maybe_null)
maybe_null=1;
if ((*arg)->binary)
binary=1;
with_sum_func= with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
}
}
fix_length_and_dec();
return 0;
}
void Item_func::split_sum_func(List<Item> &fields)
{
Item **arg,**arg_end;
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
(*arg)->split_sum_func(fields);
else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
{
fields.push_front(*arg);
*arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name);
}
}
}
void Item_func::update_used_tables()
{
used_tables_cache=0;
for (uint i=0 ; i < arg_count ; i++)
{
args[i]->update_used_tables();
used_tables_cache|=args[i]->used_tables();
}
}
table_map Item_func::used_tables() const
{
return used_tables_cache;
}
void Item_func::print(String *str)
{
str->append(func_name());
str->append('(');
for (uint i=0 ; i < arg_count ; i++)
{
if (i)
str->append(',');
args[i]->print(str);
}
str->append(')');
}
void Item_func::print_op(String *str)
{
str->append('(');
for (uint i=0 ; i < arg_count-1 ; i++)
{
args[i]->print(str);
str->append(' ');
str->append(func_name());
str->append(' ');
}
args[arg_count-1]->print(str);
str->append(')');
}
String *Item_real_func::str(String *str)
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
return str;
}
String *Item_num_func::str(String *str)
{
if (hybrid_type == INT_RESULT)
{
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr);
}
else
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
}
return str;
}
void Item_func::fix_num_length_and_dec()
{
decimals=0;
for (uint i=0 ; i < arg_count ; i++)
set_if_bigger(decimals,args[i]->decimals);
max_length=float_length(decimals);
}
String *Item_int_func::str(String *str)
{
longlong nr=val_int();
if (null_value)
return 0;
else
str->set(nr);
return str;
}
/* Change from REAL_RESULT (default) to INT_RESULT if both arguments are integers */
void Item_num_op::find_num_type(void)
{
if (args[0]->result_type() == INT_RESULT && args[1]->result_type() == INT_RESULT)
hybrid_type=INT_RESULT;
}
String *Item_num_op::str(String *str)
{
if (hybrid_type == INT_RESULT)
{
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr);
}
else
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
}
return str;
}
double Item_func_plus::val()
{
double val=args[0]->val()+args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return val;
}
longlong Item_func_plus::val_int()
{
longlong val=args[0]->val_int()+args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0;
return val;
}
double Item_func_minus::val()
{
double val=args[0]->val() - args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return val;
}
longlong Item_func_minus::val_int()
{
longlong val=args[0]->val_int() - args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0;
return val;
}
double Item_func_mul::val()
{
double val=args[0]->val()*args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0; /* purecov: inspected */
return val;
}
longlong Item_func_mul::val_int()
{
longlong val=args[0]->val_int()*args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
return val;
}
double Item_func_div::val()
{
double val=args[0]->val();
double val2=args[1]->val();
if ((null_value= val2 == 0.0 || args[0]->null_value || args[1]->null_value))
return 0.0;
return val/val2;
}
longlong Item_func_div::val_int()
{
longlong val=args[0]->val_int();
longlong val2=args[1]->val_int();
if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value))
return 0;
return val/val2;
}
void Item_func_div::fix_length_and_dec()
{
decimals=max(args[0]->decimals,args[1]->decimals)+2;
max_length=args[0]->max_length - args[0]->decimals + decimals;
uint tmp=float_length(decimals);
set_if_smaller(max_length,tmp);
maybe_null=1;
}
double Item_func_mod::val()
{
double val= floor(args[0]->val()+0.5);
double val2=floor(args[1]->val()+0.5);
if ((null_value=val2 == 0.0 || args[0]->null_value || args[1]->null_value))
return 0.0; /* purecov: inspected */
return fmod(val,val2);
}
longlong Item_func_mod::val_int()
{
longlong val= args[0]->val_int();
longlong val2= args[1]->val_int();
if ((null_value=val2 == 0 || args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
return val % val2;
}
void Item_func_mod::fix_length_and_dec()
{
max_length=args[1]->max_length;
decimals=0;
maybe_null=1;
find_num_type();
}
double Item_func_neg::val()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return -val;
}
longlong Item_func_neg::val_int()
{
longlong val=args[0]->val_int();
null_value=args[0]->null_value;
return -val;
}
void Item_func_neg::fix_length_and_dec()
{
decimals=args[0]->decimals;
max_length=args[0]->max_length;
hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
}
double Item_func_abs::val()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return fabs(val);
}
longlong Item_func_abs::val_int()
{
longlong val=args[0]->val_int();
null_value=args[0]->null_value;
return val >= 0 ? val : -val;
}
void Item_func_abs::fix_length_and_dec()
{
decimals=args[0]->decimals;
max_length=args[0]->max_length;
hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
}
double Item_func_log::val()
{
double val=args[0]->val();
if ((null_value=(args[0]->null_value || val <= 0.0)))
return 0.0; /* purecov: inspected */
return log(val);
}
double Item_func_log10::val()
{
double val=args[0]->val();
if ((null_value=(args[0]->null_value || val <= 0.0)))
return 0.0; /* purecov: inspected */
return log10(val);
}
double Item_func_exp::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0; /* purecov: inspected */
return exp(val);
}
double Item_func_sqrt::val()
{
double val=args[0]->val();
if ((null_value=(args[0]->null_value || val < 0)))
return 0.0; /* purecov: inspected */
return sqrt(val);
}
double Item_func_pow::val()
{
double val=args[0]->val();
double val2=args[1]->val();
if ((null_value=(args[0]->null_value || args[1]->null_value)))
return 0.0; /* purecov: inspected */
return pow(val,val2);
}
// Trigonometric functions
double Item_func_acos::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(acos(val));
}
double Item_func_asin::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(asin(val));
}
double Item_func_atan::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
if (arg_count == 2)
{
double val2= args[1]->val();
if ((null_value=args[1]->null_value))
return 0.0;
return fix_result(atan2(val,val2));
}
return fix_result(atan(val));
}
double Item_func_cos::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(cos(val));
}
double Item_func_sin::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(sin(val));
}
double Item_func_tan::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(tan(val));
}
// Shift-functions, same as << and >> in C/C++
longlong Item_func_shift_left::val_int()
{
uint shift;
ulonglong res= ((ulonglong) args[0]->val_int() <<
(shift=(uint) args[1]->val_int()));
if (args[0]->null_value || args[1]->null_value)
{
null_value=1;
return 0;
}
null_value=0;
return (shift < sizeof(longlong)*8 ? (longlong) res : LL(0));
}
longlong Item_func_shift_right::val_int()
{
ulonglong res= (ulonglong) args[0]->val_int() >> (uint) args[1]->val_int();
if (args[0]->null_value || args[1]->null_value)
{
null_value=1;
return 0;
}
null_value=0;
return (longlong) res;
}
// Conversion functions
void Item_func_integer::fix_length_and_dec()
{
max_length=args[0]->max_length - args[0]->decimals+1;
uint tmp=float_length(decimals);
set_if_smaller(max_length,tmp);
decimals=0;
}
longlong Item_func_ceiling::val_int()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return (longlong) ceil(val);
}
longlong Item_func_floor::val_int()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return (longlong) floor(val);
}
void Item_func_round::fix_length_and_dec()
{
max_length=args[0]->max_length;
decimals=args[0]->decimals;
if (args[1]->const_item())
{
int tmp=(int) args[1]->val_int();
if (tmp < 0)
decimals=0;
else
decimals=tmp;
}
}
double Item_func_round::val()
{
double val=args[0]->val();
int dec=(int) args[1]->val_int();
uint abs_dec=abs(dec);
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
double tmp=(abs_dec < array_elements(log_10) ?
log_10[abs_dec] : pow(10.0,(double) abs_dec));
if (truncate)
return dec < 0 ? floor(val/tmp)*tmp : floor(val*tmp)/tmp;
return dec < 0 ? rint(val/tmp)*tmp : rint(val*tmp)/tmp;
}
double Item_func_rand::val()
{
if (arg_count)
{ // Only use argument once in query
ulong tmp=((ulong) args[0]->val_int())+55555555L;
randominit(&current_thd->rand,tmp,tmp/2);
#ifdef DELETE_ITEMS
delete args[0];
#endif
arg_count=0;
}
return rnd(&current_thd->rand);
}
longlong Item_func_sign::val_int()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return val < 0.0 ? -1 : (val > 0 ? 1 : 0);
}
double Item_func_units::val()
{
double val=args[0]->val();
if ((null_value=args[0]->null_value))
return 0;
return val*mul+add;
}
void Item_func_min_max::fix_length_and_dec()
{
decimals=0;
max_length=0;
maybe_null=1;
binary=0;
cmp_type=args[0]->result_type();
for (uint i=0 ; i < arg_count ; i++)
{
if (max_length < args[i]->max_length)
max_length=args[i]->max_length;
if (decimals < args[i]->decimals)
decimals=args[i]->decimals;
if (!args[i]->maybe_null)
maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
if (args[i]->binary)
binary=1;
}
}
String *Item_func_min_max::str(String *str)
{
switch (cmp_type) {
case INT_RESULT:
{
longlong nr=val_int();
if (null_value)
return 0;
else
str->set(nr);
return str;
}
case REAL_RESULT:
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
return str;
}
case STRING_RESULT:
{
String *res;
LINT_INIT(res);
null_value=1;
for (uint i=0; i < arg_count ; i++)
{
if (null_value)
{
res=args[i]->str(str);
null_value=args[i]->null_value;
}
else
{
String *res2;
res2= args[i]->str(res == str ? &tmp_value : str);
if (res2)
{
int cmp=binary ? stringcmp(res,res2) : sortcmp(res,res2);
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
}
}
}
return res;
}
}
return 0; // Keep compiler happy
}
double Item_func_min_max::val()
{
double value=0.0;
null_value=1;
for (uint i=0; i < arg_count ; i++)
{
if (null_value)
{
value=args[i]->val();
null_value=args[i]->null_value;
}
else
{
double tmp=args[i]->val();
if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
value=tmp;
}
}
return value;
}
longlong Item_func_min_max::val_int()
{
longlong value=0;
null_value=1;
for (uint i=0; i < arg_count ; i++)
{
if (null_value)
{
value=args[i]->val_int();
null_value=args[i]->null_value;
}
else
{
longlong tmp=args[i]->val_int();
if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
value=tmp;
}
}
return value;
}
longlong Item_func_length::val_int()
{
String *res=args[0]->str(&value);
if (!res)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
return (longlong) res->length();
}
longlong Item_func_locate::val_int()
{
String *a=args[0]->str(&value1);
String *b=args[1]->str(&value2);
if (!a || !b)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
uint start=0;
if (arg_count == 3)
{
start=(uint) args[2]->val_int()-1;
if (start > a->length() || start+b->length() > a->length())
return 0;
}
if (!b->length()) // Found empty string at start
return (longlong) (start+1);
return (longlong) (a->strstr(*b,start)+1) ;
}
longlong Item_func_field::val_int()
{
String *field;
if (!(field=item->str(&value)))
return 0; // -1 if null ?
for (uint i=0 ; i < arg_count ; i++)
{
String *tmp_value=args[i]->str(&tmp);
if (tmp_value && field->length() == tmp_value->length() &&
!memcmp(field->ptr(),tmp_value->ptr(),tmp_value->length()))
return (longlong) (i+1);
}
return 0;
}
longlong Item_func_ascii::val_int()
{
String *res=args[0]->str(&value);
if (!res)
{
null_value=1;
return 0;
}
null_value=0;
return (longlong) (res->length() ? (uchar) (*res)[0] : (uchar) 0);
}
static char nbits[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
};
/* Search after a string in a string of strings separated by ',' */
/* Returns number of found type >= 1 or 0 if not found */
/* This optimizes searching in enums to bit testing! */
void Item_func_find_in_set::fix_length_and_dec()
{
decimals=0;
max_length=3; // 1-999
if (args[0]->const_item() && args[1]->type() == FIELD_ITEM)
{
Field *field= ((Item_field*) args[1])->field;
if (field->real_type() == FIELD_TYPE_SET)
{
String *find=args[0]->str(&value);
enum_value=find_enum(((Field_enum*) field)->typelib,find->ptr(),
find->length());
enum_bit=0;
if (enum_value)
enum_bit=LL(1) << (enum_value-1);
}
}
}
static const char separator=',';
longlong Item_func_find_in_set::val_int()
{
if (enum_value)
{
ulonglong tmp=(ulonglong) args[1]->val_int();
if (!(null_value=args[1]->null_value || args[0]->null_value))
{
if (tmp & enum_bit)
return enum_value;
}
return 0L;
}
String *find=args[0]->str(&value);
String *buffer=args[1]->str(&value2);
if (!find || !buffer)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
int diff;
if ((diff=buffer->length() - find->length()) >= 0)
{
const char *f_pos=find->ptr();
const char *f_end=f_pos+find->length();
const char *str=buffer->ptr();
const char *end=str+diff+1;
const char *real_end=str+buffer->length();
uint position=1;
do
{
const char *pos= f_pos;
while (pos != f_end)
{
if (toupper(*str) != toupper(*pos))
goto not_found;
str++;
pos++;
}
if (str == real_end || str[0] == separator)
return (longlong) position;
not_found:
while (str < end && str[0] != separator)
str++;
position++;
} while (++str <= end);
}
return 0;
}
longlong Item_func_bit_count::val_int()
{
ulonglong value= (ulonglong) args[0]->val_int();
if (args[0]->null_value)
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
ulong v1=(ulong) value;
#if SIZEOF_LONG_LONG > 4
ulong v2=(ulong) (value >> 32);
#else
ulong v2=0;
#endif
uint bits= (uint) (uchar) (nbits[(uchar) v1] +
nbits[(uchar) (v1 >> 8)] +
nbits[(uchar) (v1 >> 16)] +
nbits[(uchar) (v1 >> 24)] +
nbits[(uchar) v2] +
nbits[(uchar) (v2 >> 8)] +
nbits[(uchar) (v2 >> 16)] +
nbits[(uchar) (v2 >> 24)]);
return (longlong) bits;
}
/****************************************************************************
** Functions to handle dynamic loadable functions
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
** Rewritten by: Monty.
****************************************************************************/
#ifdef HAVE_DLOPEN
Item_udf_func::~Item_udf_func()
{
if (initialized)
{
if (u_d->func_deinit != NULL)
{
void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
u_d->func_deinit;
(*deinit)(&initid);
}
free_udf(u_d);
}
delete [] buffers;
}
bool
Item_udf_func::fix_fields(THD *thd,TABLE_LIST *tables)
{
char buff[sizeof(double)]; // Max argument in function
DBUG_ENTER("Item_udf_func::fix_fields");
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set!
udf_func *udf=find_udf(u_d->name,strlen(u_d->name),1);
if (!udf)
{
my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name,
errno);
DBUG_RETURN(1);
}
u_d=udf;
/* Fix all arguments */
binary=maybe_null=0;
used_tables_cache=0;
if ((f_args.arg_count=arg_count))
{
if (!(f_args.arg_type= (Item_result*)
sql_alloc(arg_count*sizeof(Item_result))))
{
free_udf(u_d);
DBUG_RETURN(1);
}
uint i;
Item **arg,**arg_end;
for (i=0, arg=args, arg_end=args+arg_count; arg != arg_end ; arg++,i++)
{
if ((*arg)->fix_fields(thd,tables))
return 1;
if ((*arg)->binary)
binary=1;
if ((*arg)->maybe_null)
maybe_null=1;
with_sum_func= with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
f_args.arg_type[i]=(*arg)->result_type();
}
if (!(buffers=new String[arg_count]) ||
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
!(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) ||
!(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) ||
!(num_buffer= sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
{
free_udf(u_d);
DBUG_RETURN(1);
}
}
fix_length_and_dec();
initid.max_length=max_length;
initid.maybe_null=maybe_null;
initid.decimals=decimals;
initid.ptr=0;
if (u_d->func_init)
{
char *to=num_buffer;
for (uint i=0; i < arg_count; i++)
{
f_args.args[i]=0;
f_args.lengths[i]=args[i]->max_length;
f_args.maybe_null[i]=(char) args[i]->maybe_null;
switch(args[i]->type()) {
case Item::STRING_ITEM: // Constant string !
{
String *res=args[i]->str((String *) 0);
if (args[i]->null_value)
continue;
f_args.args[i]= (char*) res->ptr();
break;
}
case Item::INT_ITEM:
*((longlong*) to) = args[i]->val_int();
if (!args[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(longlong));
}
break;
case Item::REAL_ITEM:
*((double*) to) = args[i]->val();
if (!args[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(double));
}
break;
default: // Skipp these
break;
}
}
thd->net.last_error[0]=0;
my_bool (*init)(UDF_INIT *, UDF_ARGS *, char *)=
(my_bool (*)(UDF_INIT *, UDF_ARGS *, char *))
u_d->func_init;
if ((error=(uchar) init(&initid, &f_args, thd->net.last_error)))
{
my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
u_d->name,thd->net.last_error);
free_udf(u_d);
DBUG_RETURN(1);
}
max_length=min(initid.max_length,MAX_BLOB_WIDTH);
maybe_null=initid.maybe_null;
decimals=min(initid.decimals,31);
}
initialized=1;
if (error)
{
my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
u_d->name, ER(ER_UNKNOWN_ERROR));
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
bool Item_udf_func::get_arguments()
{
if (error)
{
null_value=1; // If something goes wrong
return 1;
}
null_value=0;
char *to= num_buffer;
uint str_count=0;
for (uint i=0; i < arg_count; i++)
{
f_args.args[i]=0;
switch (f_args.arg_type[i]) {
case STRING_RESULT:
{
String *res=args[i]->str(&buffers[str_count++]);
if (!(args[i]->null_value))
{
f_args.args[i]= (char*) res->ptr();
f_args.lengths[i]= res->length();
break;
}
}
case INT_RESULT:
*((longlong*) to) = args[i]->val_int();
if (!args[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(longlong));
}
break;
case REAL_RESULT:
*((double*) to) = args[i]->val();
if (!args[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(double));
}
break;
}
}
return 0;
}
double Item_func_udf_float::val()
{
uchar is_null=0;
DBUG_ENTER("Item_func_udf_float::val");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
if (get_arguments())
DBUG_RETURN(0);
double (*udf)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
(double (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
double tmp=udf(&initid, &f_args, &is_null, &error);
if (is_null || error)
{
null_value=1;
return 0.0;
}
DBUG_RETURN(tmp);
}
String *Item_func_udf_float::str(String *str)
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
return str;
}
longlong Item_func_udf_int::val_int()
{
uchar is_null=0;
DBUG_ENTER("Item_func_udf_int::val_int");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
if (get_arguments())
DBUG_RETURN(0);
longlong (*udf)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
(longlong (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
longlong tmp=udf(&initid, &f_args, &is_null, &error);
if (is_null || error)
{
null_value=1;
return 0LL;
}
DBUG_RETURN(tmp);
}
String *Item_func_udf_int::str(String *str)
{
longlong nr=val_int();
if (null_value)
return 0;
else
str->set(nr);
return str;
}
/* Default max_length is max argument length */
void Item_func_udf_str::fix_length_and_dec()
{
DBUG_ENTER("Item_func_udf_str::fix_length_and_dec");
max_length=0;
for (uint i = 0; i < arg_count; i++)
set_if_bigger(max_length,args[i]->max_length);
DBUG_VOID_RETURN;
}
String *Item_func_udf_str::str(String *str)
{
uchar is_null=0;
ulong res_length;
if (get_arguments())
{
null_value=1;
return 0;
}
char * (*udf)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)=
(char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *))
u_d->func;
if ((res_length=str->alloced_length()) < MAX_FIELD_WIDTH)
{ // This happens VERY seldom
if (str->alloc(MAX_FIELD_WIDTH))
{
error=1;
null_value=1;
return 0;
}
}
char *res=udf(&initid, &f_args, (char*) str->ptr(), &res_length, &is_null,
&error);
if (is_null || !res || error) // The !res is for safety
{
null_value=1;
return 0;
}
if (res == str->ptr())
{
str->length(res_length);
return str;
}
str_value.set(res, res_length);
return &str_value;
}
#endif /* HAVE_DLOPEN */
/*
** User level locks
*/
pthread_mutex_t LOCK_user_locks;
static HASH hash_user_locks;
class ULL
{
char *key;
uint key_length;
public:
int count;
bool locked;
pthread_cond_t cond;
pthread_t thread;
ULL(const char *key_arg,uint length) :key_length(length),count(1),locked(1)
{
key=(char*) my_memdup((byte*) key_arg,length,MYF(0));
pthread_cond_init(&cond,NULL);
if (key)
{
if (hash_insert(&hash_user_locks,(byte*) this))
{
my_free((gptr) key,MYF(0));
key=0;
}
}
}
~ULL()
{
if (key)
{
hash_delete(&hash_user_locks,(byte*) this);
my_free((gptr) key,MYF(0));
}
pthread_cond_destroy(&cond);
}
inline bool initialized() { return key != 0; }
friend void item_user_lock_release(ULL *ull);
friend char *ull_get_key(const ULL *ull,uint *length,my_bool not_used);
};
char *ull_get_key(const ULL *ull,uint *length,my_bool not_used)
{
*length=(uint) ull->key_length;
return (char*) ull->key;
}
void item_user_lock_init(void)
{
pthread_mutex_init(&LOCK_user_locks,NULL);
hash_init(&hash_user_locks,16,0,0,(hash_get_key) ull_get_key,NULL,0);
}
void item_user_lock_free(void)
{
hash_free(&hash_user_locks);
}
void item_user_lock_release(ULL *ull)
{
ull->locked=0;
if (--ull->count)
pthread_cond_signal(&ull->cond);
else
delete ull;
}
/*
Get a user level lock. If the thread has an old lock this is first released.
Returns 1: Got lock
Returns 0: Timeout
Returns NULL: Error
*/
#ifndef ETIME
#define ETIME ETIMEDOUT // For FreeBSD
#endif
longlong Item_func_get_lock::val_int()
{
String *res=args[0]->str(&value);
longlong timeout=args[1]->val_int();
struct timespec abstime;
THD *thd=current_thd;
ULL *ull;
int error;
pthread_mutex_lock(&LOCK_user_locks);
if (!res || !res->length())
{
pthread_mutex_unlock(&LOCK_user_locks);
null_value=1;
return 0;
}
null_value=0;
if (thd->ull)
{
item_user_lock_release(thd->ull);
thd->ull=0;
}
if (!(ull= ((ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),res->length()))))
{
ull=new ULL(res->ptr(),res->length());
if (!ull || !ull->initialized())
{
delete ull;
pthread_mutex_unlock(&LOCK_user_locks);
null_value=1; // Probably out of memory
return 0;
}
ull->thread=thd->real_id;
thd->ull=ull;
pthread_mutex_unlock(&LOCK_user_locks);
return 1; // Got new lock
}
ull->count++;
/* structure is now initialized. Try to get the lock */
/* Set up control struct to allow others to abort locks */
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->proc_info="User lock";
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
pthread_mutex_unlock(&thd->mysys_var->mutex);
abstime.tv_sec=time((time_t*) 0)+(time_t) timeout;
abstime.tv_nsec=0;
while ((error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked)
{
if (thd->killed || abort_loop)
{
error=EINTR; // Return NULL
break;
}
}
if (ull->locked)
{
if (!--ull->count)
delete ull; // Should never happen
if (error != ETIME && error != ETIMEDOUT)
{
error=1;
null_value=1; // Return NULL
}
}
else
{
ull->locked=1;
ull->thread=thd->real_id;
thd->ull=ull;
error=0;
}
pthread_mutex_unlock(&LOCK_user_locks);
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->proc_info=0;
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
pthread_mutex_unlock(&thd->mysys_var->mutex);
return !error ? 1 : 0;
}
/*
** Release a user level lock.
** Returns 1 if lock released
** 0 if lock wasn't held
** NULL if no such lock
*/
longlong Item_func_release_lock::val_int()
{
String *res=args[0]->str(&value);
ULL *ull;
longlong result;
if (!res || !res->length())
{
null_value=1;
return 0;
}
null_value=0;
result=0;
pthread_mutex_lock(&LOCK_user_locks);
if (!(ull= ((ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),res->length()))))
{
null_value=1;
}
else
{
if (ull->locked && pthread_equal(pthread_self(),ull->thread))
{
result=1; // Release is ok
item_user_lock_release(ull);
current_thd->ull=0;
}
}
pthread_mutex_unlock(&LOCK_user_locks);
return result;
}
longlong Item_func_set_last_insert_id::val_int()
{
longlong value=args[0]->val_int();
current_thd->insert_id(value);
null_value=args[0]->null_value;
return value;
}