Commit c9981fbe authored by halfspawn's avatar halfspawn Committed by Alexander Barkov

MDEV-13003 - Oracle compatibility : Replace function

parent 1a9e13d6
SET sql_mode=ORACLE;
#
# MDEV-13003 - Oracle compatibility : Replace function
#
SELECT REPLACE(null,'a','b') ;
REPLACE(null,'a','b')
NULL
SELECT REPLACE('ab',null,'b') ;
REPLACE('ab',null,'b')
ab
SELECT REPLACE('ab','a',null) ;
REPLACE('ab','a',null)
b
SELECT REPLACE('ab',null,null) ;
REPLACE('ab',null,null)
ab
SELECT REPLACE('aaa','a',null) ;
REPLACE('aaa','a',null)
NULL
EXPLAIN EXTENDED SELECT REPLACE('ab','a',null) ;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select replace_oracle('ab','a',NULL) AS "REPLACE('ab','a',null)"
CREATE VIEW v1 AS SELECT REPLACE('ab','a',null) ;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE VIEW "v1" AS select replace_oracle('ab','a',NULL) AS "REPLACE('ab','a',null)" latin1 latin1_swedish_ci
SELECT * FROM v1;
REPLACE('ab','a',null)
b
DROP VIEW v1;
#
# Testing replace with null args
#
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-13003 - Oracle compatibility : Replace function
--echo #
SELECT REPLACE(null,'a','b') ;
SELECT REPLACE('ab',null,'b') ;
SELECT REPLACE('ab','a',null) ;
SELECT REPLACE('ab',null,null) ;
SELECT REPLACE('aaa','a',null) ;
EXPLAIN EXTENDED SELECT REPLACE('ab','a',null) ;
CREATE VIEW v1 AS SELECT REPLACE('ab','a',null) ;
SHOW CREATE VIEW v1;
SELECT * FROM v1;
DROP VIEW v1;
...@@ -2624,6 +2624,19 @@ class Create_func_release_lock : public Create_func_arg1 ...@@ -2624,6 +2624,19 @@ class Create_func_release_lock : public Create_func_arg1
}; };
class Create_func_replace_oracle : public Create_func_arg3
{
public:
virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_replace_oracle s_singleton;
protected:
Create_func_replace_oracle() {}
virtual ~Create_func_replace_oracle() {}
};
class Create_func_reverse : public Create_func_arg1 class Create_func_reverse : public Create_func_arg1
{ {
public: public:
...@@ -6214,6 +6227,16 @@ Create_func_release_lock::create_1_arg(THD *thd, Item *arg1) ...@@ -6214,6 +6227,16 @@ Create_func_release_lock::create_1_arg(THD *thd, Item *arg1)
} }
Create_func_replace_oracle Create_func_replace_oracle::s_singleton;
Item*
Create_func_replace_oracle::create_3_arg(THD *thd, Item *arg1, Item *arg2,
Item *arg3)
{
return new (thd->mem_root) Item_func_replace_oracle(thd, arg1, arg2, arg3);
}
Create_func_reverse Create_func_reverse::s_singleton; Create_func_reverse Create_func_reverse::s_singleton;
Item* Item*
...@@ -6802,6 +6825,7 @@ static Native_func_registry func_array[] = ...@@ -6802,6 +6825,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)}, { { C_STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
{ { C_STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)}, { { C_STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)},
{ { C_STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)}, { { C_STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)},
{ { C_STRING_WITH_LEN("CHR") }, BUILDER(Create_func_chr)},
{ { C_STRING_WITH_LEN("COERCIBILITY") }, BUILDER(Create_func_coercibility)}, { { C_STRING_WITH_LEN("COERCIBILITY") }, BUILDER(Create_func_coercibility)},
{ { C_STRING_WITH_LEN("COLUMN_CHECK") }, BUILDER(Create_func_dyncol_check)}, { { C_STRING_WITH_LEN("COLUMN_CHECK") }, BUILDER(Create_func_dyncol_check)},
{ { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)}, { { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)},
...@@ -6815,7 +6839,6 @@ static Native_func_registry func_array[] = ...@@ -6815,7 +6839,6 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)}, { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
{ { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)}, { { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
{ { C_STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)}, { { C_STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
{ { C_STRING_WITH_LEN("CHR") }, BUILDER(Create_func_chr)},
{ { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)}, { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
{ { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)}, { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)},
{ { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)}, { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)},
...@@ -6990,6 +7013,8 @@ static Native_func_registry func_array[] = ...@@ -6990,6 +7013,8 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, { { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)},
{ { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, { { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)},
{ { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)}, { { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)},
{ { C_STRING_WITH_LEN("REPLACE_ORACLE") },
BUILDER(Create_func_replace_oracle)},
{ { C_STRING_WITH_LEN("REVERSE") }, BUILDER(Create_func_reverse)}, { { C_STRING_WITH_LEN("REVERSE") }, BUILDER(Create_func_reverse)},
{ { C_STRING_WITH_LEN("ROUND") }, BUILDER(Create_func_round)}, { { C_STRING_WITH_LEN("ROUND") }, BUILDER(Create_func_round)},
{ { C_STRING_WITH_LEN("RPAD") }, BUILDER(Create_func_rpad)}, { { C_STRING_WITH_LEN("RPAD") }, BUILDER(Create_func_rpad)},
......
...@@ -1205,7 +1205,8 @@ void Item_func_reverse::fix_length_and_dec() ...@@ -1205,7 +1205,8 @@ void Item_func_reverse::fix_length_and_dec()
Fix that this works with binary strings when using USE_MB Fix that this works with binary strings when using USE_MB
*/ */
String *Item_func_replace::val_str(String *str) String *Item_func_replace::val_str_internal(String *str,
String *empty_string_for_null)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
String *res,*res2,*res3; String *res,*res2,*res3;
...@@ -1225,8 +1226,11 @@ String *Item_func_replace::val_str(String *str) ...@@ -1225,8 +1226,11 @@ String *Item_func_replace::val_str(String *str)
goto null; goto null;
res2=args[1]->val_str(&tmp_value); res2=args[1]->val_str(&tmp_value);
if (args[1]->null_value) if (args[1]->null_value)
{
if (!empty_string_for_null)
goto null; goto null;
res2= empty_string_for_null;
}
res->set_charset(collation.collation); res->set_charset(collation.collation);
#ifdef USE_MB #ifdef USE_MB
...@@ -1244,7 +1248,11 @@ String *Item_func_replace::val_str(String *str) ...@@ -1244,7 +1248,11 @@ String *Item_func_replace::val_str(String *str)
return res; return res;
#endif #endif
if (!(res3=args[2]->val_str(&tmp_value2))) if (!(res3=args[2]->val_str(&tmp_value2)))
{
if (!empty_string_for_null)
goto null; goto null;
res3= empty_string_for_null;
}
from_length= res2->length(); from_length= res2->length();
to_length= res3->length(); to_length= res3->length();
...@@ -1327,6 +1335,9 @@ String *Item_func_replace::val_str(String *str) ...@@ -1327,6 +1335,9 @@ String *Item_func_replace::val_str(String *str)
} }
while ((offset=res->strstr(*res2,(uint) offset)) >= 0); while ((offset=res->strstr(*res2,(uint) offset)) >= 0);
} }
if (empty_string_for_null && !res->length())
goto null;
return res; return res;
null: null:
......
...@@ -359,14 +359,28 @@ class Item_func_replace :public Item_str_func ...@@ -359,14 +359,28 @@ class Item_func_replace :public Item_str_func
public: public:
Item_func_replace(THD *thd, Item *org, Item *find, Item *replace): Item_func_replace(THD *thd, Item *org, Item *find, Item *replace):
Item_str_func(thd, org, find, replace) {} Item_str_func(thd, org, find, replace) {}
String *val_str(String *); String *val_str(String *to) { return val_str_internal(to, NULL); };
void fix_length_and_dec(); void fix_length_and_dec();
String *val_str_internal(String *str, String *empty_string_for_null);
const char *func_name() const { return "replace"; } const char *func_name() const { return "replace"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_replace>(thd, mem_root, this); } { return get_item_copy<Item_func_replace>(thd, mem_root, this); }
}; };
class Item_func_replace_oracle :public Item_func_replace
{
String tmp_emtpystr;
public:
Item_func_replace_oracle(THD *thd, Item *org, Item *find, Item *replace):
Item_func_replace(thd, org, find, replace) {}
String *val_str(String *to) { return val_str_internal(to, &tmp_emtpystr); };
const char *func_name() const { return "replace_oracle"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_replace_oracle>(thd, mem_root, this); }
};
class Item_func_regexp_replace :public Item_str_func class Item_func_regexp_replace :public Item_str_func
{ {
Regexp_processor_pcre re; Regexp_processor_pcre re;
......
...@@ -7161,3 +7161,14 @@ bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg, ...@@ -7161,3 +7161,14 @@ bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
type= type_arg; type= type_arg;
return false; return false;
} }
Item *LEX::make_item_func_replace(THD *thd,
Item *org,
Item *find,
Item *replace)
{
return (thd->variables.sql_mode & MODE_ORACLE) ?
new (thd->mem_root) Item_func_replace_oracle(thd, org, find, replace) :
new (thd->mem_root) Item_func_replace(thd, org, find, replace);
}
...@@ -3357,6 +3357,8 @@ struct LEX: public Query_tables_list ...@@ -3357,6 +3357,8 @@ struct LEX: public Query_tables_list
const LEX_CSTRING *field_name, const LEX_CSTRING *field_name,
uint pos_in_q, uint length_in_q); uint pos_in_q, uint length_in_q);
Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
/* /*
Create a my_var instance for a ROW field variable that was used Create a my_var instance for a ROW field variable that was used
as an OUT SP parameter: CALL p1(var.field); as an OUT SP parameter: CALL p1(var.field);
......
...@@ -10083,8 +10083,7 @@ function_call_conflict: ...@@ -10083,8 +10083,7 @@ function_call_conflict:
} }
| REPLACE '(' expr ',' expr ',' expr ')' | REPLACE '(' expr ',' expr ',' expr ')'
{ {
$$= new (thd->mem_root) Item_func_replace(thd, $3, $5, $7); if (!($$= Lex->make_item_func_replace(thd, $3, $5, $7)))
if ($$ == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| REVERSE_SYM '(' expr ')' | REVERSE_SYM '(' expr ')'
......
...@@ -10120,8 +10120,7 @@ function_call_conflict: ...@@ -10120,8 +10120,7 @@ function_call_conflict:
} }
| REPLACE '(' expr ',' expr ',' expr ')' | REPLACE '(' expr ',' expr ',' expr ')'
{ {
$$= new (thd->mem_root) Item_func_replace(thd, $3, $5, $7); if (!($$= Lex->make_item_func_replace(thd, $3, $5, $7)))
if ($$ == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| REVERSE_SYM '(' expr ')' | REVERSE_SYM '(' expr ')'
......
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