diff options
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r-- | sql/item_strfunc.cc | 941 |
1 files changed, 694 insertions, 247 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 31c2dc943e5..fd1222d5f1a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -33,15 +33,26 @@ #include "md5.h" #include "sha1.h" #include "my_aes.h" +C_MODE_START +#include "../mysys/my_static.h" // For soundex_map +C_MODE_END -String empty_string(""); +String my_empty_string("",default_charset_info); + +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) +{ + my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + fname); +} uint nr_of_decimals(const char *str) { if ((str=strchr(str,'.'))) { const char *start= ++str; - for (; isdigit(*str) ; str++) ; + for (; my_isdigit(system_charset_info,*str) ; str++) ; return (uint) (str-start); } return 0; @@ -49,16 +60,19 @@ uint nr_of_decimals(const char *str) double Item_str_func::val() { + int err; String *res; res=val_str(&str_value); - return res ? atof(res->c_ptr()) : 0.0; + return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), + NULL, &err) : 0.0; } longlong Item_str_func::val_int() { + int err; String *res; res=val_str(&str_value); - return res ? strtoll(res->c_ptr(),NULL,10) : (longlong) 0; + return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,NULL,&err) : (longlong) 0; } @@ -121,12 +135,12 @@ String *Item_func_sha::val_str(String *str) digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19]); - + str->length((uint) SHA1_HASH_SIZE*2); null_value=0; return str; } - } + } null_value=1; return 0; } @@ -142,7 +156,7 @@ void Item_func_sha::fix_length_and_dec() String *Item_func_aes_encrypt::val_str(String *str) { char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff)); + String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); String *sptr= args[0]->val_str(str); // String to encrypt String *key= args[1]->val_str(&tmp_key_value); // key int aes_length; @@ -150,13 +164,13 @@ String *Item_func_aes_encrypt::val_str(String *str) { null_value=0; aes_length=my_aes_get_size(sptr->length()); // Calculate result length - + if (!str_value.alloc(aes_length)) // Ensure that memory is free { // finally encrypt directly to allocated buffer. if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(), key->ptr(), key->length()) == aes_length) - { + { // We got the expected result length str_value.length((uint) aes_length); return &str_value; @@ -177,7 +191,8 @@ void Item_func_aes_encrypt::fix_length_and_dec() String *Item_func_aes_decrypt::val_str(String *str) { char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff)), *sptr, *key; + String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); + String *sptr, *key; DBUG_ENTER("Item_func_aes_decrypt::val_str"); sptr= args[0]->val_str(str); // String to decrypt @@ -193,7 +208,7 @@ String *Item_func_aes_decrypt::val_str(String *str) (char*) str_value.ptr(), key->ptr(), key->length()); if (length >= 0) // if we got correct data data - { + { str_value.length((uint) length); DBUG_RETURN(&str_value); } @@ -298,6 +313,7 @@ String *Item_func_concat::val_str(String *str) } } } + res->set_charset(collation.collation); return res; null: @@ -309,8 +325,13 @@ null: void Item_func_concat::fix_length_and_dec() { max_length=0; + + if (agg_arg_collations(collation, args, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) max_length+=args[i]->max_length; + if (max_length > MAX_BLOB_WIDTH) { max_length=MAX_BLOB_WIDTH; @@ -318,7 +339,7 @@ void Item_func_concat::fix_length_and_dec() } } -/* +/* Function des_encrypt() by tonu@spam.ee & monty Works only if compiled with OpenSSL library support. This returns a binary string where first character is CHAR(128 | key-number). @@ -340,7 +361,7 @@ String *Item_func_des_encrypt::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if ((res_length=res->length()) == 0) - return &empty_string; + return &my_empty_string; if (arg_count == 1) { @@ -375,10 +396,10 @@ String *Item_func_des_encrypt::val_str(String *str) DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } - /* + /* The problem: DES algorithm requires original data to be in 8-bytes - chunks. Missing bytes get filled with '*'s and result of encryption - can be up to 8 bytes longer than original string. When decrypted, + chunks. Missing bytes get filled with '*'s and result of encryption + can be up to 8 bytes longer than original string. When decrypted, we do not know the size of original string :( We add one byte with value 0x1..0x8 as the last byte of the padded string marking change of string length. @@ -449,7 +470,7 @@ String *Item_func_des_decrypt::val_str(String *str) // Here we set all 64-bit keys (56 effective) one by one DES_set_key_unchecked(&keyblock.key1,&keyschedule.ks1); DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); - DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); + DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } if (tmp_value.alloc(length-1)) goto error; @@ -475,7 +496,7 @@ error: } -/* +/* concat with separator. First arg is the separator concat_ws takes at least two arguments. */ @@ -483,7 +504,7 @@ error: String *Item_func_concat_ws::val_str(String *str) { char tmp_str_buff[10]; - String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff)), + String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info), *sep_str, *res, *res2,*use_as_buff; uint i; @@ -501,7 +522,7 @@ String *Item_func_concat_ws::val_str(String *str) if ((res= args[i]->val_str(str))) break; if (i == arg_count) - return &empty_string; + return &my_empty_string; for (i++; i < arg_count ; i++) { @@ -577,6 +598,7 @@ String *Item_func_concat_ws::val_str(String *str) use_as_buff=str; } } + res->set_charset(collation.collation); return res; null: @@ -584,23 +606,35 @@ null: return 0; } -void Item_func_concat_ws::split_sum_func(List<Item> &fields) +void Item_func_concat_ws::split_sum_func(Item **ref_pointer_array, + List<Item> &fields) { if (separator->with_sum_func && separator->type() != SUM_FUNC_ITEM) - separator->split_sum_func(fields); + separator->split_sum_func(ref_pointer_array, fields); else if (separator->used_tables() || separator->type() == SUM_FUNC_ITEM) { + uint el= fields.elements; fields.push_front(separator); - separator= new Item_ref((Item**) fields.head_ref(), 0, separator->name); - } - Item_str_func::split_sum_func(fields); + ref_pointer_array[el]= separator; + separator= new Item_ref(ref_pointer_array + el, + &separator, 0, separator->name); + } + Item_str_func::split_sum_func(ref_pointer_array, fields); } void Item_func_concat_ws::fix_length_and_dec() { + collation.set(separator->collation); max_length=separator->max_length*(arg_count-1); for (uint i=0 ; i < arg_count ; i++) + { max_length+=args[i]->max_length; + if (collation.aggregate(args[i]->collation)) + { + my_coll_agg_error(collation, args[i]->collation, func_name()); + break; + } + } if (max_length > MAX_BLOB_WIDTH) { max_length=MAX_BLOB_WIDTH; @@ -620,6 +654,17 @@ void Item_func_concat_ws::update_used_tables() const_item_cache&=separator->const_item(); } +void Item_func_concat_ws::print(String *str) +{ + str->append("concat_ws(", 10); + separator->print(str); + if (arg_count) + { + str->append(','); + print_args(str, 0); + } + str->append(')'); +} String *Item_func_reverse::val_str(String *str) { @@ -630,12 +675,12 @@ String *Item_func_reverse::val_str(String *str) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return &empty_string; + return &my_empty_string; res=copy_if_not_alloced(str,res,res->length()); ptr = (char *) res->ptr(); end=ptr+res->length(); #ifdef USE_MB - if (use_mb(default_charset_info) && !binary) + if (use_mb(res->charset())) { String tmpstr; tmpstr.copy(*res); @@ -643,7 +688,7 @@ String *Item_func_reverse::val_str(String *str) register uint32 l; while (ptr < end) { - if ((l=my_ismbchar(default_charset_info, ptr,end))) + if ((l=my_ismbchar(res->charset(), ptr,end))) tmp-=l, memcpy(tmp,ptr,l), ptr+=l; else *--tmp=*ptr++; @@ -667,6 +712,7 @@ String *Item_func_reverse::val_str(String *str) void Item_func_reverse::fix_length_and_dec() { + collation.set(args[0]->collation); max_length = args[0]->max_length; } @@ -686,8 +732,7 @@ String *Item_func_replace::val_str(String *str) #ifdef USE_MB const char *ptr,*end,*strend,*search,*search_end; register uint32 l; - bool binary_str = (args[0]->binary || args[1]->binary || - !use_mb(default_charset_info)); + bool binary_cmp; #endif null_value=0; @@ -698,6 +743,12 @@ String *Item_func_replace::val_str(String *str) if (args[1]->null_value) goto null; + res->set_charset(collation.collation); + +#ifdef USE_MB + binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !use_mb(res->charset())); +#endif + if (res2->length() == 0) return res; #ifndef USE_MB @@ -705,7 +756,7 @@ String *Item_func_replace::val_str(String *str) return res; #else offset=0; - if (binary_str && (offset=res->strstr(*res2)) < 0) + if (binary_cmp && (offset=res->strstr(*res2)) < 0) return res; #endif if (!(res3=args[2]->val_str(&tmp_value2))) @@ -714,7 +765,7 @@ String *Item_func_replace::val_str(String *str) to_length= res3->length(); #ifdef USE_MB - if (!binary_str) + if (!binary_cmp) { search=res2->ptr(); search_end=search+from_length; @@ -729,7 +780,7 @@ redo: register char *i,*j; i=(char*) ptr+1; j=(char*) search+1; while (j != search_end) - if (*i++ != *j++) goto skipp; + if (*i++ != *j++) goto skip; offset= (int) (ptr-res->ptr()); if (res->length()-from_length + to_length > current_thd->variables.max_allowed_packet) @@ -743,8 +794,8 @@ redo: offset+=(int) to_length; goto redo; } -skipp: - if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l; +skip: + if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l; else ++ptr; } } @@ -779,13 +830,16 @@ void Item_func_replace::fix_length_and_dec() if (diff > 0 && args[1]->max_length) { // Calculate of maxreplaces uint max_substrs= max_length/args[1]->max_length; - max_length+= max_substrs * (uint)diff; + max_length+= max_substrs * (uint) diff; } if (max_length > MAX_BLOB_WIDTH) { max_length=MAX_BLOB_WIDTH; maybe_null=1; } + + if (agg_arg_collations_for_comparison(collation, args, 3)) + return; } @@ -802,13 +856,8 @@ String *Item_func_insert::val_str(String *str) if (args[0]->null_value || args[1]->null_value || args[2]->null_value || args[3]->null_value) goto null; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(default_charset_info) && !args[0]->binary) - { - start=res->charpos(start); - length=res->charpos(length,start); - } -#endif + start=res->charpos(start); + length=res->charpos(length,start); if (start > res->length()+1) return res; // Wrong param; skip insert if (length > res->length()-start) @@ -827,6 +876,11 @@ null: void Item_func_insert::fix_length_and_dec() { + if (collation.set(args[0]->collation, args[3]->collation)) + { + my_coll_agg_error(args[0]->collation, args[3]->collation, func_name()); + return; + } max_length=args[0]->max_length+args[3]->max_length; if (max_length > MAX_BLOB_WIDTH) { @@ -874,11 +928,8 @@ String *Item_func_left::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (length <= 0) - return &empty_string; -#ifdef USE_MB - if (use_mb(default_charset_info) && !binary) - length = res->charpos(length); -#endif + return &my_empty_string; + length= res->charpos(length); if (res->length() > (ulong) length) { // Safe even if const arg if (!res->alloced_length()) @@ -897,7 +948,7 @@ void Item_str_func::left_right_max_length() max_length=args[0]->max_length; if (args[1]->const_item()) { - int length=(int) args[1]->val_int()*default_charset_info->mbmaxlen; + int length=(int) args[1]->val_int()*collation.collation->mbmaxlen; if (length <= 0) max_length=0; else @@ -908,6 +959,7 @@ void Item_str_func::left_right_max_length() void Item_func_left::fix_length_and_dec() { + collation.set(args[0]->collation); left_right_max_length(); } @@ -920,28 +972,22 @@ String *Item_func_right::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ if (length <= 0) - return &empty_string; /* purecov: inspected */ + return &my_empty_string; /* purecov: inspected */ if (res->length() <= (uint) length) return res; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(default_charset_info) && !binary) - { - uint start=res->numchars()-(uint) length; - if (start<=0) return res; - start=res->charpos(start); - tmp_value.set(*res,start,res->length()-start); - } - else -#endif - { - tmp_value.set(*res,(res->length()- (uint) length),(uint) length); - } + + uint start=res->numchars(); + if (start <= (uint) length) + return res; + start=res->charpos(start - (uint) length); + tmp_value.set(*res,start,res->length()-start); return &tmp_value; } void Item_func_right::fix_length_and_dec() { + collation.set(args[0]->collation); left_right_max_length(); } @@ -949,22 +995,18 @@ void Item_func_right::fix_length_and_dec() String *Item_func_substr::val_str(String *str) { String *res = args[0]->val_str(str); - int32 start = (int32) args[1]->val_int()-1; + int32 start = (int32) args[1]->val_int(); int32 length = arg_count == 3 ? (int32) args[2]->val_int() : INT_MAX32; int32 tmp_length; if ((null_value=(args[0]->null_value || args[1]->null_value || (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ -#ifdef USE_MB - if (use_mb(default_charset_info) && !binary) - { - start=res->charpos(start); - length=res->charpos(length,start); - } -#endif + start= (int32)((start < 0) ? res->length() + start : start -1); + start=res->charpos(start); + length=res->charpos(length,start); if (start < 0 || (uint) start+1 > res->length() || length <= 0) - return &empty_string; + return &my_empty_string; tmp_length=(int32) res->length()-start; length=min(length,tmp_length); @@ -980,6 +1022,7 @@ void Item_func_substr::fix_length_and_dec() { max_length=args[0]->max_length; + collation.set(args[0]->collation); if (args[1]->const_item()) { int32 start=(int32) args[1]->val_int()-1; @@ -999,6 +1042,15 @@ void Item_func_substr::fix_length_and_dec() } +void Item_func_substr_index::fix_length_and_dec() +{ + max_length= args[0]->max_length; + + if (agg_arg_collations_for_comparison(collation, args, 2)) + return; +} + + String *Item_func_substr_index::val_str(String *str) { String *res =args[0]->val_str(str); @@ -1014,10 +1066,12 @@ String *Item_func_substr_index::val_str(String *str) null_value=0; uint delimeter_length=delimeter->length(); if (!res->length() || !delimeter_length || !count) - return &empty_string; // Wrong parameters + return &my_empty_string; // Wrong parameters + + res->set_charset(collation.collation); #ifdef USE_MB - if (use_mb(default_charset_info) && !binary) + if (use_mb(res->charset())) { const char *ptr=res->ptr(); const char *strend = ptr+res->length(); @@ -1035,14 +1089,14 @@ String *Item_func_substr_index::val_str(String *str) register char *i,*j; i=(char*) ptr+1; j=(char*) search+1; while (j != search_end) - if (*i++ != *j++) goto skipp; + if (*i++ != *j++) goto skip; if (pass==0) ++n; else if (!--c) break; ptr+=delimeter_length; continue; } - skipp: - if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l; + skip: + if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l; else ++ptr; } /* either not found or got total number when count<0 */ if (pass == 0) /* count<0 */ @@ -1114,8 +1168,8 @@ String *Item_func_ltrim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); - String *remove_str=args[1]->val_str(&tmp); + String tmp(buff,sizeof(buff),res->charset()); + String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove; uint remove_length; LINT_INIT(remove_length); @@ -1152,8 +1206,8 @@ String *Item_func_rtrim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); - String *remove_str=args[1]->val_str(&tmp); + String tmp(buff,sizeof(buff),res->charset()); + String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove; uint remove_length; LINT_INIT(remove_length); @@ -1171,11 +1225,11 @@ String *Item_func_rtrim::val_str(String *str) { char chr=(*remove_str)[0]; #ifdef USE_MB - if (use_mb(default_charset_info) && !binary) + if (use_mb(res->charset())) { while (ptr < end) { - if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l,p=ptr; + if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l,p=ptr; else ++ptr; } ptr=p; @@ -1188,12 +1242,12 @@ String *Item_func_rtrim::val_str(String *str) { const char *r_ptr=remove_str->ptr(); #ifdef USE_MB - if (use_mb(default_charset_info) && !binary) + if (use_mb(res->charset())) { loop: while (ptr + remove_length < end) { - if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l; + if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l; else ++ptr; } if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length)) @@ -1224,8 +1278,8 @@ String *Item_func_trim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); - String *remove_str=args[1]->val_str(&tmp); + String tmp(buff,sizeof(buff),res->charset()); + String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove; uint remove_length; LINT_INIT(remove_length); @@ -1239,14 +1293,14 @@ String *Item_func_trim::val_str(String *str) while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length)) ptr+=remove_length; #ifdef USE_MB - if (use_mb(default_charset_info) && !binary) + if (use_mb(res->charset())) { char *p=ptr; register uint32 l; loop: while (ptr + remove_length < end) { - if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l; + if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l; else ++ptr; } if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length)) @@ -1270,19 +1324,69 @@ String *Item_func_trim::val_str(String *str) return &tmp_value; } +void Item_func_trim::fix_length_and_dec() +{ + max_length= args[0]->max_length; + if (arg_count == 1) + { + collation.set(args[0]->collation); + remove.set_charset(collation.collation); + remove.set_ascii(" ",1); + } + else + if (collation.set(args[1]->collation, args[0]->collation) || + collation.derivation == DERIVATION_NONE) + { + my_coll_agg_error(args[1]->collation, args[0]->collation, func_name()); + } +} + + +/* Item_func_password */ String *Item_func_password::val_str(String *str) { - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(str); + if ((null_value=args[0]->null_value)) + return 0; + if (res->length() == 0) + return &my_empty_string; + make_scrambled_password(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset()); + return str; +} + +char *Item_func_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, password); + return buff; +} + +/* Item_func_old_password */ + +String *Item_func_old_password::val_str(String *str) +{ + String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr()); - str->set(tmp_value,16); + return &my_empty_string; + make_scrambled_password_323(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset()); return str; } +char *Item_func_old_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, password); + return buff; +} + + #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') String *Item_func_encrypt::val_str(String *str) @@ -1294,7 +1398,7 @@ String *Item_func_encrypt::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &empty_string; + return &my_empty_string; if (arg_count == 1) { // generate random salt @@ -1313,7 +1417,7 @@ String *Item_func_encrypt::val_str(String *str) } pthread_mutex_lock(&LOCK_crypt); char *tmp=crypt(res->c_ptr(),salt_ptr); - str->set(tmp,(uint) strlen(tmp)); + str->set(tmp,(uint) strlen(tmp),res->charset()); str->copy(); pthread_mutex_unlock(&LOCK_crypt); return str; @@ -1362,45 +1466,60 @@ String *Item_func_decode::val_str(String *str) String *Item_func_database::val_str(String *str) { - if (!current_thd->db) - str->length(0); + THD *thd= current_thd; + if (!thd->db) + { + null_value= 1; + return 0; + } else - str->set((const char*) current_thd->db,(uint) strlen(current_thd->db)); + str->copy((const char*) thd->db,(uint) strlen(thd->db),system_charset_info); return str; } +// TODO: make USER() replicate properly (currently it is replicated to "") + String *Item_func_user::val_str(String *str) { - // TODO: make USER() replicate properly (currently it is replicated to "") - THD *thd=current_thd; - if (!(thd->user) || // for system threads (e.g. replication SQL thread) - str->copy((const char*) thd->user,(uint) strlen(thd->user)) || - str->append('@') || - str->append(thd->host ? thd->host : thd->ip ? thd->ip : "")) - return &empty_string; + THD *thd=current_thd; + CHARSET_INFO *cs= system_charset_info; + const char *host= thd->host_or_ip; + uint res_length; + + // For system threads (e.g. replication SQL thread) user may be empty + if (!thd->user) + return &my_empty_string; + res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen; + + if (str->alloc(res_length)) + { + null_value=1; + return 0; + } + res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s", + thd->user, host); + str->length(res_length); + str->set_charset(cs); return str; } void Item_func_soundex::fix_length_and_dec() { + collation.set(args[0]->collation); max_length=args[0]->max_length; set_if_bigger(max_length,4); } - /* - If alpha, map input letter to soundex code. - If not alpha and remove_garbage is set then skip to next char - else return 0 - */ - -extern "C" { -extern const char *soundex_map; // In mysys/static.c -} +/* + If alpha, map input letter to soundex code. + If not alpha and remove_garbage is set then skip to next char + else return 0 +*/ -static char get_scode(char *ptr) +static char get_scode(CHARSET_INFO *cs,char *ptr) { - uchar ch=toupper(*ptr); + uchar ch=my_toupper(cs,*ptr); if (ch < 'A' || ch > 'Z') { // Thread extended alfa (country spec) @@ -1414,6 +1533,8 @@ String *Item_func_soundex::val_str(String *str) { String *res =args[0]->val_str(str); char last_ch,ch; + CHARSET_INFO *cs= collation.collation; + if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ @@ -1421,22 +1542,23 @@ String *Item_func_soundex::val_str(String *str) return str; /* purecov: inspected */ char *to= (char *) tmp_value.ptr(); char *from= (char *) res->ptr(), *end=from+res->length(); - - while (from != end && isspace(*from)) // Skip pre-space + tmp_value.set_charset(cs); + + while (from != end && my_isspace(cs,*from)) // Skip pre-space from++; /* purecov: inspected */ if (from == end) - return &empty_string; // No alpha characters. - *to++ = toupper(*from); // Copy first letter - last_ch = get_scode(from); // code of the first letter + return &my_empty_string; // No alpha characters. + *to++ = my_toupper(cs,*from); // Copy first letter + last_ch = get_scode(cs,from); // code of the first letter // for the first 'double-letter check. // Loop on input letters until // end of input (null) or output // letter code count = 3 for (from++ ; from < end ; from++) { - if (!isalpha(*from)) + if (!my_isalpha(cs,*from)) continue; - ch=get_scode(from); + ch=get_scode(cs,from); if ((ch != '0') && (ch != last_ch)) // if not skipped or double { *to++ = ch; // letter, copy to output @@ -1462,6 +1584,11 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org) } +/* + TODO: This needs to be fixed for multi-byte character set where numbers + are stored in more than one byte +*/ + String *Item_func_format::val_str(String *str) { double nr =args[0]->val(); @@ -1470,7 +1597,8 @@ String *Item_func_format::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ dec= decimals ? decimals+1 : 0; - str->set(nr,decimals); + /* Here default_charset() is right as this is not an automatic conversion */ + str->set(nr,decimals, default_charset()); #ifdef HAVE_ISNAN if (isnan(nr)) return str; @@ -1503,46 +1631,33 @@ String *Item_func_format::val_str(String *str) } +void Item_func_format::print(String *str) +{ + str->append("format(", 7); + args[0]->print(str); + str->append(','); + // my_charset_bin is good enough for numbers + char buffer[20]; + String st(buffer, sizeof(buffer), &my_charset_bin); + st.set((ulonglong)decimals, &my_charset_bin); + str->append(st); + str->append(')'); +} + void Item_func_elt::fix_length_and_dec() { max_length=0; decimals=0; -#if MYSQL_VERSION_ID < 40100 - for (uint i= 0; i < arg_count ; i++) -#else - for (uint i= 1; i < arg_count ; i++) -#endif + + if (agg_arg_collations(collation, args+1, arg_count-1)) + return; + + for (uint i= 1 ; i < arg_count ; i++) { set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); } maybe_null=1; // NULL if wrong first arg - 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(); -} - - -void Item_func_elt::split_sum_func(List<Item> &fields) -{ - 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); - item= new Item_ref((Item**) fields.head_ref(), 0, item->name); - } - Item_str_func::split_sum_func(fields); -} - - -void Item_func_elt::update_used_tables() -{ - Item_func::update_used_tables(); - item->update_used_tables(); - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); } @@ -1550,11 +1665,10 @@ double Item_func_elt::val() { uint tmp; null_value=1; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) return 0.0; - - double result= args[tmp-1]->val(); - null_value= args[tmp-1]->null_value; + double result= args[tmp]->val(); + null_value= args[tmp]->null_value; return result; } @@ -1563,11 +1677,11 @@ longlong Item_func_elt::val_int() { uint tmp; null_value=1; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) return 0; - - longlong result= args[tmp-1]->val_int(); - null_value= args[tmp-1]->null_value; + + longlong result= args[tmp]->val_int(); + null_value= args[tmp]->null_value; return result; } @@ -1576,33 +1690,43 @@ String *Item_func_elt::val_str(String *str) { uint tmp; null_value=1; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) return NULL; - String *result= args[tmp-1]->val_str(str); - null_value= args[tmp-1]->null_value; + String *result= args[tmp]->val_str(str); + if (result) + result->set_charset(collation.collation); + null_value= args[tmp]->null_value; return result; } -void Item_func_make_set::split_sum_func(List<Item> &fields) +void Item_func_make_set::split_sum_func(Item **ref_pointer_array, + List<Item> &fields) { if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(fields); + item->split_sum_func(ref_pointer_array, fields); else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) { + uint el= fields.elements; fields.push_front(item); - item= new Item_ref((Item**) fields.head_ref(), 0, item->name); - } - Item_str_func::split_sum_func(fields); + ref_pointer_array[el]= item; + item= new Item_ref(ref_pointer_array + el, &item, 0, item->name); + } + Item_str_func::split_sum_func(ref_pointer_array, fields); } void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - for (uint i=1 ; i < arg_count ; i++) + + if (agg_arg_collations(collation, args, arg_count)) + return; + + for (uint i=0 ; i < arg_count ; i++) max_length+=args[i]->max_length; + used_tables_cache|= item->used_tables(); not_null_tables_cache&= item->not_null_tables(); const_item_cache&= item->const_item(); @@ -1624,7 +1748,7 @@ String *Item_func_make_set::val_str(String *str) ulonglong bits; bool first_found=0; Item **ptr=args; - String *result=&empty_string; + String *result=&my_empty_string; bits=item->val_int(); if ((null_value=item->null_value)) @@ -1648,7 +1772,7 @@ String *Item_func_make_set::val_str(String *str) else { if (tmp_str.copy(*res)) // Don't use 'str' - return &empty_string; + return &my_empty_string; result= &tmp_str; } } @@ -1658,11 +1782,11 @@ String *Item_func_make_set::val_str(String *str) { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return &empty_string; + return &my_empty_string; result= &tmp_str; } if (tmp_str.append(',') || tmp_str.append(*res)) - return &empty_string; + return &my_empty_string; } } } @@ -1671,6 +1795,19 @@ String *Item_func_make_set::val_str(String *str) } +void Item_func_make_set::print(String *str) +{ + str->append("make_set(", 9); + item->print(str); + if (arg_count) + { + str->append(','); + print_args(str, 0); + } + str->append(')'); +} + + String *Item_func_char::val_str(String *str) { str->length(0); @@ -1679,7 +1816,7 @@ String *Item_func_char::val_str(String *str) int32 num=(int32) args[i]->val_int(); if (!args[i]->null_value) #ifdef USE_MB - if (use_mb(default_charset_info)) + if (use_mb(collation.collation)) { if (num&0xFF000000L) { str->append((char)(num>>24)); @@ -1687,7 +1824,7 @@ String *Item_func_char::val_str(String *str) } else if (num&0xFF0000L) { b2: str->append((char)(num>>16)); goto b1; - } else if (num&0xFF00L) { + } else if (num&0xFF00L) { b1: str->append((char)(num>>8)); } } @@ -1723,6 +1860,7 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value, void Item_func_repeat::fix_length_and_dec() { + collation.set(args[0]->collation); if (args[1]->const_item()) { max_length=(long) (args[0]->max_length * args[1]->val_int()); @@ -1755,7 +1893,7 @@ String *Item_func_repeat::val_str(String *str) goto err; // string and/or delim are null null_value=0; if (count <= 0) // For nicer SQL code - return &empty_string; + return &my_empty_string; if (count == 1) // To avoid reallocs return res; length=res->length(); @@ -1782,9 +1920,15 @@ err: void Item_func_rpad::fix_length_and_dec() { + if (collation.set(args[0]->collation, args[2]->collation)) + { + my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + return; + } + if (args[1]->const_item()) { - uint32 length= (uint32) args[1]->val_int(); + uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen; max_length=max(args[0]->max_length,length); if (max_length >= MAX_BLOB_WIDTH) { @@ -1802,36 +1946,46 @@ void Item_func_rpad::fix_length_and_dec() String *Item_func_rpad::val_str(String *str) { - uint32 res_length,length_pad; + uint32 res_byte_length,res_char_length,pad_char_length,pad_byte_length; char *to; const char *ptr_pad; int32 count= (int32) args[1]->val_int(); + int32 byte_count= count * collation.collation->mbmaxlen; String *res =args[0]->val_str(str); String *rpad = args[2]->val_str(&rpad_str); if (!res || args[1]->null_value || !rpad || count < 0) goto err; null_value=0; - if (count <= (int32) (res_length=res->length())) + if (count <= (int32) (res_char_length=res->numchars())) { // String to pad is big enough - res->length(count); // Shorten result if longer + res->length(res->charpos(count)); // Shorten result if longer return (res); } - length_pad= rpad->length(); - if ((ulong) count > current_thd->variables.max_allowed_packet || - args[2]->null_value || !length_pad) + pad_char_length= rpad->numchars(); + if ((ulong) byte_count > current_thd->variables.max_allowed_packet || + args[2]->null_value || !pad_char_length) goto err; - if (!(res= alloc_buffer(res,str,&tmp_value,count))) + res_byte_length= res->length(); /* Must be done before alloc_buffer */ + if (!(res= alloc_buffer(res,str,&tmp_value,byte_count))) goto err; - to= (char*) res->ptr()+res_length; + to= (char*) res->ptr()+res_byte_length; ptr_pad=rpad->ptr(); - for (count-= res_length; (uint32) count > length_pad; count-= length_pad) + pad_byte_length= rpad->length(); + count-= res_char_length; + for ( ; (uint32) count > pad_char_length; count-= pad_char_length) { - memcpy(to,ptr_pad,length_pad); - to+= length_pad; + memcpy(to,ptr_pad,pad_byte_length); + to+= pad_byte_length; } - memcpy(to,ptr_pad,(size_t) count); + if (count) + { + pad_byte_length= rpad->charpos(count); + memcpy(to,ptr_pad,(size_t) pad_byte_length); + to+= pad_byte_length; + } + res->length(to- (char*) res->ptr()); return (res); err: @@ -1842,9 +1996,15 @@ String *Item_func_rpad::val_str(String *str) void Item_func_lpad::fix_length_and_dec() { + if (collation.set(args[0]->collation, args[2]->collation)) + { + my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + return; + } + if (args[1]->const_item()) { - uint32 length= (uint32) args[1]->val_int(); + uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen; max_length=max(args[0]->max_length,length); if (max_length >= MAX_BLOB_WIDTH) { @@ -1862,57 +2022,49 @@ void Item_func_lpad::fix_length_and_dec() String *Item_func_lpad::val_str(String *str) { - uint32 res_length,length_pad; - char *to; - const char *ptr_pad; - ulong count= (long) args[1]->val_int(); - String *res= args[0]->val_str(str); - String *lpad= args[2]->val_str(&lpad_str); + uint32 res_char_length,pad_char_length; + ulong count= (long) args[1]->val_int(), byte_count; + String *res= args[0]->val_str(&tmp_value); + String *pad= args[2]->val_str(&lpad_str); - if (!res || args[1]->null_value || !lpad) + if (!res || args[1]->null_value || !pad) goto err; + null_value=0; - if (count <= (res_length=res->length())) - { // String to pad is big enough - res->length(count); // Shorten result if longer - return (res); + res_char_length= res->numchars(); + + if (count <= res_char_length) + { + res->length(res->charpos(count)); + return res; } - length_pad= lpad->length(); - if (count > current_thd->variables.max_allowed_packet || - args[2]->null_value || !length_pad) + + pad_char_length= pad->numchars(); + byte_count= count * collation.collation->mbmaxlen; + + if (byte_count > current_thd->variables.max_allowed_packet || + args[2]->null_value || !pad_char_length || str->alloc(byte_count)) goto err; - - if (res->alloced_length() < count) + + str->length(0); + str->set_charset(collation.collation); + count-= res_char_length; + while (count >= pad_char_length) { - if (str->alloced_length() >= count) - { - memcpy((char*) str->ptr()+(count-res_length),res->ptr(),res_length); - res=str; - } - else - { - if (tmp_value.alloc(count)) - goto err; - memcpy((char*) tmp_value.ptr()+(count-res_length),res->ptr(),res_length); - res=&tmp_value; - } + str->append(*pad); + count-= pad_char_length; } - else - bmove_upp((char*) res->ptr()+count,res->ptr()+res_length,res_length); - res->length(count); - - to= (char*) res->ptr(); - ptr_pad= lpad->ptr(); - for (count-= res_length; count > length_pad; count-= length_pad) + if (count > 0) { - memcpy(to,ptr_pad,length_pad); - to+= length_pad; + pad->length(pad->charpos(count)); + str->append(*pad); } - memcpy(to,ptr_pad,(size_t) count); - return (res); + str->append(*res); + null_value= 0; + return str; - err: - null_value=1; +err: + null_value= 1; return 0; } @@ -1924,6 +2076,7 @@ String *Item_func_conv::val_str(String *str) longlong dec; int from_base= (int) args[1]->val_int(); int to_base= (int) args[2]->val_int(); + int err; if (args[0]->null_value || args[1]->null_value || args[2]->null_value || abs(to_base) > 36 || abs(to_base) < 2 || @@ -1934,12 +2087,157 @@ String *Item_func_conv::val_str(String *str) } null_value=0; if (from_base < 0) - dec= strtoll(res->c_ptr(),&endptr,-from_base); + dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err); else - dec= (longlong) strtoull(res->c_ptr(),&endptr,from_base); + dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),from_base,&endptr,&err); ptr= longlong2str(dec,ans,to_base); - if (str->copy(ans,(uint32) (ptr-ans))) - return &empty_string; + if (str->copy(ans,(uint32) (ptr-ans), default_charset())) + return &my_empty_string; + return str; +} + + +String *Item_func_conv_charset::val_str(String *str) +{ + String *arg= args[0]->val_str(str); + if (!arg) + { + null_value=1; + return 0; + } + null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(),conv_charset); + return null_value ? 0 : &str_value; +} + +void Item_func_conv_charset::fix_length_and_dec() +{ + collation.set(conv_charset, DERIVATION_IMPLICIT); + max_length = args[0]->max_length*conv_charset->mbmaxlen; +} + +void Item_func_conv_charset::print(String *str) +{ + str->append("convert(", 8); + args[0]->print(str); + str->append(" using ", 7); + str->append(conv_charset->csname); + str->append(')'); +} + +String *Item_func_conv_charset3::val_str(String *str) +{ + char cs1[30], cs2[30]; + String to_cs_buff(cs1, sizeof(cs1), default_charset_info); + String from_cs_buff(cs2, sizeof(cs2), default_charset_info); + String *arg= args[0]->val_str(str); + String *to_cs= args[1]->val_str(&to_cs_buff); + String *from_cs= args[2]->val_str(&from_cs_buff); + CHARSET_INFO *from_charset; + CHARSET_INFO *to_charset; + + if (!arg || args[0]->null_value || + !to_cs || args[1]->null_value || + !from_cs || args[2]->null_value || + !(from_charset=get_charset_by_name(from_cs->ptr(), MYF(MY_WME))) || + !(to_charset=get_charset_by_name(to_cs->ptr(), MYF(MY_WME)))) + { + null_value= 1; + return 0; + } + + if (str_value.copy(arg->ptr(), arg->length(), from_charset, to_charset)) + { + null_value= 1; + return 0; + } + null_value= 0; + return &str_value; +} + + +void Item_func_conv_charset3::fix_length_and_dec() +{ + max_length = args[0]->max_length; +} + +String *Item_func_set_collation::val_str(String *str) +{ + str=args[0]->val_str(str); + if ((null_value=args[0]->null_value)) + return 0; + str->set_charset(collation.collation); + return str; +} + +void Item_func_set_collation::fix_length_and_dec() +{ + CHARSET_INFO *set_collation; + const char *colname; + String tmp, *str= args[1]->val_str(&tmp); + colname= str->c_ptr(); + if (colname == binary_keyword) + set_collation= get_charset_by_csname(args[0]->collation.collation->csname, + MY_CS_BINSORT,MYF(0)); + else + { + if (!(set_collation= get_charset_by_name(colname,MYF(0)))) + { + my_error(ER_UNKNOWN_COLLATION, MYF(0), colname); + return; + } + } + + if (!set_collation || + !my_charset_same(args[0]->collation.collation,set_collation)) + { + my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), + colname,args[0]->collation.collation->csname); + return; + } + collation.set(set_collation, DERIVATION_EXPLICIT); + max_length= args[0]->max_length; +} + + +bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) 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; + Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item; + if (collation.collation != item_func_sc->collation.collation) + return 0; + for (uint i=0; i < arg_count ; i++) + if (!args[i]->eq(item_func_sc->args[i], binary_cmp)) + return 0; + return 1; +} + +String *Item_func_charset::val_str(String *str) +{ + String *res = args[0]->val_str(str); + + if ((null_value=(args[0]->null_value || !res->charset()))) + return 0; + str->copy(res->charset()->csname,strlen(res->charset()->csname), + &my_charset_latin1, default_charset()); + return str; +} + +String *Item_func_collation::val_str(String *str) +{ + String *res = args[0]->val_str(str); + + if ((null_value=(args[0]->null_value || !res->charset()))) + return 0; + str->copy(res->charset()->name,strlen(res->charset()->name), + &my_charset_latin1, default_charset()); return str; } @@ -1954,8 +2252,8 @@ String *Item_func_hex::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; ptr= longlong2str(dec,ans,16); - if (str->copy(ans,(uint32) (ptr-ans))) - return &empty_string; // End of memory + if (str->copy(ans,(uint32) (ptr-ans),default_charset())) + return &my_empty_string; // End of memory return str; } @@ -1982,6 +2280,14 @@ String *Item_func_hex::val_str(String *str) } +void Item_func_binary::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as binary)", 11); +} + + #include <my_dir.h> // For my_stat String *Item_load_file::val_str(String *str) @@ -1992,7 +2298,9 @@ String *Item_load_file::val_str(String *str) DBUG_ENTER("load_file"); if (!(file_name= args[0]->val_str(str)) || +#ifndef NO_EMBEDDED_ACCESS_CHECKS !(current_thd->master_access & FILE_ACL) || +#endif !my_stat(file_name->c_ptr(), &stat_info, MYF(MY_WME))) goto err; if (!(stat_info.st_mode & S_IROTH)) @@ -2028,11 +2336,11 @@ err: String* Item_func_export_set::val_str(String* str) { ulonglong the_set = (ulonglong) args[0]->val_int(); - String yes_buf, *yes; + String yes_buf, *yes; yes = args[1]->val_str(&yes_buf); - String no_buf, *no; + String no_buf, *no; no = args[2]->val_str(&no_buf); - String *sep = NULL, sep_buf ; + String *sep = NULL, sep_buf ; uint num_set_values = 64; ulonglong mask = 0x1; @@ -2067,7 +2375,7 @@ String* Item_func_export_set::val_str(String* str) } break; case 3: - sep_buf.set(",", 1); + sep_buf.set(",", 1, default_charset()); sep = &sep_buf; } null_value=0; @@ -2089,6 +2397,9 @@ void Item_func_export_set::fix_length_and_dec() uint length=max(args[1]->max_length,args[2]->max_length); uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; + + if (agg_arg_collations(collation, args+1, min(4,arg_count)-1)) + return; } String* Item_func_inet_ntoa::val_str(String* str) @@ -2110,7 +2421,7 @@ String* Item_func_inet_ntoa::val_str(String* str) int4store(buf,n); /* Now we can assume little endian. */ - + num[3]='.'; for (p=buf+4 ; p-- > buf ; ) { @@ -2131,6 +2442,7 @@ String* Item_func_inet_ntoa::val_str(String* str) return str; } + /* QUOTE() function returns argument string in single quotes suitable for using in a SQL statement. @@ -2138,7 +2450,7 @@ String* Item_func_inet_ntoa::val_str(String* str) DESCRIPTION Adds a \ before all characters that needs to be escaped in a SQL string. We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when - running commands from a file in windows. + running commands from a file in windows. This function is very useful when you want to generate SQL statements @@ -2154,7 +2466,7 @@ String *Item_func_quote::val_str(String *str) /* Bit mask that has 1 for set for the position of the following characters: 0, \, ' and ^Z - */ + */ static uchar escmask[32]= { @@ -2215,9 +2527,144 @@ String *Item_func_quote::val_str(String *str) } *to= '\''; str->length(new_length); + str->set_charset(collation.collation); return str; null: null_value= 1; return 0; } + +longlong Item_func_uncompressed_length::val_int() +{ + String *res= args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + if (res->is_empty()) return 0; + + /* + res->ptr() using is safe because we have tested that string is not empty, + res->c_ptr() is not used because: + - we do not need \0 terminated string to get first 4 bytes + - c_ptr() tests simbol after string end (uninitialiozed memory) which + confuse valgrind + */ + return uint4korr(res->ptr()) & 0x3FFFFFFF; +} + +longlong Item_func_crc32::val_int() +{ + String *res=args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + return (longlong) crc32(0L, (uchar*)res->ptr(), res->length()); +} + +#ifdef HAVE_COMPRESS +#include "zlib.h" + +String *Item_func_compress::val_str(String *str) +{ + String *res= args[0]->val_str(str); + if (!res) + { + null_value= 1; + return 0; + } + if (res->is_empty()) return res; + + int err= Z_OK; + int code; + + /* + citation from zlib.h (comment for compress function): + + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. + + Proportion 120/100 founded by Sinica with help of procedure + compress(compress(compress(...))) + I.e. zlib give number 'at least'.. + */ + ulong new_size= (ulong)((res->length()*120)/100)+12; + + buffer.realloc((uint32)new_size + 4 + 1); + Byte *body= ((Byte*)buffer.ptr()) + 4; + + + // As far as we have checked res->is_empty() we can use ptr() + if ((err= compress(body, &new_size, + (const Bytef*)res->ptr(), res->length())) != Z_OK) + { + code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR; + push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); + null_value= 1; + return 0; + } + + char *tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects + int4store(tmp, res->length() & 0x3FFFFFFF); + + /* This is for the stupid char fields which trim ' ': */ + char *last_char= ((char*)body)+new_size-1; + if (*last_char == ' ') + { + *++last_char= '.'; + new_size++; + } + + buffer.length((uint32)new_size + 4); + return &buffer; +} + + +String *Item_func_uncompress::val_str(String *str) +{ + String *res= args[0]->val_str(str); + ulong new_size; + int err; + uint code; + + if (!res) + goto err; + if (res->is_empty()) + return res; + + new_size= uint4korr(res->ptr()) & 0x3FFFFFFF; + if (new_size > current_thd->variables.max_allowed_packet) + { + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_TOO_BIG_FOR_UNCOMPRESS, + ER(ER_TOO_BIG_FOR_UNCOMPRESS), + current_thd->variables.max_allowed_packet); + goto err; + } + if (buffer.realloc((uint32)new_size)) + goto err; + + if ((err= uncompress((Byte*)buffer.ptr(), &new_size, + ((const Bytef*)res->ptr())+4,res->length())) == Z_OK) + { + buffer.length((uint32) new_size); + return &buffer; + } + + code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR : + ((err == Z_MEM_ERROR) ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR)); + push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); + +err: + null_value= 1; + return 0; +} +#endif |