diff options
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r-- | sql/item_strfunc.cc | 323 |
1 files changed, 218 insertions, 105 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 34f974042a5..fc9375e68a5 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -14,9 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all string functions -** Warning: Some string functions doesn't always put and end-null on a String -** (This shouldn't be needed) +/** + @file + + @brief + This file defines all string functions + + @warning + Some string functions don't always put and end-null on a String. + (This shouldn't be needed) */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -25,12 +31,10 @@ #include "mysql_priv.h" #include <m_ctype.h> -#ifdef HAVE_OPENSSL -#include <openssl/des.h> -#endif /* HAVE_OPENSSL */ #include "my_md5.h" #include "sha1.h" #include "my_aes.h" +#include <zlib.h> C_MODE_START #include "../mysys/my_static.h" // For soundex_map C_MODE_END @@ -102,11 +106,11 @@ String *Item_func_md5::val_str(String *str) if (sptr) { my_MD5_CTX context; - unsigned char digest[16]; + uchar digest[16]; null_value=0; my_MD5Init (&context); - my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); + my_MD5Update (&context,(uchar *) sptr->ptr(), sptr->length()); my_MD5Final (digest, &context); if (str->alloc(32)) // Ensure that memory is free { @@ -154,7 +158,7 @@ String *Item_func_sha::val_str(String *str) mysql_sha1_reset(&context); /* We do not have to check for error here */ /* No need to check error as the only case would be too long message */ mysql_sha1_input(&context, - (const unsigned char *) sptr->ptr(), sptr->length()); + (const uchar *) sptr->ptr(), sptr->length()); /* Ensure that memory is free and we got result */ if (!( str->alloc(SHA1_HASH_SIZE*2) || (mysql_sha1_result(&context,digest)))) @@ -269,9 +273,9 @@ void Item_func_aes_decrypt::fix_length_and_dec() } -/* +/** Concatenate args with the following premises: - If only one arg (which is ok), return value of arg + If only one arg (which is ok), return value of arg; Don't reallocate val_str() if not absolute necessary. */ @@ -364,10 +368,35 @@ String *Item_func_concat::val_str(String *str) } else { // Two big const strings - if (tmp_value.alloc(max_length) || - tmp_value.copy(*res) || - tmp_value.append(*res2)) + /* + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which + can be any. Instead of overcommitting at the first row, we grow + the allocated amount by the factor of 2. This ensures that no + more than 25% of memory will be overcommitted on average. + */ + + uint concat_len= res->length() + res2->length(); + + if (tmp_value.alloced_length() < concat_len) + { + if (tmp_value.alloced_length() == 0) + { + if (tmp_value.alloc(concat_len)) + goto null; + } + else + { + uint new_len = max(tmp_value.alloced_length() * 2, concat_len); + + if (tmp_value.realloc(new_len)) + goto null; + } + } + + if (tmp_value.copy(*res) || tmp_value.append(*res2)) goto null; + res= &tmp_value; use_as_buff=str; } @@ -408,13 +437,15 @@ void Item_func_concat::fix_length_and_dec() max_length= (ulong) max_result_length; } -/* +/** + @details 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). - If one uses a string key key_number is 127. - Encryption result is longer than original by formula: - new_length= org_length + (8-(org_length % 8))+1 + @return + A binary string where first character is CHAR(128 | key-number). + If one uses a string key key_number is 127. + Encryption result is longer than original by formula: + @code new_length= org_length + (8-(org_length % 8))+1 @endcode */ String *Item_func_des_encrypt::val_str(String *str) @@ -587,7 +618,7 @@ wrong_key: } -/* +/** concat with separator. First arg is the separator concat_ws takes at least two arguments. */ @@ -687,8 +718,33 @@ String *Item_func_concat_ws::val_str(String *str) } else { // Two big const strings - if (tmp_value.alloc(max_length) || - tmp_value.copy(*res) || + /* + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which can + be any. Instead of overcommitting at the first row, we grow the + allocated amount by the factor of 2. This ensures that no more than + 25% of memory will be overcommitted on average. + */ + + uint concat_len= res->length() + sep_str->length() + res2->length(); + + if (tmp_value.alloced_length() < concat_len) + { + if (tmp_value.alloced_length() == 0) + { + if (tmp_value.alloc(concat_len)) + goto null; + } + else + { + uint new_len = max(tmp_value.alloced_length() * 2, concat_len); + + if (tmp_value.realloc(new_len)) + goto null; + } + } + + if (tmp_value.copy(*res) || tmp_value.append(*sep_str) || tmp_value.append(*res2)) goto null; @@ -784,12 +840,14 @@ void Item_func_reverse::fix_length_and_dec() max_length = args[0]->max_length; } -/* -** Replace all occurences of string2 in string1 with string3. -** Don't reallocate val_str() if not needed -*/ +/** + Replace all occurences of string2 in string1 with string3. + + Don't reallocate val_str() if not needed. -/* TODO: Fix that this works with binary strings when using USE_MB */ + @todo + Fix that this works with binary strings when using USE_MB +*/ String *Item_func_replace::val_str(String *str) { @@ -949,8 +1007,8 @@ String *Item_func_insert::val_str(String *str) length= res->length(); /* start and length are now sufficiently valid to pass to charpos function */ - start= res->charpos((int) start); - length= res->charpos((int) length, (uint32) start); + start= res->charpos((int) start); + length= res->charpos((int) length, (uint32) start); /* Re-testing with corrected params */ if (start > res->length()) @@ -1027,6 +1085,23 @@ String *Item_str_conv::val_str(String *str) } +void Item_func_lcase::fix_length_and_dec() +{ + collation.set(args[0]->collation); + multiply= collation.collation->casedn_multiply; + converter= collation.collation->cset->casedn; + max_length= args[0]->max_length * multiply; +} + +void Item_func_ucase::fix_length_and_dec() +{ + collation.set(args[0]->collation); + multiply= collation.collation->caseup_multiply; + converter= collation.collation->cset->caseup; + max_length= args[0]->max_length * multiply; +} + + String *Item_func_left::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -1525,20 +1600,20 @@ void Item_func_trim::fix_length_and_dec() } } -void Item_func_trim::print(String *str) +void Item_func_trim::print(String *str, enum_query_type query_type) { if (arg_count == 1) { - Item_func::print(str); + Item_func::print(str, query_type); return; } str->append(Item_func_trim::func_name()); str->append('('); str->append(mode_name()); str->append(' '); - args[1]->print(str); + args[1]->print(str, query_type); str->append(STRING_WITH_LEN(" from ")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } @@ -1640,51 +1715,62 @@ String *Item_func_encrypt::val_str(String *str) void Item_func_encode::fix_length_and_dec() { max_length=args[0]->max_length; - maybe_null=args[0]->maybe_null; + maybe_null=args[0]->maybe_null || args[1]->maybe_null; collation.set(&my_charset_bin); } String *Item_func_encode::val_str(String *str) { - DBUG_ASSERT(fixed == 1); String *res; + char pw_buff[80]; + String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info); + String *password; + DBUG_ASSERT(fixed == 1); + if (!(res=args[0]->val_str(str))) { null_value=1; /* purecov: inspected */ return 0; /* purecov: inspected */ } + + if (!(password=args[1]->val_str(& tmp_pw_value))) + { + null_value=1; + return 0; + } + null_value=0; res=copy_if_not_alloced(str,res,res->length()); + SQL_CRYPT sql_crypt(password->ptr()); sql_crypt.init(); sql_crypt.encode((char*) res->ptr(),res->length()); res->set_charset(&my_charset_bin); return res; } -void Item_func_encode::print(String *str) -{ - str->append(func_name()); - str->append('('); - args[0]->print(str); - str->append(','); - str->append('\''); - str->append(seed); - str->append('\''); - str->append(')'); -} - - String *Item_func_decode::val_str(String *str) { - DBUG_ASSERT(fixed == 1); String *res; + char pw_buff[80]; + String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info); + String *password; + DBUG_ASSERT(fixed == 1); + if (!(res=args[0]->val_str(str))) { null_value=1; /* purecov: inspected */ return 0; /* purecov: inspected */ } + + if (!(password=args[1]->val_str(& tmp_pw_value))) + { + null_value=1; + return 0; + } + null_value=0; res=copy_if_not_alloced(str,res,res->length()); + SQL_CRYPT sql_crypt(password->ptr()); sql_crypt.init(); sql_crypt.decode((char*) res->ptr(),res->length()); return res; @@ -1732,8 +1818,9 @@ String *Item_func_database::val_str(String *str) } -/* - TODO: make USER() replicate properly (currently it is replicated to "") +/** + @todo + make USER() replicate properly (currently it is replicated to "") */ bool Item_func_user::init(const char *user, const char *host) { @@ -1793,7 +1880,7 @@ void Item_func_soundex::fix_length_and_dec() } -/* +/** If alpha, map input letter to soundex code. If not alpha and remove_garbage is set then skip to next char else return 0 @@ -1937,28 +2024,56 @@ String *Item_func_soundex::val_str(String *str) } -/* -** Change a number to format '3,333,333,333.000' -** This should be 'internationalized' sometimes. +/** + Change a number to format '3,333,333,333.000'. + + This should be 'internationalized' sometimes. */ -Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org) +const int FORMAT_MAX_DECIMALS= 30; + +Item_func_format::Item_func_format(Item *org, Item *dec) +: Item_str_func(org, dec) +{ +} + +void Item_func_format::fix_length_and_dec() { - decimals=(uint) set_zone(dec,0,30); + uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen; + uint max_sep_count= char_length/3 + (decimals ? 1 : 0) + /*sign*/1; + collation.set(default_charset()); + max_length= (char_length + max_sep_count + decimals) * + collation.collation->mbmaxlen; } -/* - TODO: This needs to be fixed for multi-byte character set where numbers +/** + @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) { - uint32 length, str_length ,dec; + uint32 length; + uint32 str_length; + /* Number of decimal digits */ + int dec; + /* Number of characters used to represent the decimals, including '.' */ + uint32 dec_length; int diff; DBUG_ASSERT(fixed == 1); - dec= decimals ? decimals+1 : 0; + + dec= (int) args[1]->val_int(); + if (args[1]->null_value) + { + null_value=1; + return NULL; + } + + dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS); + dec_length= dec ? dec+1 : 0; + null_value=0; if (args[0]->result_type() == DECIMAL_RESULT || args[0]->result_type() == INT_RESULT) @@ -1967,7 +2082,7 @@ String *Item_func_format::val_str(String *str) res= args[0]->val_decimal(&dec_val); if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ - my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec); + my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec); my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); str_length= str->length(); if (rnd_dec.sign()) @@ -1978,9 +2093,9 @@ String *Item_func_format::val_str(String *str) double nr= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ - nr= my_double_round(nr, (longlong) decimals, FALSE, FALSE); + nr= my_double_round(nr, (longlong) dec, FALSE, FALSE); /* Here default_charset() is right as this is not an automatic conversion */ - str->set(nr,decimals, default_charset()); + str->set_real(nr, dec, default_charset()); if (isnan(nr)) return str; str_length=str->length(); @@ -1988,13 +2103,13 @@ String *Item_func_format::val_str(String *str) str_length--; // Don't count sign } /* We need this test to handle 'nan' values */ - if (str_length >= dec+4) + if (str_length >= dec_length+4) { char *tmp,*pos; - length= str->length()+(diff=((int)(str_length- dec-1))/3); + length= str->length()+(diff=((int)(str_length- dec_length-1))/3); str= copy_if_not_alloced(&tmp_str,str,length); str->length(length); - tmp= (char*) str->ptr()+length - dec-1; + tmp= (char*) str->ptr()+length - dec_length-1; for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--) pos[0]= pos[-diff]; while (diff) @@ -2014,16 +2129,12 @@ String *Item_func_format::val_str(String *str) } -void Item_func_format::print(String *str) +void Item_func_format::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("format(")); - 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); + args[0]->print(str, query_type); + str->append(','); + args[1]->print(str, query_type); str->append(')'); } @@ -2174,7 +2285,7 @@ String *Item_func_make_set::val_str(String *str) } -Item *Item_func_make_set::transform(Item_transformer transformer, byte *arg) +Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg) { DBUG_ASSERT(!current_thd->is_stmt_prepare()); @@ -2194,14 +2305,14 @@ Item *Item_func_make_set::transform(Item_transformer transformer, byte *arg) } -void Item_func_make_set::print(String *str) +void Item_func_make_set::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("make_set(")); - item->print(str); + item->print(str, query_type); if (arg_count) { str->append(','); - print_args(str, 0); + print_args(str, 0, query_type); } str->append(')'); } @@ -2285,9 +2396,9 @@ void Item_func_repeat::fix_length_and_dec() } } -/* -** Item_func_repeat::str is carefully written to avoid reallocs -** as much as possible at the cost of a local buffer +/** + Item_func_repeat::str is carefully written to avoid reallocs + as much as possible at the cost of a local buffer */ String *Item_func_repeat::val_str(String *str) @@ -2398,7 +2509,7 @@ String *Item_func_rpad::val_str(String *str) count= INT_MAX32; if (count <= (res_char_length= res->numchars())) { // String to pad is big enough - res->length(res->charpos((int) count)); // Shorten result if longer + res->length(res->charpos((int) count)); // Shorten result if longer return (res); } pad_char_length= rpad->numchars(); @@ -2612,10 +2723,10 @@ void Item_func_conv_charset::fix_length_and_dec() max_length = args[0]->max_length*conv_charset->mbmaxlen; } -void Item_func_conv_charset::print(String *str) +void Item_func_conv_charset::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("convert(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" using ")); str->append(conv_charset->csname); str->append(')'); @@ -2683,10 +2794,10 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const } -void Item_func_set_collation::print(String *str) +void Item_func_set_collation::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" collate ")); DBUG_ASSERT(args[1]->basic_const_item() && args[1]->type() == Item::STRING_ITEM); @@ -2763,7 +2874,7 @@ String *Item_func_hex::val_str(String *str) return &tmp_value; } - /* Convert given hex string to a binary string */ + /** Convert given hex string to a binary string. */ String *Item_func_unhex::val_str(String *str) { @@ -2805,10 +2916,10 @@ String *Item_func_unhex::val_str(String *str) } -void Item_func_binary::print(String *str) +void Item_func_binary::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as binary)")); } @@ -2859,7 +2970,7 @@ String *Item_load_file::val_str(String *str) goto err; if ((file = my_open(file_name->c_ptr(), O_RDONLY, MYF(0))) < 0) goto err; - if (my_read(file, (byte*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP))) + if (my_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP))) { my_close(file, MYF(0)); goto err; @@ -2996,27 +3107,27 @@ String* Item_func_inet_ntoa::val_str(String* str) } -/* +#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) + +/** QUOTE() function returns argument string in single quotes suitable for using in a SQL statement. - 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. + 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. - This function is very useful when you want to generate SQL statements + This function is very useful when you want to generate SQL statements. - NOTE + @note QUOTE(NULL) returns the string 'NULL' (4 letters, without quotes). - RETURN VALUES - str Quoted string - NULL Out of memory. + @retval + str Quoted string + @retval + NULL Out of memory. */ -#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) - String *Item_func_quote::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -3262,8 +3373,10 @@ static uint nanoseq; static ulonglong uuid_time=0; static char clock_seq_and_node_str[]="-0000-000000000000"; -/* number of 100-nanosecond intervals between - 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00 */ +/** + number of 100-nanosecond intervals between + 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00. +*/ #define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * \ 1000 * 1000 * 10) |