diff --git a/mysql-test/suite/compat/oracle/r/func_replace.result b/mysql-test/suite/compat/oracle/r/func_replace.result new file mode 100644 index 0000000..358cb8f --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/func_replace.result @@ -0,0 +1,13 @@ +SET sql_mode=ORACLE; +SELECT replace(null,'a','b') from dual; +replace(null,'a','b') +NULL +SELECT replace('ab',null,'b') from dual; +replace('ab',null,'b') +ab +SELECT replace('ab','a',null) from dual; +replace('ab','a',null) +b +SELECT replace('ab',null,null) from dual; +replace('ab',null,null) +ab diff --git a/mysql-test/suite/compat/oracle/t/func_replace.test b/mysql-test/suite/compat/oracle/t/func_replace.test new file mode 100644 index 0000000..57d2f5c --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_replace.test @@ -0,0 +1,10 @@ +# +# Testing replace with null args +# + +SET sql_mode=ORACLE; + +SELECT replace(null,'a','b') from dual; +SELECT replace('ab',null,'b') from dual; +SELECT replace('ab','a',null) from dual; +SELECT replace('ab',null,null) from dual; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c88afce..447648c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1199,8 +1199,24 @@ void Item_func_reverse::fix_length_and_dec() String *Item_func_replace::val_str(String *str) { + + if (args[1]->null_value) + { + null_value= 1; + return 0; + } + return replace_value(str, + args[1]->val_str(&tmp_value), + args[2]->val_str(&tmp_value2)); +} + + +String *Item_func_replace::replace_value(String *str, + String *res2, + String *res3) +{ DBUG_ASSERT(fixed == 1); - String *res,*res2,*res3; + String *res; int offset; uint from_length,to_length; bool alloced=0; @@ -1215,9 +1231,6 @@ String *Item_func_replace::val_str(String *str) res=args[0]->val_str(str); if (args[0]->null_value) goto null; - res2=args[1]->val_str(&tmp_value); - if (args[1]->null_value) - goto null; res->set_charset(collation.collation); @@ -1235,7 +1248,7 @@ String *Item_func_replace::val_str(String *str) if (binary_cmp && (offset=res->strstr(*res2)) < 0) return res; #endif - if (!(res3=args[2]->val_str(&tmp_value2))) + if (!res3) goto null; from_length= res2->length(); to_length= res3->length(); @@ -1343,6 +1356,24 @@ void Item_func_replace::fix_length_and_dec() } +String *Item_func_replace_oracle::val_str(String *str) +{ + String *res; + String *str2= args[1]->val_str(&tmp_value2); + String *str3= args[2]->val_str(&tmp_value3); + + if ((res = replace_value(str, + str2 ? str2 : &tmp_emtpystr, + str3 ? str3 : &tmp_emtpystr))) + { + if (res->length()) + return res ; + } + null_value= 1; + return 0; +} + + /*********************************************************************/ void Item_func_regexp_replace::fix_length_and_dec() { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 854a692..c340e32 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -364,11 +364,25 @@ class Item_func_replace :public Item_str_func Item_str_func(thd, org, find, replace) {} String *val_str(String *); void fix_length_and_dec(); + String *replace_value(String *str, String *res2, String *res3); const char *func_name() const { return "replace"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; +class Item_func_replace_oracle :public Item_func_replace +{ + String tmp_value2, tmp_value3, 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 *); + void fix_args(THD *thd, Item *org, Item *find, Item *replace); + const char *func_name() const { return "replace_oracle"; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + class Item_func_regexp_replace :public Item_str_func { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index dad438d..6d16b21 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7040,3 +7040,13 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name) return true; 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); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b90d340..f65f8a1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3596,6 +3596,9 @@ struct LEX: public Query_tables_list SELECT_LEX *exclude_last_select(); bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); + + Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace); + }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 59c0450..0eef2b5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9963,8 +9963,7 @@ function_call_conflict: } | REPLACE '(' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_replace(thd, $3, $5, $7); - if ($$ == NULL) + if (!($$= Lex->make_item_func_replace(thd, $3, $5, $7))) MYSQL_YYABORT; } | REVERSE_SYM '(' expr ')' diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 77ced40..e18c62d 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -10054,8 +10054,7 @@ function_call_conflict: } | REPLACE '(' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_replace(thd, $3, $5, $7); - if ($$ == NULL) + if (!($$= Lex->make_item_func_replace(thd, $3, $5, $7))) MYSQL_YYABORT; } | REVERSE_SYM '(' expr ')'