diff options
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 645 |
1 files changed, 433 insertions, 212 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 217768db2c5..8e9677cc459 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -43,7 +43,7 @@ Item_func::Item_func(List<Item> &list) if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) { uint i=0; - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) @@ -61,7 +61,7 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) Item **arg,**arg_end; char buff[STACK_BUFF_ALLOC]; // Max argument in function binary=0; - used_tables_cache=0; + used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; if (thd && check_stack_overrun(thd,buff)) @@ -70,15 +70,17 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd,tables)) + Item *item=*arg; + if (item->fix_fields(thd,tables)) return 1; /* purecov: inspected */ - if ((*arg)->maybe_null) + if (item->maybe_null) maybe_null=1; - if ((*arg)->binary) + if (item->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(); + with_sum_func= with_sum_func || item->with_sum_func; + used_tables_cache|= item->used_tables(); + not_null_tables_cache|= item->not_null_tables(); + const_item_cache&= item->const_item(); } } fix_length_and_dec(); @@ -91,12 +93,13 @@ 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) + Item *item=*arg; + 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(*arg); - *arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name); + *arg=new Item_ref((Item**) fields.head_ref(),0,item->name); } } } @@ -120,6 +123,13 @@ table_map Item_func::used_tables() const return used_tables_cache; } + +table_map Item_func::not_null_tables() const +{ + return not_null_tables_cache; +} + + void Item_func::print(String *str) { str->append(func_name()); @@ -166,6 +176,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 (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(); @@ -184,8 +224,10 @@ String *Item_num_func::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; /* purecov: inspected */ - else + else if (!unsigned_flag) str->set(nr); + else + str->set((ulonglong) nr); } else { @@ -207,24 +249,31 @@ void Item_func::fix_num_length_and_dec() max_length=float_length(decimals); } - String *Item_int_func::val_str(String *str) { longlong nr=val_int(); if (null_value) return 0; - else + else if (!unsigned_flag) str->set(nr); + else + str->set((ulonglong) nr); return str; } -/* Change from REAL_RESULT (default) to INT_RESULT if both arguments are integers */ +/* + 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; + unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; + } } String *Item_num_op::val_str(String *str) @@ -234,8 +283,10 @@ String *Item_num_op::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; /* purecov: inspected */ - else + else if (!unsigned_flag) str->set(nr); + else + str->set((ulonglong) nr); } else { @@ -269,6 +320,21 @@ longlong Item_func_plus::val_int() return (longlong) Item_func_plus::val(); } + +/* + The following function is here to allow the user to force + subtraction of UNSIGNED BIGINT to return negative values. +*/ + +void Item_func_minus::fix_length_and_dec() +{ + Item_num_op::fix_length_and_dec(); + if (unsigned_flag && + (current_thd->sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) + unsigned_flag=0; +} + + double Item_func_minus::val() { double value=args[0]->val() - args[1]->val(); @@ -411,14 +477,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(); @@ -594,35 +689,64 @@ double Item_func_round::val() double value=args[0]->val(); int dec=(int) args[1]->val_int(); uint abs_dec=abs(dec); + double tmp; + /* + tmp2 is here to avoid return the value with 80 bit precision + This will fix that the test round(0.1,1) = round(0.1,1) is true + */ + volatile double tmp2; 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)); + tmp=(abs_dec < array_elements(log_10) ? + log_10[abs_dec] : pow(10.0,(double) abs_dec)); if (truncate) { if (value >= 0) - return dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp; + tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp; else - return dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp; + tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp; } - return dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp; + else + tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp; + return tmp2; } -double Item_func_rand::val() +void Item_func_rand::fix_length_and_dec() { + decimals=NOT_FIXED_DEC; + max_length=float_length(decimals); 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; + uint32 tmp= (uint32) (args[0]->val_int()); + if ((rand= (struct rand_struct*) sql_alloc(sizeof(*rand)))) + randominit(rand,(uint32) (tmp*0x10001L+55555555L), + (uint32) (tmp*0x10000001L)); } - return rnd(¤t_thd->rand); + else + { + THD *thd= current_thd; + /* + No need to send a Rand log event if seed was given eg: RAND(seed), + as it will be replicated in the query as such. + + Save the seed only the first time RAND() is used in the query + Once events are forwarded rather than recreated, + the following can be skipped if inside the slave thread + */ + thd->rand_used=1; + thd->rand_saved_seed1=thd->rand.seed1; + thd->rand_saved_seed2=thd->rand.seed2; + rand= &thd->rand; + } +} + + +double Item_func_rand::val() +{ + return my_rnd(rand); } longlong Item_func_sign::val_int() @@ -672,8 +796,10 @@ String *Item_func_min_max::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else + else if (!unsigned_flag) str->set(nr); + else + str->set((ulonglong) nr); return str; } case REAL_RESULT: @@ -789,9 +915,7 @@ 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; @@ -845,7 +969,8 @@ longlong Item_func_locate::val_int() return 0; } #endif /* USE_MB */ - return (longlong) (a->strstr(*b,start)+1) ; + return (longlong) (binary ? a->strstr(*b,start) : + (a->strstr_case(*b,start)))+1; } @@ -993,47 +1118,6 @@ longlong Item_func_find_in_set::val_int() 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(); @@ -1042,7 +1126,7 @@ longlong Item_func_bit_count::val_int() null_value=1; /* purecov: inspected */ return 0; /* purecov: inspected */ } - return (longlong) count_bits(value); + return (longlong) my_count_bits(value); } @@ -1066,7 +1150,8 @@ udf_handler::~udf_handler() } free_udf(u_d); } - delete [] buffers; + if (buffers) // Because of bug in ecc + delete [] buffers; } @@ -1115,16 +1200,17 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, arg != arg_end ; arg++,i++) { - if ((*arg)->fix_fields(thd,tables)) + Item *item=*arg; + if (item->fix_fields(thd,tables)) return 1; - if ((*arg)->binary) + if (item->binary) func->binary=1; - if ((*arg)->maybe_null) + if (item->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(); + func->with_sum_func= func->with_sum_func || item->with_sum_func; + used_tables_cache|=item->used_tables(); + const_item_cache&=item->const_item(); + f_args.arg_type[i]=item->result_type(); } if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || @@ -1322,8 +1408,10 @@ String *Item_func_udf_int::val_str(String *str) longlong nr=val_int(); if (null_value) return 0; - else + else if (!unsigned_flag) str->set(nr); + else + str->set((ulonglong) nr); return str; } @@ -1410,6 +1498,7 @@ void item_user_lock_init(void) void item_user_lock_free(void) { hash_free(&hash_user_locks); + pthread_mutex_destroy(&LOCK_user_locks); } void item_user_lock_release(ULL *ull) @@ -1417,20 +1506,15 @@ void item_user_lock_release(ULL *ull) ull->locked=0; if (mysql_bin_log.is_open()) { - THD *thd = current_thd; - int save_errno; char buf[256]; String tmp(buf,sizeof(buf)); tmp.length(0); tmp.append("DO RELEASE_LOCK(\""); tmp.append(ull->key,ull->key_length); tmp.append("\")"); - save_errno=thd->net.last_errno; - thd->net.last_errno=0; - thd->query_length=tmp.length(); - Query_log_event qev(thd,tmp.ptr()); + Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1); + qev.error_code=0; // this query is always safe to run on slave mysql_bin_log.write(&qev); - thd->net.last_errno=save_errno; } if (--ull->count) pthread_cond_signal(&ull->cond); @@ -1448,22 +1532,95 @@ longlong Item_master_pos_wait::val_int() THD* thd = current_thd; String *log_name = args[0]->val_str(&value); int event_count; - + null_value=0; if (thd->slave_thread || !log_name || !log_name->length()) { null_value = 1; return 0; } - ulong pos = (ulong)args[1]->val_int(); - if ((event_count = glob_mi.wait_for_pos(thd, log_name, pos)) == -1) + longlong pos = args[1]->val_int(); + longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ; + LOCK_ACTIVE_MI; + if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) { null_value = 1; event_count=0; } + UNLOCK_ACTIVE_MI; return event_count; } +#ifdef EXTRA_DEBUG +void debug_sync_point(const char* lock_name, uint lock_timeout) +{ + THD* thd=current_thd; + ULL* ull; + struct timespec abstime; + int lock_name_len,error=0; + lock_name_len=strlen(lock_name); + pthread_mutex_lock(&LOCK_user_locks); + + if (thd->ull) + { + item_user_lock_release(thd->ull); + 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 (!(ull= ((ULL*) hash_search(&hash_user_locks,lock_name, + lock_name_len)))) + { + pthread_mutex_unlock(&LOCK_user_locks); + return; + } + ull->count++; + + /* + 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; + + set_timespec(abstime,lock_timeout); + while (!thd->killed && + (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime)) + != ETIME && error != ETIMEDOUT && ull->locked) ; + if (ull->locked) + { + if (!--ull->count) + delete ull; // Should never happen + } + else + { + ull->locked=1; + ull->thread=thd->real_id; + thd->ull=ull; + } + 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); + pthread_mutex_lock(&LOCK_user_locks); + if (thd->ull) + { + item_user_lock_release(thd->ull); + thd->ull=0; + } + pthread_mutex_unlock(&LOCK_user_locks); +} + +#endif + /* Get a user level lock. If the thread has an old lock this is first released. Returns 1: Got lock @@ -1514,20 +1671,15 @@ 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; -#ifdef HAVE_TIMESPEC_TS_SEC - abstime.ts_sec=time((time_t*) 0)+(time_t) timeout; - abstime.ts_nsec=0; -#else - abstime.tv_sec=time((time_t*) 0)+(time_t) timeout; - abstime.tv_nsec=0; -#endif - + set_timespec(abstime,timeout); while (!thd->killed && (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime)) != ETIME && error != ETIMEDOUT && error != EINVAL && ull->locked) ; @@ -1563,10 +1715,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() @@ -1635,6 +1788,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, @@ -1672,7 +1826,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables) { if (!thd) - thd=current_thd; + thd=current_thd; // Should never happen if (Item_func::fix_fields(thd,tables) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; @@ -1801,13 +1955,13 @@ void Item_func_set_user_var::print(String *str) user_var_entry *Item_func_get_user_var::get_entry() { - if (!entry || ! entry->value) + if (!var_entry || ! var_entry->value) { null_value=1; return 0; } null_value=0; - return entry; + return var_entry; } @@ -1876,11 +2030,14 @@ void Item_func_get_user_var::fix_length_and_dec() maybe_null=1; decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - if ((entry= get_variable(&thd->user_vars, name, 0))) - const_var_flag= thd->query_id != entry->update_query_id; + var_entry= get_variable(&thd->user_vars, name, 0); } +bool Item_func_get_user_var::const_item() const +{ return var_entry && current_thd->query_id != var_entry->update_query_id; } + + enum Item_result Item_func_get_user_var::result_type() const { user_var_entry *entry; @@ -1899,6 +2056,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 */ @@ -1958,48 +2116,15 @@ err: return 0; } -double Item_func_match::val() -{ - if (ft_handler==NULL) - return -1.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) { + DBUG_ENTER("Item_func_match::init_search"); if (ft_handler) - return; + DBUG_VOID_RETURN; + + if (key == NO_SUCH_KEY) + concat= new Item_func_concat_ws(new Item_string(" ",1), fields); if (master) { @@ -2007,31 +2132,32 @@ void Item_func_match::init_search(bool no_order) master->init_search(no_order); ft_handler=master->ft_handler; join_key=master->join_key; - return; + DBUG_VOID_RETURN; } String *ft_tmp=0; char tmp1[FT_QUERY_MAXLEN]; String tmp2(tmp1,sizeof(tmp1)); - // MATCH ... AGAINST (NULL) is meaningless, but possible + // MATCH ... AGAINST (NULL) is meaningless, but possible if (!(ft_tmp=key_item()->val_str(&tmp2))) { - ft_tmp=&tmp2; + ft_tmp= &tmp2; tmp2.set("",0); } - ft_handler=(FT_DOCLIST *) - table->file->ft_init_ext(key, (byte*) ft_tmp->ptr(), ft_tmp->length(), - join_key && !no_order); + ft_handler=table->file->ft_init_ext(mode, key, + (byte*) ft_tmp->ptr(), + ft_tmp->length(), + join_key && !no_order); if (join_key) - { table->file->ft_handler=ft_handler; - return; - } + + DBUG_VOID_RETURN; } + bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) { List_iterator<Item> li(fields); @@ -2040,12 +2166,12 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) maybe_null=1; join_key=0; - /* Serg: - I'd rather say now that 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) || !const_item()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); @@ -2059,106 +2185,111 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) if (item->type() == Item::REF_ITEM) li.replace(item= *((Item_ref *)item)->ref); if (item->type() != Item::FIELD_ITEM || !item->used_tables()) - { - my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); - return 1; - } + key=NO_SUCH_KEY; used_tables_cache|=item->used_tables(); } /* check that all columns come from the same table */ - if (count_bits(used_tables_cache) != 1) + if (my_count_bits(used_tables_cache) != 1) + key=NO_SUCH_KEY; + const_item_cache=0; + table=((Item_field *)fields.head())->field->table; + table->fulltext_searched=1; + record=table->record[0]; + if (key == NO_SUCH_KEY && mode != FT_BOOL) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); return 1; } - const_item_cache=0; - table=((Item_field *)fields.head())->field->table; - table->fulltext_searched=1; + return 0; } bool Item_func_match::fix_index() { - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Item_field *item; - uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key; + uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, keynr; + uint max_cnt=0, mkeys=0; + + if (key == NO_SUCH_KEY) + return 0; - for (key=0 ; key<table->keys ; key++) + for (keynr=0 ; keynr < table->keys ; keynr++) { - if ((table->key_info[key].flags & HA_FULLTEXT) && - (table->keys_in_use_for_query & (((key_map)1) << key))) + if ((table->key_info[keynr].flags & HA_FULLTEXT) && + (table->keys_in_use_for_query & (((key_map)1) << keynr))) { - ft_to_key[fts]=key; + ft_to_key[fts]=keynr; 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; - } + goto err; while ((item=(Item_field*)(li++))) { - for (key=0 ; key<fts ; key++) + for (keynr=0 ; keynr < fts ; keynr++) { - KEY *ft_key=&table->key_info[ft_to_key[key]]; + KEY *ft_key=&table->key_info[ft_to_key[keynr]]; 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]++; + ft_cnt[keynr]++; } } } - uint max_cnt=0, mkeys=0; - for (key=0 ; key<fts ; key++) + for (keynr=0 ; keynr < fts ; keynr++) { - if (ft_cnt[key] > max_cnt) + if (ft_cnt[keynr] > max_cnt) { mkeys=0; - max_cnt=ft_cnt[mkeys]=ft_cnt[key]; - ft_to_key[mkeys]=ft_to_key[key]; + max_cnt=ft_cnt[mkeys]=ft_cnt[keynr]; + ft_to_key[mkeys]=ft_to_key[keynr]; continue; } - if (max_cnt && ft_cnt[key] == max_cnt) + if (max_cnt && ft_cnt[keynr] == max_cnt) { mkeys++; - ft_cnt[mkeys]=ft_cnt[key]; - ft_to_key[mkeys]=ft_to_key[key]; + ft_cnt[mkeys]=ft_cnt[keynr]; + ft_to_key[mkeys]=ft_to_key[keynr]; continue; } } - for (key=0 ; key<=mkeys ; key++) + for (keynr=0 ; keynr <= mkeys ; keynr++) { // for now, partial keys won't work. SerG if (max_cnt < fields.elements || - max_cnt < table->key_info[ft_to_key[key]].key_parts) + max_cnt < table->key_info[ft_to_key[keynr]].key_parts) continue; - this->key=ft_to_key[key]; + key=ft_to_key[keynr]; return 0; } +err: + if (mode == FT_BOOL) + { + key=NO_SUCH_KEY; + 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; @@ -2171,19 +2302,109 @@ bool Item_func_match::eq(const Item *item, bool binary_cmp) const } +double Item_func_match::val() +{ + DBUG_ENTER("Item_func_match::val"); + if (ft_handler == NULL) + DBUG_RETURN(-1.0); + + if (table->null_row) /* NULL row from an outer join */ + return 0.0; + + if (join_key) + { + if (table->file->ft_handler) + DBUG_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))) + DBUG_RETURN(0); + DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, + (byte *)a->ptr(), a->length())); + } + else + DBUG_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(name.str,"IDENTITY")) - return new Item_int((char*) "@@IDENTITY", - current_thd->insert_id(),21); if (!my_strcasecmp(name.str,"VERSION")) return new Item_string("@@VERSION",server_version, (uint) strlen(server_version)); - net_printf(¤t_thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); + + THD *thd=current_thd; + Item *item; + sys_var *var; + char buff[MAX_SYS_VAR_LENGTH+3+8], *pos; + + if (!(var= find_sys_var(name.str))) + return 0; + if (!(item=var->item(thd, var_type))) + return 0; // Impossible + thd->safe_to_cache_query=0; + buff[0]='@'; + buff[1]='@'; + pos=buff+2; + if (var_type == OPT_SESSION) + pos=strmov(pos,"session."); + else if (var_type == OPT_GLOBAL) + pos=strmov(pos,"global."); + memcpy(pos, var->name, var->name_length+1); + // set_name() will allocate the name + item->set_name(buff,(uint) (pos-buff)+var->name_length); + 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; } |