diff options
author | halfspawn <j.brauge@qualiac.com> | 2017-05-31 09:49:17 +0200 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-08-11 14:47:36 +0400 |
commit | c9981fbee2436dcb893ff74e57a0f461a2020f92 (patch) | |
tree | 17bd91cbd8503834a22eb833fb6768d23c174823 | |
parent | 1a9e13d622382285d979e75774bdd1dde1660e2d (diff) | |
download | mariadb-git-c9981fbee2436dcb893ff74e57a0f461a2020f92.tar.gz |
MDEV-13003 - Oracle compatibility : Replace function
-rw-r--r-- | mysql-test/suite/compat/oracle/r/func_replace.result | 32 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/func_replace.test | 22 | ||||
-rw-r--r-- | sql/item_create.cc | 27 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 19 | ||||
-rw-r--r-- | sql/item_strfunc.h | 16 | ||||
-rw-r--r-- | sql/sql_lex.cc | 11 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 3 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 3 |
9 files changed, 125 insertions, 10 deletions
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 00000000000..02516096286 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/func_replace.result @@ -0,0 +1,32 @@ +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; 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 00000000000..0028f7d27cf --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_replace.test @@ -0,0 +1,22 @@ +# +# 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; diff --git a/sql/item_create.cc b/sql/item_create.cc index 50f524bad40..e0bfe7a4402 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2624,6 +2624,19 @@ protected: }; +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 { public: @@ -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; Item* @@ -6802,6 +6825,7 @@ static Native_func_registry func_array[] = { { 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("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("COLUMN_CHECK") }, BUILDER(Create_func_dyncol_check)}, { { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)}, @@ -6815,7 +6839,6 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)}, { { 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("CHR") }, BUILDER(Create_func_chr)}, { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)}, { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)}, { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)}, @@ -6990,6 +7013,8 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, { { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, { { 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("ROUND") }, BUILDER(Create_func_round)}, { { C_STRING_WITH_LEN("RPAD") }, BUILDER(Create_func_rpad)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4852a9cb425..3b1dbf57fc4 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1205,7 +1205,8 @@ void Item_func_reverse::fix_length_and_dec() 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); String *res,*res2,*res3; @@ -1225,8 +1226,11 @@ String *Item_func_replace::val_str(String *str) goto null; res2=args[1]->val_str(&tmp_value); if (args[1]->null_value) - goto null; - + { + if (!empty_string_for_null) + goto null; + res2= empty_string_for_null; + } res->set_charset(collation.collation); #ifdef USE_MB @@ -1244,7 +1248,11 @@ String *Item_func_replace::val_str(String *str) return res; #endif if (!(res3=args[2]->val_str(&tmp_value2))) - goto null; + { + if (!empty_string_for_null) + goto null; + res3= empty_string_for_null; + } from_length= res2->length(); to_length= res3->length(); @@ -1327,6 +1335,9 @@ redo: } while ((offset=res->strstr(*res2,(uint) offset)) >= 0); } + if (empty_string_for_null && !res->length()) + goto null; + return res; null: diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index ab2d183dbe5..c022282ab30 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -359,14 +359,28 @@ class Item_func_replace :public Item_str_func public: Item_func_replace(THD *thd, Item *org, Item *find, Item *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(); + String *val_str_internal(String *str, String *empty_string_for_null); const char *func_name() const { return "replace"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { 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 { Regexp_processor_pcre re; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 034cb62bbf4..f9c335e04bd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7161,3 +7161,14 @@ bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg, type= type_arg; 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 6bd7f78822c..e404af4afd9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3357,6 +3357,8 @@ public: const LEX_CSTRING *field_name, 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 as an OUT SP parameter: CALL p1(var.field); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e7ea40ca334..49eda48c451 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10083,8 +10083,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 9a5ebe45468..80c9375e777 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -10120,8 +10120,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 ')' |