summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhalfspawn <j.brauge@qualiac.com>2017-05-31 09:49:17 +0200
committerAlexander Barkov <bar@mariadb.org>2017-08-11 14:47:36 +0400
commitc9981fbee2436dcb893ff74e57a0f461a2020f92 (patch)
tree17bd91cbd8503834a22eb833fb6768d23c174823
parent1a9e13d622382285d979e75774bdd1dde1660e2d (diff)
downloadmariadb-git-c9981fbee2436dcb893ff74e57a0f461a2020f92.tar.gz
MDEV-13003 - Oracle compatibility : Replace function
-rw-r--r--mysql-test/suite/compat/oracle/r/func_replace.result32
-rw-r--r--mysql-test/suite/compat/oracle/t/func_replace.test22
-rw-r--r--sql/item_create.cc27
-rw-r--r--sql/item_strfunc.cc19
-rw-r--r--sql/item_strfunc.h16
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--sql/sql_yacc_ora.yy3
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 ')'