summaryrefslogtreecommitdiff
path: root/sql/item_func.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r--sql/item_func.cc299
1 files changed, 225 insertions, 74 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8728187718c..bd811726b47 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -58,6 +58,41 @@ Item_func::Item_func(List<Item> &list)
list.empty(); // Fields are used
}
+
+/*
+ Resolve references to table column for a function and it's argument
+
+ SYNOPSIS:
+ fix_fields()
+ thd Thread object
+ tables List of all open tables involved in the query
+ ref Pointer to where this object is used. This reference
+ is used if we want to replace this object with another
+ one (for example in the summary functions).
+
+ DESCRIPTION
+ Call fix_fields() for all arguments to the function. The main intention
+ is to allow all Item_field() objects to setup pointers to the table fields.
+
+ Sets as a side effect the following class variables:
+ maybe_null Set if any argument may return NULL
+ binary Set if any of the arguments is binary
+ with_sum_func Set if any of the arguments contains a sum function
+ used_table_cache Set to union of the arguments used table
+
+ str_value.charset If this is a string function, set this to the
+ character set for the first argument.
+
+ If for any item any of the defaults are wrong, then this can
+ be fixed in the fix_length_and_dec() function that is called
+ after this one or by writing a specialized fix_fields() for the
+ item.
+
+ RETURN VALUES
+ 0 ok
+ 1 Got error. Stored with my_error().
+*/
+
bool
Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
@@ -79,21 +114,16 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
maybe_null=1;
if ((*arg)->binary)
binary=1;
- /*
- Change charset to arg charset if it is not equal to
- default_charset_info. This will work for many cases,
- but generally this should be done more carefull. Each string
- function should have it's own fix_fields() method to correctly
- setup it's result's character set taking in account arguments.
- For example: left(a,b) should take in account only first argument,
- but ignore the second one.
- */
- if ((*arg)->str_value.charset() != default_charset_info)
- str_value.set_charset((*arg)->str_value.charset());
with_sum_func= with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
const_item_cache&= (*arg)->const_item();
}
+ /*
+ Set return character set to first argument if we are returning a
+ string.
+ */
+ if (result_type() == STRING_RESULT)
+ str_value.set_charset((*args)->str_value.charset());
}
fix_length_and_dec();
return 0;
@@ -180,6 +210,36 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
}
+Field *Item_func::tmp_table_field(TABLE *t_arg)
+{
+ Field *res;
+ LINT_INIT(res);
+
+ if (!t_arg)
+ return result_field;
+ switch (args[0]->result_type()) {
+ case INT_RESULT:
+ if (max_length > 11)
+ res= new Field_longlong(max_length, maybe_null, name, t_arg,
+ unsigned_flag);
+ else
+ res= new Field_long(max_length, maybe_null, name, t_arg,
+ unsigned_flag);
+ break;
+ case REAL_RESULT:
+ res= new Field_double(max_length, maybe_null, name, t_arg, decimals);
+ break;
+ case STRING_RESULT:
+ if (max_length > 255)
+ res= new Field_blob(max_length, maybe_null, name, t_arg, binary);
+ else
+ res= new Field_string(max_length, maybe_null, name, t_arg, binary);
+ break;
+ }
+ return res;
+}
+
+
String *Item_real_func::val_str(String *str)
{
double nr=val();
@@ -451,14 +511,43 @@ void Item_func_abs::fix_length_and_dec()
hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
}
+/* Gateway to natural LOG function */
+double Item_func_ln::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || value <= 0.0)))
+ return 0.0;
+ return log(value);
+}
+
+/*
+ Extended but so slower LOG function
+ We have to check if all values are > zero and first one is not one
+ as these are the cases then result is not a number.
+*/
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 0.0;
+ if (arg_count == 2)
+ {
+ double value2= args[1]->val();
+ if ((null_value=(args[1]->null_value || value2 <= 0.0 || value == 1.0)))
+ return 0.0;
+ return log(value2) / log(value);
+ }
return log(value);
}
+double Item_func_log2::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || value <= 0.0)))
+ return 0.0;
+ return log(value) / log(2.0);
+}
+
double Item_func_log10::val()
{
double value=args[0]->val();
@@ -891,7 +980,8 @@ longlong Item_func_locate::val_int()
return (longlong) start0+1;
}
skipp:
- if ((l=my_ismbchar(a->charset(),ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(a->charset(),ptr,strend)))
+ ptr+=l;
else ++ptr;
++start0;
}
@@ -946,7 +1036,8 @@ longlong Item_func_ord::val_int()
{
register const char *str=res->ptr();
register uint32 n=0, l=my_ismbchar(res->charset(),str,str+res->length());
- if (!l) return (longlong)((uchar) *str);
+ if (!l)
+ return (longlong)((uchar) *str);
while (l--)
n=(n<<8)|(uint32)((uchar) *str++);
return (longlong) n;
@@ -1006,6 +1097,7 @@ longlong Item_func_find_in_set::val_int()
null_value=0;
int diff;
+ CHARSET_INFO *charset= find->charset();
if ((diff=buffer->length() - find->length()) >= 0)
{
const char *f_pos=find->ptr();
@@ -1019,8 +1111,7 @@ longlong Item_func_find_in_set::val_int()
const char *pos= f_pos;
while (pos != f_end)
{
- if (my_toupper(find->charset(),*str) !=
- my_toupper(find->charset(),*pos))
+ if (my_toupper(charset,*str) != my_toupper(charset,*pos))
goto not_found;
str++;
pos++;
@@ -1464,20 +1555,15 @@ void item_user_lock_release(ULL *ull)
ull->locked=0;
if (mysql_bin_log.is_open())
{
- THD *thd = current_thd;
- uint save_query_length;
char buf[256];
- String tmp(buf,sizeof(buf), default_charset_info);
- tmp.length(0);
- tmp.append("DO RELEASE_LOCK(\"");
+ const char *command="DO RELEASE_LOCK(\"";
+ String tmp(buf,sizeof(buf), system_charset_info);
+ tmp.copy(command, strlen(command));
tmp.append(ull->key,ull->key_length);
tmp.append("\")");
- save_query_length=thd->query_length;
- thd->query_length=tmp.length();
- Query_log_event qev(thd,tmp.ptr());
+ Query_log_event qev(current_thd,tmp.ptr(), tmp.length());
qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
- thd->query_length=save_query_length;
}
if (--ull->count)
pthread_cond_signal(&ull->cond);
@@ -1529,10 +1615,11 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
thd->ull=0;
}
- /* if the lock has not been aquired by some client, we do not want to
- create an entry for it, since we immediately release the lock. In
- this case, we will not be waiting, but rather, just waste CPU and
- memory on the whole deal
+ /*
+ If the lock has not been aquired by some client, we do not want to
+ create an entry for it, since we immediately release the lock. In
+ this case, we will not be waiting, but rather, just waste CPU and
+ memory on the whole deal
*/
if (!(ull= ((ULL*) hash_search(&hash_user_locks,lock_name,
lock_name_len))))
@@ -1542,8 +1629,10 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
}
ull->count++;
- /* structure is now initialized. Try to get the lock */
- /* Set up control struct to allow others to abort locks */
+ /*
+ Structure is now initialized. Try to get the lock.
+ Set up control struct to allow others to abort locks
+ */
thd->proc_info="User lock";
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
@@ -1630,8 +1719,10 @@ longlong Item_func_get_lock::val_int()
}
ull->count++;
- /* structure is now initialized. Try to get the lock */
- /* Set up control struct to allow others to abort locks */
+ /*
+ Structure is now initialized. Try to get the lock.
+ Set up control struct to allow others to abort locks.
+ */
thd->proc_info="User lock";
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
@@ -1672,10 +1763,11 @@ longlong Item_func_get_lock::val_int()
/*
-** Release a user level lock.
-** Returns 1 if lock released
-** 0 if lock wasn't held
-** NULL if no such lock
+ Release a user level lock.
+ Return:
+ 1 if lock released
+ 0 if lock wasn't held
+ (SQL) NULL if no such lock
*/
longlong Item_func_release_lock::val_int()
@@ -1744,6 +1836,7 @@ longlong Item_func_benchmark::val_int()
return 0;
}
+
#define extra_size sizeof(double)
static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
@@ -1782,7 +1875,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref)
{
if (!thd)
- thd=current_thd;
+ thd=current_thd; // Should never happen
if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
@@ -2008,6 +2101,7 @@ void Item_func_get_user_var::print(String *str)
str->append(')');
}
+
bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
{
/* Assume we don't have rtti */
@@ -2067,6 +2161,7 @@ err:
return 0;
}
+
void Item_func_match::init_search(bool no_order)
{
if (ft_handler)
@@ -2086,14 +2181,14 @@ void Item_func_match::init_search(bool no_order)
return;
}
- String *ft_tmp=0;
+ String *ft_tmp= 0;
char tmp1[FT_QUERY_MAXLEN];
String tmp2(tmp1,sizeof(tmp1),default_charset_info);
// MATCH ... AGAINST (NULL) is meaningless, but possible
if (!(ft_tmp=key_item()->val_str(&tmp2)))
{
- ft_tmp=&tmp2;
+ ft_tmp= &tmp2;
tmp2.set("",0,default_charset_info);
}
@@ -2109,6 +2204,7 @@ void Item_func_match::init_search(bool no_order)
}
}
+
bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
List_iterator<Item> li(fields);
@@ -2117,10 +2213,11 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
maybe_null=1;
join_key=0;
- /* const_item is assumed in quite a bit of places, so it would be difficult
- to remove; If it would ever to be removed, this should include
- modifications to find_best and auto_close as complement to auto_init code
- above.
+ /*
+ const_item is assumed in quite a bit of places, so it would be difficult
+ to remove; If it would ever to be removed, this should include
+ modifications to find_best and auto_close as complement to auto_init code
+ above.
*/
if (Item_func::fix_fields(thd, tlist, ref) || !const_item())
{
@@ -2140,7 +2237,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
}
/* check that all columns come from the same table */
if (count_bits(used_tables_cache) != 1)
- key=NO_SUCH_KEY;
+ key=NO_SUCH_KEY;
const_item_cache=0;
table=((Item_field *)fields.head())->field->table;
table->fulltext_searched=1;
@@ -2154,6 +2251,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
return 0;
}
+
bool Item_func_match::fix_index()
{
List_iterator_fast<Item> li(fields);
@@ -2230,16 +2328,15 @@ err:
return 0;
}
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
- ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
+ ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
return 1;
}
+
bool Item_func_match::eq(const Item *item, bool binary_cmp) const
{
- if (item->type() != FUNC_ITEM)
- return 0;
-
- if (func_name() != ((Item_func*)item)->func_name())
+ if (item->type() != FUNC_ITEM ||
+ func_name() != ((Item_func*)item)->func_name())
return 0;
Item_func_match *ifm=(Item_func_match*) item;
@@ -2251,6 +2348,7 @@ bool Item_func_match::eq(const Item *item, bool binary_cmp) const
return 0;
}
+
double Item_func_match::val()
{
if (ft_handler == NULL)
@@ -2260,14 +2358,13 @@ double Item_func_match::val()
{
if (table->file->ft_handler)
return ft_handler->please->get_relevance(ft_handler);
-
join_key=0;
}
if (key == NO_SUCH_KEY)
{
- String *a=concat->val_str(&value);
- if ((null_value= (a==0)))
+ String *a= concat->val_str(&value);
+ if ((null_value= (a == 0)))
return 0;
return ft_handler->please->find_relevance(ft_handler,
(byte *)a->ptr(), a->length());
@@ -2276,26 +2373,86 @@ double Item_func_match::val()
return ft_handler->please->find_relevance(ft_handler, record, 0);
}
+
+longlong Item_func_bit_xor::val_int()
+{
+ ulonglong arg1= (ulonglong) args[0]->val_int();
+ ulonglong arg2= (ulonglong) args[1]->val_int();
+ if ((null_value= (args[0]->null_value || args[1]->null_value)))
+ return 0;
+ return (longlong) (arg1 ^ arg2);
+}
+
+
/***************************************************************************
System variables
- This has to be recoded after we get more than 3 system variables
****************************************************************************/
-Item *get_system_var(LEX_STRING name)
+Item *get_system_var(enum_var_type var_type, LEX_STRING name)
{
- if (!my_strcasecmp(system_charset_info, name.str, "IDENTITY"))
- return new Item_int((char*) "@@IDENTITY",
- current_thd->insert_id(),21);
- if (!my_strcasecmp(system_charset_info, name.str, "VERSION"))
+ if (!my_strcasecmp(name.str,"VERSION"))
return new Item_string("@@VERSION",server_version,
- (uint) strlen(server_version), system_charset_info);
- net_printf(&current_thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str);
+ (uint) strlen(server_version));
+
+ THD *thd=current_thd;
+ Item *item;
+ sys_var *var;
+ char buff[MAX_SYS_VAR_LENGTH+3];
+
+ if (!(var= find_sys_var(name.str)))
+ {
+ net_printf(&thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str);
+ return 0;
+ }
+ if (!(item=var->item(thd, var_type)))
+ return 0; // Impossible
+ thd->safe_to_cache_query=0;
+ buff[0]='@';
+ buff[1]='@';
+ memcpy(buff+2, var->name, var->name_length+1);
+ item->set_name(buff,var->name_length+2); // Will allocate name
+ return item;
+}
+
+
+/*
+ Check a user level lock.
+
+ SYNOPSIS:
+ val_int()
+
+ RETURN VALUES
+ 1 Available
+ 0 Already taken
+ NULL Error
+*/
+
+longlong Item_func_is_free_lock::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ THD *thd=current_thd;
+ ULL *ull;
+ int error=0;
+
+ null_value=0;
+ if (!res || !res->length())
+ {
+ null_value=1;
+ return 0;
+ }
+
+ pthread_mutex_lock(&LOCK_user_locks);
+ ull= (ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),
+ res->length());
+ pthread_mutex_unlock(&LOCK_user_locks);
+ if (!ull || !ull->locked)
+ return 1;
return 0;
}
/**************************************************************************
-Spatial functions
+ Spatial functions
***************************************************************************/
longlong Item_func_dimension::val_int()
@@ -2319,7 +2476,6 @@ longlong Item_func_numinteriorring::val_int()
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,num_interior_ring) ||
geom.num_interior_ring(&num));
@@ -2329,12 +2485,11 @@ longlong Item_func_numinteriorring::val_int()
longlong Item_func_numgeometries::val_int()
{
- uint32 num;
+ uint32 num=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,num_geometries) ||
geom.num_geometries(&num));
@@ -2344,7 +2499,7 @@ longlong Item_func_numgeometries::val_int()
longlong Item_func_numpoints::val_int()
{
- uint32 num;
+ uint32 num=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
@@ -2360,12 +2515,11 @@ longlong Item_func_numpoints::val_int()
double Item_func_x::val()
{
- double res;
+ double res=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,get_x) ||
geom.get_x(&res));
@@ -2376,12 +2530,11 @@ double Item_func_x::val()
double Item_func_y::val()
{
- double res;
+ double res=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,get_y) ||
geom.get_y(&res));
@@ -2392,12 +2545,11 @@ double Item_func_y::val()
double Item_func_area::val()
{
- double res;
+ double res=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,area) ||
geom.area(&res));
@@ -2408,12 +2560,11 @@ double Item_func_area::val()
double Item_func_glength::val()
{
- double res;
+ double res=0;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
- args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,length) ||
geom.length(&res));