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

920 lines
19 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 compare functions */
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#include <m_ctype.h>
/*
** Test functions
** These returns 0LL if false and 1LL if true and null if some arg is null
** 'AND' and 'OR' never return null
*/
longlong Item_func_not::val_int()
{
double val=args[0]->val();
null_value=args[0]->null_value;
return !null_value && val == 0 ? 1 : 0;
}
void Item_bool_func2::fix_length_and_dec()
{
decimals=0; max_length=1;
// Make a special case of compare with fields to get nicer DATE comparisons
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
if (field->store_for_compare() && args[1]->const_item())
{
Item *item=args[1];
item->save_in_field(field);
if (!item->null_value)
{
args[1]=new Item_int(field->val_int());
#ifdef DELETE_ITEMS
delete item;
#endif
cmp_type=INT_RESULT; // Works for all types.
return;
}
}
}
if (args[1]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[1])->field;
if (field->store_for_compare() && args[0]->const_item())
{
Item *item=args[0];
item->save_in_field(field);
if (!item->null_value)
{
args[0]=new Item_int(field->val_int());
#ifdef DELETE_ITEMS
delete item;
#endif
cmp_type=INT_RESULT; // Works for all types.
return;
}
}
}
cmp_type=item_cmp_type(args[0]->result_type(),args[1]->result_type());
}
int Item_bool_func2::compare()
{
null_value=0;
if (cmp_type == STRING_RESULT)
{
String *res1,*res2;
res1=args[0]->str(&tmp_value1);
res2=args[1]->str(&tmp_value2);
if (!args[0]->null_value && !args[1]->null_value)
{
return binary ? stringcmp(res1,res2) : sortcmp(res1,res2);
}
}
else if (cmp_type == REAL_RESULT)
{
double val1=args[0]->val();
double val2=args[1]->val();
if (!args[0]->null_value && !args[1]->null_value)
{
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
else
{
longlong val1=args[0]->val_int();
longlong val2=args[1]->val_int();
if (!args[0]->null_value && !args[1]->null_value)
{
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
null_value=1;
return 0;
}
longlong Item_func_eq::val_int()
{
int val=compare();
#ifdef mSQL_COMPLIANT
// mSQL returns true if one compares NULL_value=NULL constant
if (null_value)
{
if (args[0]->type() == NULL_ITEM ||
args[1]->type() == NULL_ITEM)
{ // Compare with NULL const
if (args[0]->null_value && args[1]->null_value)
{
null_value=0;
return 1;
}
}
return 0;
}
#endif
return val == 0 && !null_value ? 1 : 0;
}
longlong Item_func_ne::val_int()
{
int val=compare();
#ifdef mSQL_COMPLIANT
// mSQL returns true if one compares NOT NULL_value <> NULL constant
if (null_value)
{
if (args[0]->type() == NULL_ITEM ||
args[1]->type() == NULL_ITEM)
{ // Compare with NULL const
null_value=0;
return (args[0]->null_value && args[1]->null_value) ? 0 : 1;
}
return 0;
}
#endif
return val != 0 && !null_value ? 1 : 0;
}
longlong Item_func_ge::val_int()
{
int val=compare();
return val >= 0 && !null_value ? 1 : 0;
}
longlong Item_func_gt::val_int()
{
int val=compare();
return val > 0 ? 1 : 0;
}
longlong Item_func_le::val_int()
{
int val=compare();
return val <= 0 && !null_value ? 1 : 0;
}
longlong Item_func_lt::val_int()
{
int val=compare();
return val < 0 ? 1 : 0;
}
longlong Item_func_strcmp::val_int()
{
String *a=args[0]->str(&tmp_value1);
String *b=args[1]->str(&tmp_value2);
if (!a || !b)
{
null_value=1;
return 0;
}
int val=stringcmp(a,b);
null_value=0;
return !val ? 0 : (val < 0 ? (longlong) -1 : (longlong) 1);
}
void Item_func_interval::fix_length_and_dec()
{
bool nums=1;
for (uint i=0 ; i < arg_count ; i++)
{
if (args[i]->type() != Item::INT_ITEM &&
args[i]->type() != Item::REAL_ITEM)
{
nums=0;
break;
}
}
if (nums && arg_count >= 8)
{
intervals=(double*) sql_alloc(sizeof(double)*arg_count);
for (uint i=0 ; i < arg_count ; i++)
intervals[i]=args[i]->val();
}
maybe_null=0; max_length=2;
used_tables_cache|=item->used_tables();
}
/*
return -1 if null value,
0 if lower than lowest
1 - arg_count if between args[n] and args[n+1]
arg_count+1 if higher than biggest argument
*/
longlong Item_func_interval::val_int()
{
double value=item->val();
if (item->null_value)
return -1; // -1 if null /* purecov: inspected */
if (intervals)
{ // Use binary search to find interval
uint start,end;
start=0; end=arg_count-1;
while (start != end)
{
uint mid=(start+end+1)/2;
if (intervals[mid] <= value)
start=mid;
else
end=mid-1;
}
return (value < intervals[start]) ? 0 : start+1;
}
if (args[0]->val() > value)
return 0;
for (uint i=1 ; i < arg_count ; i++)
{
if (args[i]->val() > value)
return i;
}
return (longlong) arg_count;
}
void Item_func_interval::update_used_tables()
{
Item_func::update_used_tables();
item->update_used_tables();
used_tables_cache|=item->used_tables();
}
void Item_func_between::fix_length_and_dec()
{
max_length=1;
if (args[0]->binary)
string_compare=stringcmp;
else
string_compare=sortcmp;
}
longlong Item_func_between::val_int()
{ // ANSI BETWEEN
if (args[0]->result_type() == STRING_RESULT)
{
String *value,*a,*b;
value=args[0]->str(&value0);
if ((null_value=args[0]->null_value))
return 0;
a=args[1]->str(&value1);
b=args[2]->str(&value2);
if (!args[1]->null_value && !args[2]->null_value)
return (string_compare(value,a) >= 0 && string_compare(value,b) <= 0) ?
1 : 0;
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
{
null_value= string_compare(value,b) <= 0; // not null if false range.
}
else
{
null_value= string_compare(value,a) >= 0; // not null if false range.
}
}
else if (args[0]->result_type() == INT_RESULT)
{
longlong value=args[0]->val_int(),a,b;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
a=args[1]->val_int();
b=args[2]->val_int();
if (!args[1]->null_value && !args[2]->null_value)
return (value >= a && value <= b) ? 1 : 0;
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
{
null_value= value <= b; // not null if false range.
}
else
{
null_value= value >= a;
}
}
else
{
double value=args[0]->val(),a,b;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
a=args[1]->val();
b=args[2]->val();
if (!args[1]->null_value && !args[2]->null_value)
return (value >= a && value <= b) ? 1 : 0;
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
{
null_value= value <= b; // not null if false range.
}
else
{
null_value= value >= a;
}
}
return 0;
}
void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
max_length=max(args[0]->max_length,args[1]->max_length);
decimals=max(args[0]->decimals,args[1]->decimals);
cached_result_type=args[0]->result_type();
}
double
Item_func_ifnull::val()
{
double value=args[0]->val();
if (!args[0]->null_value)
{
null_value=0;
return value;
}
value=args[1]->val();
if ((null_value=args[1]->null_value))
return 0.0;
return value;
}
longlong
Item_func_ifnull::val_int()
{
longlong value=args[0]->val_int();
if (!args[0]->null_value)
{
null_value=0;
return value;
}
value=args[1]->val_int();
if ((null_value=args[1]->null_value))
return 0;
return value;
}
String *
Item_func_ifnull::str(String *str)
{
String *res =args[0]->str(str);
if (!args[0]->null_value)
{
null_value=0;
return res;
}
res=args[1]->str(str);
if ((null_value=args[1]->null_value))
return 0;
return res;
}
void
Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
max_length=max(args[1]->max_length,args[2]->max_length);
decimals=max(args[0]->decimals,args[1]->decimals);
cached_result_type = args[1]->result_type();
}
double
Item_func_if::val()
{
Item *arg= args[0]->val_int() ? args[1] : args[2];
double value=arg->val();
null_value=arg->null_value;
return value;
}
longlong
Item_func_if::val_int()
{
Item *arg= args[0]->val_int() ? args[1] : args[2];
longlong value=arg->val_int();
null_value=arg->null_value;
return value;
}
String *
Item_func_if::str(String *str)
{
Item *arg= args[0]->val_int() ? args[1] : args[2];
String *res=arg->str(str);
null_value=arg->null_value;
return res;
}
/****************************************************************************
** classes and function for the IN operator
****************************************************************************/
static int cmp_longlong(longlong *a,longlong *b)
{
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
static int cmp_double(double *a,double *b)
{
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
int in_vector::find(Item *item)
{
byte *result=get_value(item);
if (!result || !used_count)
return 0; // Null value
uint start,end;
start=0; end=used_count-1;
while (start != end)
{
uint mid=(start+end+1)/2;
int res;
if ((res=(*compare)(base+mid*size,result)) == 0)
return 1;
if (res < 0)
start=mid;
else
end=mid-1;
}
return (int) ((*compare)(base+start*size,result) == 0);
}
in_string::in_string(uint elements,qsort_cmp cmp_func)
:in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff))
{}
in_string::~in_string()
{
for (uint i=0 ; i < count ; i++)
((String*) base)[i].free();
}
void in_string::set(uint pos,Item *item)
{
String *str=((String*) base)+pos;
String *res=item->str(str);
if (res && res != str)
*str= *res;
}
byte *in_string::get_value(Item *item)
{
return (byte*) item->str(&tmp);
}
in_longlong::in_longlong(uint elements)
:in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong)
{}
void in_longlong::set(uint pos,Item *item)
{
((longlong*) base)[pos]=item->val_int();
}
byte *in_longlong::get_value(Item *item)
{
tmp=item->val_int();
if (item->null_value)
return 0; /* purecov: inspected */
return (byte*) &tmp;
}
in_double::in_double(uint elements)
:in_vector(elements,sizeof(double),(qsort_cmp) cmp_double)
{}
void in_double::set(uint pos,Item *item)
{
((double*) base)[pos]=item->val();
}
byte *in_double::get_value(Item *item)
{
tmp=item->val();
if (item->null_value)
return 0; /* purecov: inspected */
return (byte*) &tmp;
}
void Item_func_in::fix_length_and_dec()
{
if (const_item())
{
switch (item->result_type()) {
case STRING_RESULT:
if (item->binary)
array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */
else
array=new in_string(arg_count,(qsort_cmp) sortcmp);
break;
case INT_RESULT:
array= new in_longlong(arg_count);
break;
case REAL_RESULT:
array= new in_double(arg_count);
break;
}
uint j=0;
for (uint i=0 ; i < arg_count ; i++)
{
array->set(j,args[i]);
if (!args[i]->null_value) // Skipp NULL values
j++;
}
if ((array->used_count=j))
array->sort();
}
else
{
switch (item->result_type()) {
case STRING_RESULT:
if (item->binary)
in_item= new cmp_item_binary_string;
else
in_item= new cmp_item_sort_string;
break;
case INT_RESULT:
in_item= new cmp_item_int;
break;
case REAL_RESULT:
in_item= new cmp_item_real;
break;
}
}
maybe_null=0; max_length=2;
used_tables_cache|=item->used_tables();
}
void Item_func_in::print(String *str)
{
str->append('(');
item->print(str);
Item_func::print(str);
str->append(')');
}
longlong Item_func_in::val_int()
{
if (array)
return array->find(item);
in_item->store_value(item);
if (item->null_value)
return 0;
for (uint i=0 ; i < arg_count ; i++)
{
if (!in_item->cmp(args[i]) && !args[i]->null_value)
return 1; // Would maybe be nice with i ?
}
return 0;
}
void Item_func_in::update_used_tables()
{
Item_func::update_used_tables();
item->update_used_tables();
used_tables_cache|=item->used_tables();
}
longlong Item_func_bit_or::val_int()
{
ulonglong arg1= (ulonglong) args[0]->val_int();
if (args[0]->null_value)
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
ulonglong arg2= (ulonglong) args[1]->val_int();
if (args[1]->null_value)
{
null_value=1;
return 0;
}
null_value=0;
return (longlong) (arg1 | arg2);
}
longlong Item_func_bit_and::val_int()
{
ulonglong arg1= (ulonglong) args[0]->val_int();
if (args[0]->null_value)
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
ulonglong arg2= (ulonglong) args[1]->val_int();
if (args[1]->null_value)
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
null_value=0;
return (longlong) (arg1 & arg2);
}
bool
Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
{
List_iterator<Item> li(list);
Item *item;
char buff[sizeof(char*)]; // Max local vars in function
used_tables_cache=0;
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set!
while ((item=li++))
{
while (item->type() == Item::COND_ITEM &&
((Item_cond*) item)->functype() == functype())
{ // Identical function
li.replace(((Item_cond*) item)->list);
((Item_cond*) item)->list.empty();
#ifdef DELETE_ITEMS
delete (Item_cond*) item;
#endif
item= *li.ref(); // new current item
}
if (item->fix_fields(thd,tables))
return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func;
}
if (thd)
thd->cond_count+=list.elements;
fix_length_and_dec();
return 0;
}
void Item_cond::split_sum_func(List<Item> &fields)
{
List_iterator<Item> li(list);
Item *item;
while ((item=li++))
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
item->split_sum_func(fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
fields.push_front(item);
li.replace(new Item_ref((Item**) fields.head_ref(),0,item->name));
}
item->update_used_tables();
used_tables_cache|=item->used_tables();
}
}
ulong
Item_cond::used_tables() const
{ // This caches used_tables
return used_tables_cache;
}
void Item_cond::update_used_tables()
{
used_tables_cache=0;
List_iterator<Item> li(list);
Item *item;
while ((item=li++))
{
item->update_used_tables();
used_tables_cache|=item->used_tables();
}
}
void Item_cond::print(String *str)
{
str->append('(');
List_iterator<Item> li(list);
Item *item;
if ((item=li++))
item->print(str);
while ((item=li++))
{
str->append(' ');
str->append(func_name());
str->append(' ');
item->print(str);
}
str->append(')');
}
longlong Item_cond_and::val_int()
{
List_iterator<Item> li(list);
Item *item;
while ((item=li++))
if (item->val_int() == 0)
return 0;
return 1;
}
longlong Item_cond_or::val_int()
{
List_iterator<Item> li(list);
Item *item;
while ((item=li++))
if (item->val_int() != 0)
return 1;
return 0;
}
longlong Item_func_isnull::val_int()
{
(void) args[0]->val();
return (args[0]->null_value) ? 1 : 0;
}
longlong Item_func_isnotnull::val_int()
{
(void) args[0]->val();
return !(args[0]->null_value) ? 1 : 0;
}
void Item_func_like::fix_length_and_dec()
{
decimals=0; max_length=1;
cmp_type=STRING_RESULT; // For quick select
}
longlong Item_func_like::val_int()
{
String *res,*res2;
res=args[0]->str(&tmp_value1);
if (args[0]->null_value)
{
null_value=1;
return 0;
}
res2=args[1]->str(&tmp_value2);
if (args[1]->null_value)
{
null_value=1;
return 0;
}
null_value=0;
if (binary)
return wild_compare(*res,*res2,escape) ? 0 : 1;
else
return wild_case_compare(*res,*res2,escape) ? 0 : 1;
}
/* We can optimize a where if first character isn't a wildcard */
Item_func::optimize_type Item_func_like::select_optimize() const
{
if (args[1]->type() == STRING_ITEM)
{
if (((Item_string *) args[1])->str_value[0] != wild_many)
{
if ((args[0]->result_type() != STRING_RESULT) ||
((Item_string *) args[1])->str_value[0] != wild_one)
return OPTIMIZE_OP;
}
}
return OPTIMIZE_NONE;
}
#ifdef USE_REGEX
bool
Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
{
if (args[0]->fix_fields(thd,tables) || args[1]->fix_fields(thd,tables))
return 1; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;;
max_length=1; decimals=0;
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
if (!regex_compiled && args[1]->const_item())
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff));
String *res=args[1]->str(&tmp);
if (args[1]->null_value)
{
my_error(ER_INVALID_USE_OF_NULL,MYF(0));
return 1;
}
int error;
if ((error=regcomp(&preg,res->c_ptr(),REG_EXTENDED | REG_NOSUB)))
{
char buff[100];
(void) regerror(error,&preg,buff,sizeof(buff));
my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff);
return 1;
}
regex_compiled=regex_is_const=1;
maybe_null=args[0]->maybe_null;
}
else
maybe_null=1;
return 0;
}
longlong Item_func_regex::val_int()
{
char buff[MAX_FIELD_WIDTH];
String *res, tmp(buff,sizeof(buff));
res=args[0]->str(&tmp);
if (args[0]->null_value)
{
null_value=1;
return 0;
}
if (!regex_is_const)
{
char buff2[MAX_FIELD_WIDTH];
String *res2, tmp2(buff2,sizeof(buff2));
res2= args[1]->str(&tmp2);
if (args[1]->null_value)
{
null_value=1;
return 0;
}
if (!regex_compiled || stringcmp(res2,&prev_regexp))
{
prev_regexp.copy(*res2);
if (regex_compiled)
{
regfree(&preg);
regex_compiled=0;
}
if (regcomp(&preg,res2->c_ptr(),REG_EXTENDED | REG_NOSUB))
{
null_value=1;
return 0;
}
regex_compiled=1;
}
}
null_value=0;
return regexec(&preg,res->c_ptr(),0,(regmatch_t*) 0,0) ? 0 : 1;
}
Item_func_regex::~Item_func_regex()
{
if (regex_compiled)
{
regfree(&preg);
regex_compiled=0;
}
}
#endif /* USE_REGEX */