home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 January
/
Chip_2001-01_cd1.bin
/
tema
/
mysql
/
mysql-3.23.28g-win-source.exe
/
sql
/
item_func.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2000-11-16
|
46KB
|
2,047 lines
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* 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 <ft_global.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
}
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;
const_item_cache=1;
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error if 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();
const_item_cache&= (*arg)->const_item();
}
}
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;
const_item_cache=1;
for (uint i=0 ; i < arg_count ; i++)
{
args[i]->update_used_tables();
used_tables_cache|=args[i]->used_tables();
const_item_cache&=args[i]->const_item();
}
}
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(')');
}
bool Item_func::eq(const Item *item) const
{
/* Assume we don't have rtti */
if (this == item)
return 1;
if (item->type() != FUNC_ITEM)
return 0;
Item_func *item_func=(Item_func*) item;
if (arg_count != item_func->arg_count ||
func_name() != item_func->func_name())
return 0;
for (uint i=0; i < arg_count ; i++)
if (!args[i]->eq(item_func->args[i]))
return 0;
return 1;
}
String *Item_real_func::val_str(String *str)
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
else
str->set(nr,decimals);
return str;
}
String *Item_num_func::val_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::val_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::val_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 value=args[0]->val()+args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
longlong Item_func_plus::val_int()
{
longlong value=args[0]->val_int()+args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0;
return value;
}
double Item_func_minus::val()
{
double value=args[0]->val() - args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
longlong Item_func_minus::val_int()
{
longlong value=args[0]->val_int() - args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0;
return value;
}
double Item_func_mul::val()
{
double value=args[0]->val()*args[1]->val();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0; /* purecov: inspected */
return value;
}
longlong Item_func_mul::val_int()
{
longlong value=args[0]->val_int()*args[1]->val_int();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
return value;
}
double Item_func_div::val()
{
double value=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 value/val2;
}
longlong Item_func_div::val_int()
{
longlong value=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 value/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 value= 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(value,val2);
}
longlong Item_func_mod::val_int()
{
longlong value= 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 value % 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 value=args[0]->val();
null_value=args[0]->null_value;
return -value;
}
longlong Item_func_neg::val_int()
{
longlong value=args[0]->val_int();
null_value=args[0]->null_value;
return -value;
}
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 value=args[0]->val();
null_value=args[0]->null_value;
return fabs(value);
}
longlong Item_func_abs::val_int()
{
longlong value=args[0]->val_int();
null_value=args[0]->null_value;
return value >= 0 ? value : -value;
}
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 value=args[0]->val();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0; /* purecov: inspected */
return log(value);
}
double Item_func_log10::val()
{
double value=args[0]->val();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0; /* purecov: inspected */
return log10(value);
}
double Item_func_exp::val()
{
double value=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0; /* purecov: inspected */
return exp(value);
}
double Item_func_sqrt::val()
{
double value=args[0]->val();
if ((null_value=(args[0]->null_value || value < 0)))
return 0.0; /* purecov: inspected */
return sqrt(value);
}
double Item_func_pow::val()
{
double value=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(value,val2);
}
// Trigonometric functions
double Item_func_acos::val()
{
double value=args[0]->val();
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
return 0.0;
return fix_result(acos(value));
}
double Item_func_asin::val()
{
double value=args[0]->val();
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
return 0.0;
return fix_result(asin(value));
}
double Item_func_atan::val()
{
double value=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(value,val2));
}
return fix_result(atan(value));
}
double Item_func_cos::val()
{
double value=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(cos(value));
}
double Item_func_sin::val()
{
double value=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(sin(value));
}
double Item_func_tan::val()
{
double value=args[0]->val();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(tan(value));
}
// 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()
{
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_bit_neg::val_int()
{
ulonglong res= (ulonglong) args[0]->val_int();
if ((null_value=args[0]->null_value))
return 0;
return ~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 value=args[0]->val();
null_value=args[0]->null_value;
return (longlong) ceil(value);
}
longlong Item_func_floor::val_int()
{
double value=args[0]->val();
null_value=args[0]->null_value;
return (longlong) floor(value);
}
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 value=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(value/tmp)*tmp : floor(value*tmp)/tmp;
return dec < 0 ? rint(value/tmp)*tmp : rint(value*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(¤t_thd->rand,tmp,tmp/2);
#ifdef DELETE_ITEMS
delete args[0];
#endif
arg_count=0;
}
return rnd(¤t_thd->rand);
}
longlong Item_func_sign::val_int()
{
double value=args[0]->val();
null_value=args[0]->null_value;
return value < 0.0 ? -1 : (value > 0 ? 1 : 0);
}
double Item_func_units::val()
{
double value=args[0]->val();
if ((null_value=args[0]->null_value))
return 0;
return value*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::val_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]->val_str(str);
null_value=args[i]->null_value;
}
else
{
String *res2;
res2= args[i]->val_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]->val_str(&value);
if (!res)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
return (longlong) res->length();
}
longlong Item_func_char_length::val_int()
{
String *res=args[0]->val_str(&value);
if (!res)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
return (longlong) (!args[0]->binary) ? res->numchars() : res->length();
}
longlong Item_func_locate::val_int()
{
String *a=args[0]->val_str(&value1);
String *b=args[1]->val_str(&value2);
#ifdef USE_MB
bool binary_str = args[0]->binary || args[1]->binary;
#endif
if (!a || !b)
{
null_value=1;
return 0; /* purecov: inspected */
}
null_value=0;
uint start=0;
#ifdef USE_MB
uint start0=0;
#endif
if (arg_count == 3)
{
start=(uint) args[2]->val_int()-1;
#ifdef USE_MB
if (use_mb(default_charset_info))
{
start0=start;
if (!binary_str)
start=a->charpos(start);
}
#endif
if (start > a->length() || start+b->length() > a->length())
return 0;
}
if (!b->length()) // Found empty string at start
return (longlong) (start+1);
#ifdef USE_MB
if (use_mb(default_charset_info) && !binary_str)
{
const char *ptr=a->ptr()+start;
const char *search=b->ptr();
const char *strend = ptr+a->length();
const char *end=strend-b->length()+1;
const char *search_end=search+b->length();
register uint32 l;
while (ptr < end)
{
if (*ptr == *search)
{
register char *i,*j;
i=(char*) ptr+1; j=(char*) search+1;
while (j != search_end)
if (*i++ != *j++) goto skipp;
return (longlong) start0+1;
}
skipp:
if ((l=my_ismbchar(default_charset_info,ptr,strend))) ptr+=l;
else ++ptr;
++start0;
}
return 0;
}
#endif /* USE_MB */
return (longlong) (a->strstr(*b,start)+1) ;
}
longlong Item_func_field::val_int()
{
String *field;
if (!(field=item->val_str(&value)))
return 0; // -1 if null ?
for (uint i=0 ; i < arg_count ; i++)
{
String *tmp_value=args[i]->val_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]->val_str(&value);
if (!res)
{
null_value=1;
return 0;
}
null_value=0;
return (longlong) (res->length() ? (uchar) (*res)[0] : (uchar) 0);
}
longlong Item_func_ord::val_int()
{
String *res=args[0]->val_str(&value);
if (!res)
{
null_value=1;
return 0;
}
null_value=0;
if (!res->length()) return 0;
#ifdef USE_MB
if (use_mb(default_charset_info) && !args[0]->binary)
{
register const char *str=res->ptr();
register uint32 n=0, l=my_ismbchar(default_charset_info,
str,str+res->length());
if (!l) return (longlong)((uchar) *str);
while (l--)
n=(n<<8)|(uint32)((uchar) *str++);
return (longlong) n;
}
#endif
return (longlong) ((uchar) (*res)[0]);
}
/* 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]->val_str(&value);
if (find)
{
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]->val_str(&value);
String *buffer=args[1]->val_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;
}
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,
};
uint count_bits(ulonglong v)
{
#if SIZEOF_LONG_LONG > 4
/* The following code is a bit faster on 16 bit machines than if we would
only shift v */
ulong v2=(ulong) (v >> 32);
return (uint) (uchar) (nbits[(uchar) v] +
nbits[(uchar) (v >> 8)] +
nbits[(uchar) (v >> 16)] +
nbits[(uchar) (v >> 24)] +
nbits[(uchar) (v2)] +
nbits[(uchar) (v2 >> 8)] +
nbits[(uchar) (v2 >> 16)] +
nbits[(uchar) (v2 >> 24)]);
#else
return (uint) (uchar) (nbits[(uchar) v] +
nbits[(uchar) (v >> 8)] +
nbits[(uchar) (v >> 16)] +
nbits[(uchar) (v >> 24)]);
#endif
}
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 */
}
return (longlong) count_bits(value);
}
/****************************************************************************
** Functions to handle dynamic loadable functions
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
** Rewritten by monty.
****************************************************************************/
#ifdef HAVE_DLOPEN
udf_handler::~udf_handler()
{
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
udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
uint arg_count, Item **arguments)
{
char buff[sizeof(double)]; // Max argument in function
DBUG_ENTER("Item_udf_func::fix_fields");
if (thd)
{
if (check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set!
}
else
thd=current_thd; // In WHERE / const clause
udf_func *tmp_udf=find_udf(u_d->name,(uint) strlen(u_d->name),1);
if (!tmp_udf)
{
my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name,
errno);
DBUG_RETURN(1);
}
u_d=tmp_udf;
args=arguments;
/* Fix all arguments */
func->binary=func->maybe_null=0;
used_tables_cache=0;
const_item_cache=1;
if ((f_args.arg_count=arg_count))
{
if (!(f_args.arg_type= (Item_result*)
sql_alloc(f_args.arg_count*sizeof(Item_result))))
{
free_udf(u_d);
DBUG_RETURN(1);
}
uint i;
Item **arg,**arg_end;
for (i=0, arg=arguments, arg_end=arguments+arg_count;
arg != arg_end ;
arg++,i++)
{
if ((*arg)->fix_fields(thd,tables))
return 1;
if ((*arg)->binary)
func->binary=1;
if ((*arg)->maybe_null)
func->maybe_null=1;
func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
const_item_cache&=(*arg)->const_item();
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= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
{
free_udf(u_d);
DBUG_RETURN(1);
}
}
func->fix_length_and_dec();
initid.max_length=func->max_length;
initid.maybe_null=func->maybe_null;
initid.const_item=const_item_cache;
initid.decimals=func->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]=arguments[i]->max_length;
f_args.maybe_null[i]=(char) arguments[i]->maybe_null;
switch(arguments[i]->type()) {
case Item::STRING_ITEM: // Constant string !
{
String *res=arguments[i]->val_str((String *) 0);
if (arguments[i]->null_value)
continue;
f_args.args[i]= (char*) res->ptr();
break;
}
case Item::INT_ITEM:
*((longlong*) to) = arguments[i]->val_int();
if (!arguments[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(longlong));
}
break;
case Item::REAL_ITEM:
*((double*) to) = arguments[i]->val();
if (!arguments[i]->null_value)
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(double));
}
break;
default: // Skip 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);
}
func->max_length=min(initid.max_length,MAX_BLOB_WIDTH);
func->maybe_null=initid.maybe_null;
const_item_cache=initid.const_item;
func->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 udf_handler::get_arguments()
{
if (error)
return 1; // Got an error earlier
char *to= num_buffer;
uint str_count=0;
for (uint i=0; i < f_args.arg_count; i++)
{
f_args.args[i]=0;
switch (f_args.arg_type[i]) {
case STRING_RESULT:
{
String *res=args[i]->val_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;
}
/* This returns (String*) 0 in case of NULL values */
String *udf_handler::val_str(String *str,String *save_str)
{
uchar is_null=0;
ulong res_length;
if (get_arguments())
return 0;
char * (*func)(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;
return 0;
}
}
char *res=func(&initid, &f_args, (char*) str->ptr(), &res_length, &is_null,
&error);
if (is_null || !res || error) // The !res is for safety
{
return 0;
}
if (res == str->ptr())
{
str->length(res_length);
return str;
}
save_str->set(res, res_length);
return save_str;
}
double Item_func_udf_float::val()
{
DBUG_ENTER("Item_func_udf_float::val");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
DBUG_RETURN(udf.val(&null_value));
}
String *Item_func_udf_float::val_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()
{
DBUG_ENTER("Item_func_udf_int::val_int");
DBUG_PRINT("info",("result_type: %d arg_count: %d",
args[0]->result_type(), arg_count));
DBUG_RETURN(udf.val_int(&null_value));
}
String *Item_func_udf_int::val_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::val_str(String *str)
{
String *res=udf.val_str(str,&str_value);
null_value = !res;
return res;
}
#else
bool udf_handler::get_arguments() { return 0; }
#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 __attribute__((unused)))
{
*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
*/
longlong Item_func_get_lock::val_int()
{
String *res=args[0]->val_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]->val_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,(const 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;
}
/* This function is just used to test speed of different functions */
longlong Item_func_benchmark::val_int()
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff));
THD *thd=current_thd;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
{
switch (args[0]->result_type()) {
case REAL_RESULT:
(void) args[0]->val();
break;
case INT_RESULT:
(void) args[0]->val_int();
break;
case STRING_RESULT:
(void) args[0]->val_str(&tmp);
break;
}
}
return 0;
}
#define extra_size sizeof(double)
static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
bool create_if_not_exists)
{
user_var_entry *entry;
if (!(entry = (user_var_entry*) hash_search(hash, (byte*) name.str,
name.length)) &&
create_if_not_exists)
{
uint size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
if (!hash_inited(hash))
return 0;
if (!(entry = (user_var_entry*) my_malloc(size,MYF(MY_WME))))
return 0;
entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
extra_size;
entry->name.length=name.length;
entry->value=0;
entry->length=0;
entry->type=STRING_RESULT;
memcpy(entry->name.str, name.str, name.length+1);
if (hash_insert(hash,(byte*) entry))
{
my_free((char*) entry,MYF(0));
return 0;
}
}
return entry;
}
bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables)
{
if (!thd)
thd=current_thd;
if (Item_func::fix_fields(thd,tables) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
return 0;
}
void
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,
Item_result type)
{
if ((null_value=args[0]->null_value))
{
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value && entry->value != pos)
my_free(entry->value,MYF(0));
entry->value=0;
entry->length=0;
}
else
{
if (length <= extra_size)
{
/* Save value in value struct */
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value != pos)
{
if (entry->value)
my_free(entry->value,MYF(0));
entry->value=pos;
}
}
else
{
/* Allocate variable */
if (entry->length != length)
{
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value == pos)
entry->value=0;
if (!(entry->value=(char*) my_realloc(entry->value, length,
MYF(MY_ALLOW_ZERO_PTR))))
goto err;
}
}
memcpy(entry->value,ptr,length);
entry->length= length;
entry->type=type;
}
return;
err:
current_thd->fatal_error=1; // Probably end of memory
null_value=1;
return;
}
bool
Item_func_set_user_var::update()
{
switch (cached_result_type) {
case REAL_RESULT:
(void) val();
break;
case INT_RESULT:
(void) val_int();
break;
case STRING_RESULT:
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer,sizeof(buffer));
(void) val_str(&tmp);
break;
}
return current_thd->fatal_error;
}
double
Item_func_set_user_var::val()
{
double value=args[0]->val();
update_hash((void*) &value,sizeof(value), REAL_RESULT);
return value;
}
longlong
Item_func_set_user_var::val_int()
{
longlong value=args[0]->val_int();
update_hash((void*) &value,sizeof(longlong),INT_RESULT);
return value;
}
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);
else
update_hash(res->c_ptr(),res->length()+1,STRING_RESULT);
return res;
}
user_var_entry *Item_func_get_user_var::get_entry()
{
if (!entry || ! entry->value)
{
null_value=1;
return 0;
}
null_value=0;
return 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);
break;
case INT_RESULT:
str->set(*(longlong*) entry->value);
break;
case STRING_RESULT:
if (str->copy(entry->value, entry->length-1))
{
null_value=1;
return NULL;
}
break;
}
return str;
}
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
}
return 0.0; // Impossible
}
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
}
return LL(0); // Impossible
}
void Item_func_get_user_var::fix_length_and_dec()
{
maybe_null=1;
decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH;
entry= get_variable(¤t_thd->user_vars, name, 0);
}
enum Item_result Item_func_get_user_var::result_type() const
{
user_var_entry *entry;
if (!(entry = (user_var_entry*) hash_search(¤t_thd->user_vars,
(byte*) name.str,
name.length)))
return STRING_RESULT;
return entry->type;
}
longlong Item_func_inet_aton::val_int()
{
uint byte_result = 0;
ulonglong result = 0; // We are ready for 64 bit addresses
const char *p,* end;
char c = '.'; // we mark c to indicate invalid IP in case length is 0
char buff[36];
String *s,tmp(buff,sizeof(buff));
if (!(s = args[0]->val_str(&tmp))) // If null value
goto err;
null_value=0;
end= (p = s->ptr()) + s->length();
while (p < end)
{
c = *p++;
int digit = (int) (c - '0'); // Assume ascii
if (digit >= 0 && digit <= 9)
{
if ((byte_result = byte_result * 10 + digit) > 255)
goto err; // Wrong address
}
else if (c == '.')
{
result= (result << 8) + (ulonglong) byte_result;
byte_result = 0;
}
else
goto err; // Invalid character
}
if (c != '.') // IP number can't end on '.'
return (result << 8) + (ulonglong) byte_result;
err:
null_value=1;
return 0;
}
double Item_func_match::val()
{
// Don't know how to return an error from val(), so NULL will be returned
if ((null_value=(ft_handler==NULL)))
return 0.0;
if (join_key)
{
if (table->file->ft_handler)
return ft_get_relevance(ft_handler);
join_key=0; // Magic here ! See ha_myisam::ft_read()
}
/* we'll have to find ft_relevance manually in ft_handler array */
int a,b,c;
FT_DOC *docs=ft_handler->doc;
my_off_t docid=table->file->row_position();
if ((null_value=(docid==HA_OFFSET_ERROR)))
return 0.0;
// Assuming docs[] is sorted by dpos...
for (a=0, b=ft_handler->ndocs, c=(a+b)/2; b-a>1; c=(a+b)/2)
{
if (docs[c].dpos > docid)
b=c;
else
a=c;
}
if (docs[a].dpos == docid)
return docs[a].weight;
else
return 0.0;
}
void Item_func_match::init_search(bool no_order)
{
if (ft_handler)
return;
if (master)
{
join_key=master->join_key=join_key|master->join_key;
master->init_search(no_order);
ft_handler=master->ft_handler;
join_key=master->join_key;
return;
}
String *ft_tmp=0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1));
ft_tmp=key_item()->val_str(&tmp2);
ft_handler=(FT_DOCLIST *)
table->file->ft_init_ext(key, (byte*) ft_tmp->ptr(), ft_tmp->length(),
join_key && !no_order);
if (join_key)
{
table->file->ft_handler=ft_handler;
return;
}
}
bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
{
List_iterator<Item> li(fields);
Item *item;
/* Why testing for const_item ? Monty */
/* I'll remove it later, but this should include modifications to
find_best and auto_close as complement to auto_init code above. SerG */
/* I'd rather say now that const_item is assumed in quite a bit of
places, so it would be difficult to remove. SerG */
if (Item_func::fix_fields(thd,tlist) || !const_item())
return 1;
while ((item=li++))
{
if (item->type() != Item::FIELD_ITEM || item->fix_fields(thd,tlist) ||
!item->used_tables())
return 1;
used_tables_cache|=item->used_tables();
}
/* check that all columns comes from the same table */
if (count_bits(used_tables_cache) != 1)
return 1;
const_item_cache=0;
table=((Item_field *)fields.head())->field->table;
return 0;
}
bool Item_func_match::fix_index()
{
List_iterator<Item> li(fields);
Item_field *item;
uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key;
for (key=0 ; key<table->keys ; key++)
{
if ((table->key_info[key].flags & HA_FULLTEXT) &&
(table->keys_in_use_for_query & (((key_map)1) << key)))
{
ft_to_key[fts]=key;
ft_cnt[fts]=0;
fts++;
}
}
if (!fts)
{
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
return 1;
}
while ((item=(Item_field*)(li++)))
{
for (key=0 ; key<fts ; key++)
{
KEY *ft_key=&table->key_info[ft_to_key[key]];
uint key_parts=ft_key->key_parts;
for (uint part=0 ; part < key_parts ; part++)
{
if (item->field->eq(ft_key->key_part[part].field))
ft_cnt[key]++;
}
}
}
uint max_cnt=0, mkeys=0;
for (key=0 ; key<fts ; key++)
{
if (ft_cnt[key] > max_cnt)
{
mkeys=0;
max_cnt=ft_cnt[mkeys]=ft_cnt[key];
ft_to_key[mkeys]=ft_to_key[key];
continue;
}
if (ft_cnt[key] == max_cnt)
{
mkeys++;
ft_cnt[mkeys]=ft_cnt[key];
ft_to_key[mkeys]=ft_to_key[key];
continue;
}
}
for (key=0 ; key<=mkeys ; key++)
{
// for now, partial keys won't work. SerG
if (max_cnt < fields.elements ||
max_cnt < table->key_info[ft_to_key[key]].key_parts)
continue;
this->key=ft_to_key[key];
maybe_null=1;
join_key=0;
return 0;
}
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
return 1;
}
bool Item_func_match::eq(const Item *item) const
{
if (item->type() != FUNC_ITEM)
return 0;
if (func_name() != ((Item_func*)item)->func_name())
return 0;
Item_func_match *ifm=(Item_func_match*) item;
if (key == ifm->key && table == ifm->table &&
key_item()->eq(ifm->key_item()))
return 1;
return 0;
}
/***************************************************************************
System variables
This has to be recoded after we get more than 3 system variables
****************************************************************************/
Item *get_system_var(LEX_STRING name)
{
if (!strcmp(name.str,"IDENTITY"))
return new Item_int((char*) "@@IDENTITY",
current_thd->insert_id(),21);
my_error(ER_UNKNOWN_SYSTEM_VARIABLE,MYF(0),name);
return 0;
}