Bug#22684 (BENCHMARK, ENCODE, DECODE and FORMAT are not real functions)

Before this change, the functions BENCHMARK, ENCODE, DECODE and FORMAT could
only accept a constant for some parameters.

After this change, this restriction has been removed. An implication is that
these functions can also be used in prepared statements.

The change consist of changing the following classes:
- Item_func_benchmark
- Item_func_encode
- Item_func_decode
- Item_func_format
to:
- only accept Item* in the constructor,
- and evaluate arguments during calls to val_xxx()
which fits the general design of all the other functions.

The 'TODO' items identified in item_create.cc during the work done for
Bug 21114 are addressed by this fix, as a natural consequence of aligning
the design.

In the 'func_str' test, a single very long test line involving an explain
extended select with many functions has been rewritten into multiple
separate tests, to improve maintainability.
The result of explain extended select decode(encode(...)) has changed,
since the encode and decode functions now print all their parameters.
parent 6b0e7f3e
This diff is collapsed.
...@@ -296,11 +296,6 @@ select atan(); ...@@ -296,11 +296,6 @@ select atan();
ERROR 42000: Incorrect parameter count in the call to native function 'atan' ERROR 42000: Incorrect parameter count in the call to native function 'atan'
select atan2(1, 2, 3); select atan2(1, 2, 3);
ERROR 42000: Incorrect parameter count in the call to native function 'atan2' ERROR 42000: Incorrect parameter count in the call to native function 'atan2'
select benchmark(10, 1+1);
benchmark(10, 1+1)
0
select benchmark(5+5, 2);
ERROR 42000: Incorrect parameters in the call to native function 'BENCHMARK'
select concat(); select concat();
ERROR 42000: Incorrect parameter count in the call to native function 'concat' ERROR 42000: Incorrect parameter count in the call to native function 'concat'
select concat("foo"); select concat("foo");
...@@ -310,11 +305,6 @@ select concat_ws(); ...@@ -310,11 +305,6 @@ select concat_ws();
ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws' ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws'
select concat_ws("foo"); select concat_ws("foo");
ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws' ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws'
set @pwd="my password";
select encode("secret", @pwd);
ERROR 42000: Incorrect parameters in the call to native function 'ENCODE'
select decode("encoded-secret", @pwd);
ERROR 42000: Incorrect parameters in the call to native function 'DECODE'
select encrypt(); select encrypt();
ERROR 42000: Incorrect parameter count in the call to native function 'encrypt' ERROR 42000: Incorrect parameter count in the call to native function 'encrypt'
select encrypt(1, 2, 3); select encrypt(1, 2, 3);
...@@ -339,9 +329,6 @@ select field(); ...@@ -339,9 +329,6 @@ select field();
ERROR 42000: Incorrect parameter count in the call to native function 'field' ERROR 42000: Incorrect parameter count in the call to native function 'field'
select field("p1"); select field("p1");
ERROR 42000: Incorrect parameter count in the call to native function 'field' ERROR 42000: Incorrect parameter count in the call to native function 'field'
set @dec=2;
select format(pi(), @dec);
ERROR 42000: Incorrect parameters in the call to native function 'FORMAT'
select from_unixtime(); select from_unixtime();
ERROR 42000: Incorrect parameter count in the call to native function 'from_unixtime' ERROR 42000: Incorrect parameter count in the call to native function 'from_unixtime'
select from_unixtime(1, 2, 3); select from_unixtime(1, 2, 3);
......
...@@ -2391,3 +2391,49 @@ Level Code Message ...@@ -2391,3 +2391,49 @@ Level Code Message
Note 1051 Unknown table 't1' Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2' Note 1051 Unknown table 't2'
deallocate prepare abc; deallocate prepare abc;
set @my_password="password";
set @my_data="clear text to encode";
prepare stmt1 from 'select decode(encode(?, ?), ?)';
execute stmt1 using @my_data, @my_password, @my_password;
decode(encode(?, ?), ?)
clear text to encode
set @my_data="more text to encode";
execute stmt1 using @my_data, @my_password, @my_password;
decode(encode(?, ?), ?)
more text to encode
set @my_password="new password";
execute stmt1 using @my_data, @my_password, @my_password;
decode(encode(?, ?), ?)
more text to encode
deallocate prepare stmt1;
set @to_format="123456789.123456789";
set @dec=0;
prepare stmt2 from 'select format(?, ?)';
execute stmt2 using @to_format, @dec;
format(?, ?)
123,456,789
set @dec=4;
execute stmt2 using @to_format, @dec;
format(?, ?)
123,456,789.1235
set @dec=6;
execute stmt2 using @to_format, @dec;
format(?, ?)
123,456,789.123457
set @dec=2;
execute stmt2 using @to_format, @dec;
format(?, ?)
123,456,789.12
set @to_format="100";
execute stmt2 using @to_format, @dec;
format(?, ?)
100.00
set @to_format="1000000";
execute stmt2 using @to_format, @dec;
format(?, ?)
1,000,000.00
set @to_format="10000";
execute stmt2 using @to_format, @dec;
format(?, ?)
10,000.00
deallocate prepare stmt2;
...@@ -460,7 +460,51 @@ drop table t7; ...@@ -460,7 +460,51 @@ drop table t7;
select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2);
explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty"); explain extended select md5('hello');
explain extended select sha('abc');
explain extended select sha1('abc');
explain extended select soundex('');
explain extended select 'mood' sounds like 'mud';
explain extended select aes_decrypt(aes_encrypt('abc','1'),'1');
explain extended select concat('*',space(5),'*');
explain extended select reverse('abc');
explain extended select rpad('a',4,'1');
explain extended select lpad('a',4,'1');
explain extended select concat_ws(',','',NULL,'a');
explain extended select make_set(255,_latin2'a', _latin2'b', _latin2'c');
explain extended select elt(2,1);
explain extended select locate("a","b",2);
explain extended select format(130,10);
explain extended select char(0);
explain extended select conv(130,16,10);
explain extended select hex(130);
explain extended select binary 'HE';
explain extended select export_set(255,_latin2'y', _latin2'n', _latin2' ');
explain extended select FIELD('b' COLLATE latin1_bin,'A','B');
explain extended select FIND_IN_SET(_latin1'B', _latin1'a,b,c,d');
explain extended select collation(conv(130,16,10));
explain extended select coercibility(conv(130,16,10));
explain extended select length('\n\t\r\b\0\_\%\\');
explain extended select bit_length('\n\t\r\b\0\_\%\\');
explain extended select bit_length('\n\t\r\b\0\_\%\\');
explain extended select concat('monty',' was here ','again');
explain extended select length('hello');
explain extended select char(ascii('h'));
explain extended select ord('h');
explain extended select quote(1/0);
explain extended select crc32("123");
explain extended select replace('aaaa','a','b');
explain extended select insert('txs',2,1,'hi');
explain extended select left(_latin2'a',1);
explain extended select right(_latin2'a',1);
explain extended select lcase(_latin2'a');
explain extended select ucase(_latin2'a');
explain extended select SUBSTR('abcdefg',3,2);
explain extended select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2);
explain extended select trim(_latin2' a ');
explain extended select ltrim(_latin2' a ');
explain extended select rtrim(_latin2' a ');
explain extended select decode(encode(repeat("a",100000),"monty"),"monty");
# #
# lpad returns incorrect result (Bug #2182) # lpad returns incorrect result (Bug #2182)
...@@ -780,4 +824,67 @@ SELECT * FROM t1 INNER JOIN t2 ON code=id ...@@ -780,4 +824,67 @@ SELECT * FROM t1 INNER JOIN t2 ON code=id
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# Bug#22684: The Functions ENCODE, DECODE and FORMAT are not real functions
#
select encode(NULL, NULL);
select encode("data", NULL);
select encode(NULL, "password");
select decode(NULL, NULL);
select decode("data", NULL);
select decode(NULL, "password");
select format(NULL, NULL);
select format(pi(), NULL);
select format(NULL, 2);
select benchmark(NULL, NULL);
select benchmark(0, NULL);
select benchmark(100, NULL);
select benchmark(NULL, 1+1);
#
# Please note:
# 1) The collation of the password is irrelevant, the encryption uses
# the binary representation of the string without charset/collation.
# 2) These tests can not print the encoded text directly, because it's binary,
# and doing this would cause problems with source control.
# Instead, an md5() checksum is used, to verify the result indirectly.
# 3) Each md5() result must be identical.
# 4) The md5() result must never change, and must be stable across releases.
#
set @password="password";
set @my_data="clear text to encode";
select md5(encode(@my_data, "password"));
select md5(encode(@my_data, _utf8 "password"));
select md5(encode(@my_data, binary "password"));
select md5(encode(@my_data, _latin1 "password"));
select md5(encode(@my_data, _koi8r "password"));
select md5(encode(@my_data, (select "password" from dual)));
select md5(encode(@my_data, concat("pass", "word")));
select md5(encode(@my_data, @password));
set @my_data="binary encoded data";
select md5(decode(@my_data, "password"));
select md5(decode(@my_data, _utf8 "password"));
select md5(decode(@my_data, binary "password"));
select md5(decode(@my_data, _latin1 "password"));
select md5(decode(@my_data, _koi8r "password"));
select md5(decode(@my_data, (select "password" from dual)));
select md5(decode(@my_data, concat("pass", "word")));
select md5(decode(@my_data, @password));
set @dec=5;
select format(pi(), (1+1));
select format(pi(), (select 3 from dual));
select format(pi(), @dec);
set @bench_count=10;
select benchmark(10, pi());
select benchmark(5+5, pi());
select benchmark((select 10 from dual), pi());
select benchmark(@bench_count, pi());
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -399,11 +399,6 @@ select atan(); ...@@ -399,11 +399,6 @@ select atan();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select atan2(1, 2, 3); select atan2(1, 2, 3);
select benchmark(10, 1+1);
-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
select benchmark(5+5, 2);
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select concat(); select concat();
select concat("foo"); select concat("foo");
...@@ -413,12 +408,6 @@ select concat_ws(); ...@@ -413,12 +408,6 @@ select concat_ws();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select concat_ws("foo"); select concat_ws("foo");
set @pwd="my password";
-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
select encode("secret", @pwd);
-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
select decode("encoded-secret", @pwd);
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select encrypt(); select encrypt();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
...@@ -448,10 +437,6 @@ select field(); ...@@ -448,10 +437,6 @@ select field();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select field("p1"); select field("p1");
set @dec=2;
-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
select format(pi(), @dec);
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select from_unixtime(); select from_unixtime();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
......
...@@ -2414,3 +2414,38 @@ execute abc; ...@@ -2414,3 +2414,38 @@ execute abc;
drop table if exists t1, t2; drop table if exists t1, t2;
execute abc; execute abc;
deallocate prepare abc; deallocate prepare abc;
#
# Bug#22684: The Functions ENCODE, DECODE and FORMAT are not real functions
#
set @my_password="password";
set @my_data="clear text to encode";
prepare stmt1 from 'select decode(encode(?, ?), ?)';
execute stmt1 using @my_data, @my_password, @my_password;
set @my_data="more text to encode";
execute stmt1 using @my_data, @my_password, @my_password;
set @my_password="new password";
execute stmt1 using @my_data, @my_password, @my_password;
deallocate prepare stmt1;
set @to_format="123456789.123456789";
set @dec=0;
prepare stmt2 from 'select format(?, ?)';
execute stmt2 using @to_format, @dec;
set @dec=4;
execute stmt2 using @to_format, @dec;
set @dec=6;
execute stmt2 using @to_format, @dec;
set @dec=2;
execute stmt2 using @to_format, @dec;
set @to_format="100";
execute stmt2 using @to_format, @dec;
set @to_format="1000000";
execute stmt2 using @to_format, @dec;
set @to_format="10000";
execute stmt2 using @to_format, @dec;
deallocate prepare stmt2;
...@@ -2612,15 +2612,8 @@ Create_func_benchmark Create_func_benchmark::s_singleton; ...@@ -2612,15 +2612,8 @@ Create_func_benchmark Create_func_benchmark::s_singleton;
Item* Item*
Create_func_benchmark::create(THD *thd, Item *arg1, Item *arg2) Create_func_benchmark::create(THD *thd, Item *arg1, Item *arg2)
{ {
/* TODO: Known limitation, see Bug#22684 */
if ((arg1->type() != Item::INT_ITEM) || ! arg1->basic_const_item())
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "BENCHMARK");
return NULL;
}
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_benchmark(arg1->val_int(), arg2); return new (thd->mem_root) Item_func_benchmark(arg1, arg2);
} }
...@@ -2887,17 +2880,7 @@ Create_func_decode Create_func_decode::s_singleton; ...@@ -2887,17 +2880,7 @@ Create_func_decode Create_func_decode::s_singleton;
Item* Item*
Create_func_decode::create(THD *thd, Item *arg1, Item *arg2) Create_func_decode::create(THD *thd, Item *arg1, Item *arg2)
{ {
/* TODO: Known limitation, see Bug#22684 */ return new (thd->mem_root) Item_func_decode(arg1, arg2);
if ((arg2->type() != Item::STRING_ITEM) || ! arg2->basic_const_item())
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "DECODE");
return NULL;
}
String dummy;
String *val = arg2->val_str(& dummy);
DBUG_ASSERT(val);
return new (thd->mem_root) Item_func_decode(arg1, val->c_ptr());
} }
...@@ -3033,17 +3016,7 @@ Create_func_encode Create_func_encode::s_singleton; ...@@ -3033,17 +3016,7 @@ Create_func_encode Create_func_encode::s_singleton;
Item* Item*
Create_func_encode::create(THD *thd, Item *arg1, Item *arg2) Create_func_encode::create(THD *thd, Item *arg1, Item *arg2)
{ {
/* TODO: Known limitation, see Bug#22684 */ return new (thd->mem_root) Item_func_encode(arg1, arg2);
if ((arg2->type() != Item::STRING_ITEM) || ! arg2->basic_const_item())
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "ENCODE");
return NULL;
}
String dummy;
String *val = arg2->val_str(& dummy);
DBUG_ASSERT(val);
return new (thd->mem_root) Item_func_encode(arg1, val->c_ptr());
} }
...@@ -3235,14 +3208,7 @@ Create_func_format Create_func_format::s_singleton; ...@@ -3235,14 +3208,7 @@ Create_func_format Create_func_format::s_singleton;
Item* Item*
Create_func_format::create(THD *thd, Item *arg1, Item *arg2) Create_func_format::create(THD *thd, Item *arg1, Item *arg2)
{ {
/* TODO: Known limitation, see Bug#22684 */ return new (thd->mem_root) Item_func_format(arg1, arg2);
if ((arg2->type() != Item::INT_ITEM) || ! arg2->basic_const_item())
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "FORMAT");
return NULL;
}
return new (thd->mem_root) Item_func_format(arg1, arg2->val_int());
} }
......
...@@ -3390,18 +3390,28 @@ longlong Item_func_benchmark::val_int() ...@@ -3390,18 +3390,28 @@ longlong Item_func_benchmark::val_int()
char buff[MAX_FIELD_WIDTH]; char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), &my_charset_bin); String tmp(buff,sizeof(buff), &my_charset_bin);
THD *thd=current_thd; THD *thd=current_thd;
ulong loop_count;
loop_count= args[0]->val_int();
if (args[0]->null_value)
{
null_value= 1;
return 0;
}
null_value=0;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++) for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
{ {
switch (args[0]->result_type()) { switch (args[1]->result_type()) {
case REAL_RESULT: case REAL_RESULT:
(void) args[0]->val_real(); (void) args[1]->val_real();
break; break;
case INT_RESULT: case INT_RESULT:
(void) args[0]->val_int(); (void) args[1]->val_int();
break; break;
case STRING_RESULT: case STRING_RESULT:
(void) args[0]->val_str(&tmp); (void) args[1]->val_str(&tmp);
break; break;
case ROW_RESULT: case ROW_RESULT:
default: default:
...@@ -3417,13 +3427,9 @@ longlong Item_func_benchmark::val_int() ...@@ -3417,13 +3427,9 @@ longlong Item_func_benchmark::val_int()
void Item_func_benchmark::print(String *str) void Item_func_benchmark::print(String *str)
{ {
str->append(STRING_WITH_LEN("benchmark(")); str->append(STRING_WITH_LEN("benchmark("));
char buffer[20];
// my_charset_bin is good enough for numbers
String st(buffer, sizeof(buffer), &my_charset_bin);
st.set((ulonglong)loop_count, &my_charset_bin);
str->append(st);
str->append(',');
args[0]->print(str); args[0]->print(str);
str->append(',');
args[1]->print(str);
str->append(')'); str->append(')');
} }
......
...@@ -924,10 +924,9 @@ public: ...@@ -924,10 +924,9 @@ public:
class Item_func_benchmark :public Item_int_func class Item_func_benchmark :public Item_int_func
{ {
ulong loop_count;
public: public:
Item_func_benchmark(ulong loop_count_arg,Item *expr) Item_func_benchmark(Item *count_expr, Item *expr)
:Item_int_func(expr), loop_count(loop_count_arg) :Item_int_func(count_expr, expr)
{} {}
longlong val_int(); longlong val_int();
const char *func_name() const { return "benchmark"; } const char *func_name() const { return "benchmark"; }
......
...@@ -1621,21 +1621,33 @@ String *Item_func_encrypt::val_str(String *str) ...@@ -1621,21 +1621,33 @@ String *Item_func_encrypt::val_str(String *str)
void Item_func_encode::fix_length_and_dec() void Item_func_encode::fix_length_and_dec()
{ {
max_length=args[0]->max_length; 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); collation.set(&my_charset_bin);
} }
String *Item_func_encode::val_str(String *str) String *Item_func_encode::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1);
String *res; 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))) if (!(res=args[0]->val_str(str)))
{ {
null_value=1; /* purecov: inspected */ null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */ return 0; /* purecov: inspected */
} }
if (!(password=args[1]->val_str(& tmp_pw_value)))
{
null_value=1;
return 0;
}
null_value=0; null_value=0;
res=copy_if_not_alloced(str,res,res->length()); res=copy_if_not_alloced(str,res,res->length());
SQL_CRYPT sql_crypt(password->ptr());
sql_crypt.init(); sql_crypt.init();
sql_crypt.encode((char*) res->ptr(),res->length()); sql_crypt.encode((char*) res->ptr(),res->length());
res->set_charset(&my_charset_bin); res->set_charset(&my_charset_bin);
...@@ -1644,15 +1656,27 @@ String *Item_func_encode::val_str(String *str) ...@@ -1644,15 +1656,27 @@ String *Item_func_encode::val_str(String *str)
String *Item_func_decode::val_str(String *str) String *Item_func_decode::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1);
String *res; 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))) if (!(res=args[0]->val_str(str)))
{ {
null_value=1; /* purecov: inspected */ null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */ return 0; /* purecov: inspected */
} }
if (!(password=args[1]->val_str(& tmp_pw_value)))
{
null_value=1;
return 0;
}
null_value=0; null_value=0;
res=copy_if_not_alloced(str,res,res->length()); res=copy_if_not_alloced(str,res,res->length());
SQL_CRYPT sql_crypt(password->ptr());
sql_crypt.init(); sql_crypt.init();
sql_crypt.decode((char*) res->ptr(),res->length()); sql_crypt.decode((char*) res->ptr(),res->length());
return res; return res;
...@@ -1822,9 +1846,19 @@ String *Item_func_soundex::val_str(String *str) ...@@ -1822,9 +1846,19 @@ String *Item_func_soundex::val_str(String *str)
** This should be 'internationalized' sometimes. ** 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); collation.set(default_charset());
uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
max_length= ((char_length + (char_length-args[0]->decimals)/3) *
collation.collation->mbmaxlen);
} }
...@@ -1835,10 +1869,25 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org) ...@@ -1835,10 +1869,25 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
String *Item_func_format::val_str(String *str) 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; int diff;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
dec= decimals ? decimals+1 : 0;
dec= 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 || if (args[0]->result_type() == DECIMAL_RESULT ||
args[0]->result_type() == INT_RESULT) args[0]->result_type() == INT_RESULT)
...@@ -1847,7 +1896,7 @@ String *Item_func_format::val_str(String *str) ...@@ -1847,7 +1896,7 @@ String *Item_func_format::val_str(String *str)
res= args[0]->val_decimal(&dec_val); res= args[0]->val_decimal(&dec_val);
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */ 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); my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
str_length= str->length(); str_length= str->length();
if (rnd_dec.sign()) if (rnd_dec.sign())
...@@ -1858,9 +1907,9 @@ String *Item_func_format::val_str(String *str) ...@@ -1858,9 +1907,9 @@ String *Item_func_format::val_str(String *str)
double nr= args[0]->val_real(); double nr= args[0]->val_real();
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */ return 0; /* purecov: inspected */
nr= my_double_round(nr, decimals, FALSE); nr= my_double_round(nr, dec, FALSE);
/* Here default_charset() is right as this is not an automatic conversion */ /* Here default_charset() is right as this is not an automatic conversion */
str->set_real(nr,decimals, default_charset()); str->set_real(nr, dec, default_charset());
if (isnan(nr)) if (isnan(nr))
return str; return str;
str_length=str->length(); str_length=str->length();
...@@ -1868,13 +1917,13 @@ String *Item_func_format::val_str(String *str) ...@@ -1868,13 +1917,13 @@ String *Item_func_format::val_str(String *str)
str_length--; // Don't count sign str_length--; // Don't count sign
} }
/* We need this test to handle 'nan' values */ /* We need this test to handle 'nan' values */
if (str_length >= dec+4) if (str_length >= dec_length+4)
{ {
char *tmp,*pos; 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= copy_if_not_alloced(&tmp_str,str,length);
str->length(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--) for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--)
pos[0]= pos[-diff]; pos[0]= pos[-diff];
while (diff) while (diff)
...@@ -1898,12 +1947,8 @@ void Item_func_format::print(String *str) ...@@ -1898,12 +1947,8 @@ void Item_func_format::print(String *str)
{ {
str->append(STRING_WITH_LEN("format(")); str->append(STRING_WITH_LEN("format("));
args[0]->print(str); args[0]->print(str);
str->append(','); str->append(',');
// my_charset_bin is good enough for numbers args[1]->print(str);
char buffer[20];
String st(buffer, sizeof(buffer), &my_charset_bin);
st.set((ulonglong)decimals, &my_charset_bin);
str->append(st);
str->append(')'); str->append(')');
} }
......
...@@ -360,11 +360,9 @@ public: ...@@ -360,11 +360,9 @@ public:
class Item_func_encode :public Item_str_func class Item_func_encode :public Item_str_func
{ {
protected:
SQL_CRYPT sql_crypt;
public: public:
Item_func_encode(Item *a, char *seed): Item_func_encode(Item *a, Item *seed):
Item_str_func(a),sql_crypt(seed) {} Item_str_func(a, seed) {}
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "encode"; } const char *func_name() const { return "encode"; }
...@@ -374,7 +372,7 @@ public: ...@@ -374,7 +372,7 @@ public:
class Item_func_decode :public Item_func_encode class Item_func_decode :public Item_func_encode
{ {
public: public:
Item_func_decode(Item *a, char *seed): Item_func_encode(a,seed) {} Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {}
String *val_str(String *); String *val_str(String *);
const char *func_name() const { return "decode"; } const char *func_name() const { return "decode"; }
}; };
...@@ -507,15 +505,9 @@ class Item_func_format :public Item_str_func ...@@ -507,15 +505,9 @@ class Item_func_format :public Item_str_func
{ {
String tmp_str; String tmp_str;
public: public:
Item_func_format(Item *org,int dec); Item_func_format(Item *org, Item *dec);
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec() void fix_length_and_dec();
{
collation.set(default_charset());
uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
max_length= ((char_length + (char_length-args[0]->decimals)/3) *
collation.collation->mbmaxlen);
}
const char *func_name() const { return "format"; } const char *func_name() const { return "format"; }
void print(String *); void print(String *);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment