diff options
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 299 |
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(¤t_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)); |