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.cc941
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