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.cc292
1 files changed, 186 insertions, 106 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 6962ba7c4ac..018afac3812 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -41,35 +41,25 @@ 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);
+ 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 (; my_isdigit(system_charset_info,*str) ; str++) ;
- return (uint) (str-start);
- }
- return 0;
-}
-double Item_str_func::val()
+double Item_str_func::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
- char buff[64];
- char *end_not_used;
+ int err_not_used;
+ char *end_not_used, buff[64];
String *res, tmp(buff,sizeof(buff), &my_charset_bin);
res= val_str(&tmp);
- return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
- &end_not_used, &err) : 0.0;
+ return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0;
}
+
longlong Item_str_func::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -467,7 +457,6 @@ String *Item_func_des_decrypt::val_str(String *str)
DBUG_ASSERT(fixed == 1);
#ifdef HAVE_OPENSSL
uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE;
- DES_key_schedule ks1, ks2, ks3;
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
@@ -484,7 +473,8 @@ String *Item_func_des_decrypt::val_str(String *str)
{
uint key_number=(uint) (*res)[0] & 127;
// Check if automatic key and that we have privilege to uncompress using it
- if (!(current_thd->master_access & SUPER_ACL) || key_number > 9)
+ if (!(current_thd->security_ctx->master_access & SUPER_ACL) ||
+ key_number > 9)
goto error;
VOID(pthread_mutex_lock(&LOCK_des_key_file));
@@ -937,7 +927,7 @@ void Item_func_insert::fix_length_and_dec()
}
-String *Item_func_lcase::val_str(String *str)
+String *Item_str_conv::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
@@ -947,24 +937,25 @@ String *Item_func_lcase::val_str(String *str)
return 0; /* purecov: inspected */
}
null_value=0;
- res=copy_if_not_alloced(str,res,res->length());
- res->casedn();
- return res;
-}
-
-
-String *Item_func_ucase::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- String *res;
- if (!(res=args[0]->val_str(str)))
+ if (multiply == 1)
{
- null_value=1; /* purecov: inspected */
- return 0; /* purecov: inspected */
+ uint len;
+ res= copy_if_not_alloced(str,res,res->length());
+ len= converter(collation.collation, (char*) res->ptr(), res->length(),
+ (char*) res->ptr(), res->length());
+ DBUG_ASSERT(len <= res->length());
+ res->length(len);
+ }
+ else
+ {
+ uint len= res->length() * multiply;
+ tmp_value.alloc(len);
+ tmp_value.set_charset(collation.collation);
+ len= converter(collation.collation, (char*) res->ptr(), res->length(),
+ (char*) tmp_value.ptr(), len);
+ tmp_value.length(len);
+ res= &tmp_value;
}
- null_value=0;
- res=copy_if_not_alloced(str,res,res->length());
- res->caseup();
return res;
}
@@ -1227,21 +1218,29 @@ String *Item_func_substr_index::val_str(String *str)
String *Item_func_ltrim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
- String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove;
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ String tmp(buff,sizeof(buff),system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
+ if (arg_count == 2)
+ {
+ remove_str= args[1]->val_str(&tmp);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ }
+
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
if (remove_length == 1)
{
char chr=(*remove_str)[0];
@@ -1266,21 +1265,29 @@ String *Item_func_ltrim::val_str(String *str)
String *Item_func_rtrim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
- String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove;
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ String tmp(buff, sizeof(buff), system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
+ if (arg_count == 2)
+ {
+ remove_str= args[1]->val_str(&tmp);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ }
+
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
#ifdef USE_MB
char *p=ptr;
register uint32 l;
@@ -1339,31 +1346,31 @@ String *Item_func_rtrim::val_str(String *str)
String *Item_func_trim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ const char *r_ptr;
+ String tmp(buff, sizeof(buff), system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- String *remove_str; /* The string to remove from res. */
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
if (arg_count == 2)
{
remove_str= args[1]->val_str(&tmp);
if ((null_value= args[1]->null_value))
return 0;
}
- else
- remove_str= &remove; /* Default value. */
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
- const char *r_ptr=remove_str->ptr();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
+ r_ptr= remove_str->ptr();
while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
ptr+=remove_length;
#ifdef USE_MB
@@ -1555,14 +1562,16 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
uint conv_errors;
String tmp, cstr, *ostr= val_str(&tmp);
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
+ if (conv_errors ||
+ !(conv= new Item_static_string_func(fully_qualified_func_name(),
+ cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
{
return NULL;
}
conv->str_value.copy();
- conv->str_value.shrink_to_length();
+ conv->str_value.mark_as_const();
return conv;
}
@@ -1588,13 +1597,24 @@ String *Item_func_user::val_str(String *str)
DBUG_ASSERT(fixed == 1);
THD *thd=current_thd;
CHARSET_INFO *cs= system_charset_info;
- const char *host= thd->host_or_ip;
+ const char *host, *user;
uint res_length;
+ if (is_current)
+ {
+ user= thd->security_ctx->priv_user;
+ host= thd->security_ctx->priv_host;
+ }
+ else
+ {
+ user= thd->main_security_ctx.user;
+ host= thd->main_security_ctx.host_or_ip;
+ }
+
// For system threads (e.g. replication SQL thread) user may be empty
- if (!thd->user)
+ if (!user)
return &my_empty_string;
- res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
+ res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
if (str->alloc(res_length))
{
@@ -1602,12 +1622,13 @@ String *Item_func_user::val_str(String *str)
return 0;
}
res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",
- thd->user, host);
+ 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);
@@ -1702,27 +1723,43 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
String *Item_func_format::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double nr =args[0]->val();
+ uint32 length, str_length ,dec;
int diff;
- uint32 length, str_length;
- uint dec;
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
+ DBUG_ASSERT(fixed == 1);
dec= decimals ? decimals+1 : 0;
- /* Here default_charset() is right as this is not an automatic conversion */
- str->set(nr,decimals, default_charset());
- if (isnan(nr))
- return str;
- str_length=str->length();
- if (nr < 0)
- str_length--; // Don't count sign
+ if (args[0]->result_type() == DECIMAL_RESULT ||
+ args[0]->result_type() == INT_RESULT)
+ {
+ my_decimal dec_val, rnd_dec, *res;
+ 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_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
+ str_length= str->length();
+ if (rnd_dec.sign())
+ str_length--;
+ }
+ else
+ {
+ double nr= args[0]->val_real();
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ nr= my_double_round(nr, decimals, FALSE);
+ /* Here default_charset() is right as this is not an automatic conversion */
+ str->set(nr,decimals, default_charset());
+ if (isnan(nr))
+ return str;
+ str_length=str->length();
+ if (nr < 0)
+ str_length--; // Don't count sign
+ }
/* We need this test to handle 'nan' values */
if (str_length >= dec+4)
{
char *tmp,*pos;
- length= str->length()+(diff= (int)(str_length- dec-1)/3);
+ length= str->length()+(diff=((int)(str_length- dec-1))/3);
str= copy_if_not_alloced(&tmp_str,str,length);
str->length(length);
tmp= (char*) str->ptr()+length - dec-1;
@@ -1775,14 +1812,14 @@ void Item_func_elt::fix_length_and_dec()
}
-double Item_func_elt::val()
+double Item_func_elt::val_real()
{
DBUG_ASSERT(fixed == 1);
uint tmp;
null_value=1;
if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
return 0.0;
- double result= args[tmp]->val();
+ double result= args[tmp]->val_real();
null_value= args[tmp]->null_value;
return result;
}
@@ -1835,7 +1872,7 @@ void Item_func_make_set::fix_length_and_dec()
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();
@@ -1946,6 +1983,33 @@ b1: str->append((char)(num>>8));
}
str->set_charset(collation.collation);
str->realloc(str->length()); // Add end 0 (for Purify)
+
+ /* Check whether we got a well-formed string */
+ CHARSET_INFO *cs= collation.collation;
+ int well_formed_error;
+ uint wlen= cs->cset->well_formed_len(cs,
+ str->ptr(), str->ptr() + str->length(),
+ str->length(), &well_formed_error);
+ if (wlen < str->length())
+ {
+ THD *thd= current_thd;
+ char hexbuf[7];
+ enum MYSQL_ERROR::enum_warning_level level;
+ uint diff= str->length() - wlen;
+ set_if_smaller(diff, 3);
+ octet2hex(hexbuf, (const uchar*) str->ptr() + wlen, diff);
+ if (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ null_value= 1;
+ str= 0;
+ }
+ else
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
+ ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
+ }
return str;
}
@@ -2098,7 +2162,7 @@ String *Item_func_rpad::val_str(String *str)
func_name(), current_thd->variables.max_allowed_packet);
goto err;
}
- if(args[2]->null_value || !pad_char_length)
+ if (args[2]->null_value || !pad_char_length)
goto err;
res_byte_length= res->length(); /* Must be done before alloc_buffer */
if (!(res= alloc_buffer(res,str,&tmp_value,byte_count)))
@@ -2304,8 +2368,8 @@ void Item_func_set_collation::fix_length_and_dec()
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);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ colname, args[0]->collation.collation->csname);
return;
}
collation.set(set_collation, DERIVATION_EXPLICIT);
@@ -2322,7 +2386,7 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
return 0;
Item_func *item_func=(Item_func*) item;
if (arg_count != item_func->arg_count ||
- func_name() != item_func->func_name())
+ functype() != item_func->functype())
return 0;
Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item;
if (collation.collation != item_func_sc->collation.collation)
@@ -2333,6 +2397,18 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
return 1;
}
+
+void Item_func_set_collation::print(String *str)
+{
+ str->append('(');
+ args[0]->print(str);
+ str->append(" collate ", 9);
+ DBUG_ASSERT(args[1]->basic_const_item() &&
+ args[1]->type() == Item::STRING_ITEM);
+ args[1]->str_value.print(str);
+ str->append(')');
+}
+
String *Item_func_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -2366,9 +2442,10 @@ String *Item_func_hex::val_str(String *str)
ulonglong dec;
char ans[65],*ptr;
/* Return hex of unsigned longlong value */
- if (args[0]->result_type() == REAL_RESULT)
+ if (args[0]->result_type() == REAL_RESULT ||
+ args[0]->result_type() == DECIMAL_RESULT)
{
- double val= args[0]->val();
+ double val= args[0]->val_real();
if ((val <= (double) LONGLONG_MIN) ||
(val >= (double) (ulonglong) ULONGLONG_MAX))
dec= ~(longlong) 0;
@@ -2471,7 +2548,7 @@ String *Item_load_file::val_str(String *str)
if (!(file_name= args[0]->val_str(str))
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- || !(current_thd->master_access & FILE_ACL)
+ || !(current_thd->security_ctx->master_access & FILE_ACL)
#endif
)
goto err;
@@ -2913,6 +2990,8 @@ String *Item_func_uuid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
char *s;
+ THD *thd= current_thd;
+
pthread_mutex_lock(&LOCK_uuid_generator);
if (! uuid_time) /* first UUID() call. initializing data */
{
@@ -2927,7 +3006,7 @@ String *Item_func_uuid::val_str(String *str)
with a clock_seq value (initialized random below), we use a separate
randominit() here
*/
- randominit(&uuid_rand, tmp + (ulong)current_thd, tmp + query_id);
+ randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)query_id);
for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
}
@@ -2937,16 +3016,17 @@ String *Item_func_uuid::val_str(String *str)
*--s=_dig_vec_lower[mac[i] & 15];
*--s=_dig_vec_lower[mac[i] >> 4];
}
- randominit(&uuid_rand, tmp + (ulong)start_time, tmp + bytes_sent);
+ randominit(&uuid_rand, tmp + (ulong)start_time,
+ tmp + thd->status_var.bytes_sent);
set_clock_seq_str();
}
ulonglong tv=my_getsystime() + UUID_TIME_OFFSET + nanoseq;
if (unlikely(tv < uuid_time))
set_clock_seq_str();
- else
- if (unlikely(tv == uuid_time))
- { /* special protection from low-res system clocks */
+ else if (unlikely(tv == uuid_time))
+ {
+ /* special protection from low-res system clocks */
nanoseq++;
tv++;
}