summaryrefslogtreecommitdiff
path: root/sql/item_strfunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r--sql/item_strfunc.cc323
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)