From c8822d71efd426902db6f8096037a1ad9d61b3fe Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 19 Sep 2016 11:39:36 +0400 Subject: [PATCH] MDEV-10342 Providing compatibility for basic SQL built-in functions Adding the Oracle style DECODE function: DECODE(operand, search, result [, search, result ...] [, default_result]) --- mysql-test/r/keywords.result | 2 + .../suite/compat/oracle/r/func_decode.result | 33 ++++++++++++ .../suite/compat/oracle/t/func_decode.test | 21 ++++++++ mysql-test/t/keywords.test | 3 ++ sql/item_create.cc | 23 --------- sql/lex.h | 1 + sql/sql_yacc.yy | 8 +++ sql/sql_yacc_ora.yy | 51 +++++++++++++++++++ 8 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 mysql-test/suite/compat/oracle/r/func_decode.result create mode 100644 mysql-test/suite/compat/oracle/t/func_decode.test diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result index 7031adcca8f..d9b8d911ef4 100644 --- a/mysql-test/r/keywords.result +++ b/mysql-test/r/keywords.result @@ -346,3 +346,5 @@ CREATE TABLE raw (raw int); DROP TABLE raw; CREATE TABLE varchar2 (varchar2 int); DROP TABLE varchar2; +CREATE TABLE decode (decode int); +DROP TABLE decode; diff --git a/mysql-test/suite/compat/oracle/r/func_decode.result b/mysql-test/suite/compat/oracle/r/func_decode.result new file mode 100644 index 00000000000..a7c0ffdc264 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/func_decode.result @@ -0,0 +1,33 @@ +SET sql_mode=ORACLE; +SELECT DECODE(10); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1 +SELECT DECODE(10,10); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1 +SELECT DECODE(10,10,'x10'); +DECODE(10,10,'x10') +x10 +SELECT DECODE(11,10,'x10'); +DECODE(11,10,'x10') +NULL +SELECT DECODE(10,10,'x10','def'); +DECODE(10,10,'x10','def') +x10 +SELECT DECODE(11,10,'x10','def'); +DECODE(11,10,'x10','def') +def +SELECT DECODE(10,10,'x10',11,'x11','def'); +DECODE(10,10,'x10',11,'x11','def') +x10 +SELECT DECODE(11,10,'x10',11,'x11','def'); +DECODE(11,10,'x10',11,'x11','def') +x11 +SELECT DECODE(12,10,'x10',11,'x11','def'); +DECODE(12,10,'x10',11,'x11','def') +def +EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def'); +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 (case 12 when 10 then 'x10' when 11 then 'x11' else 'def' end) AS "DECODE(12,10,'x10',11,'x11','def')" +CREATE TABLE decode (decode int); +DROP TABLE decode; diff --git a/mysql-test/suite/compat/oracle/t/func_decode.test b/mysql-test/suite/compat/oracle/t/func_decode.test new file mode 100644 index 00000000000..ae05cb2c3d1 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_decode.test @@ -0,0 +1,21 @@ +SET sql_mode=ORACLE; + +--error ER_PARSE_ERROR +SELECT DECODE(10); +--error ER_PARSE_ERROR +SELECT DECODE(10,10); + +SELECT DECODE(10,10,'x10'); +SELECT DECODE(11,10,'x10'); + +SELECT DECODE(10,10,'x10','def'); +SELECT DECODE(11,10,'x10','def'); + +SELECT DECODE(10,10,'x10',11,'x11','def'); +SELECT DECODE(11,10,'x10',11,'x11','def'); +SELECT DECODE(12,10,'x10',11,'x11','def'); + +EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def'); + +CREATE TABLE decode (decode int); +DROP TABLE decode; diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test index b0b85539ee7..b9e52ab8308 100644 --- a/mysql-test/t/keywords.test +++ b/mysql-test/t/keywords.test @@ -241,3 +241,6 @@ DROP TABLE raw; CREATE TABLE varchar2 (varchar2 int); DROP TABLE varchar2; + +CREATE TABLE decode (decode int); +DROP TABLE decode; diff --git a/sql/item_create.cc b/sql/item_create.cc index 978459acf0e..6b0a8d2c87f 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -882,19 +882,6 @@ protected: }; -class Create_func_decode : public Create_func_arg2 -{ -public: - virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); - - static Create_func_decode s_singleton; - -protected: - Create_func_decode() {} - virtual ~Create_func_decode() {} -}; - - class Create_func_degrees : public Create_func_arg1 { public: @@ -4067,15 +4054,6 @@ Create_func_dayofyear::create_1_arg(THD *thd, Item *arg1) } -Create_func_decode Create_func_decode::s_singleton; - -Item* -Create_func_decode::create_2_arg(THD *thd, Item *arg1, Item *arg2) -{ - return new (thd->mem_root) Item_func_decode(thd, arg1, arg2); -} - - Create_func_degrees Create_func_degrees::s_singleton; Item* @@ -6772,7 +6750,6 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("DAYOFMONTH") }, BUILDER(Create_func_dayofmonth)}, { { C_STRING_WITH_LEN("DAYOFWEEK") }, BUILDER(Create_func_dayofweek)}, { { C_STRING_WITH_LEN("DAYOFYEAR") }, BUILDER(Create_func_dayofyear)}, - { { C_STRING_WITH_LEN("DECODE") }, BUILDER(Create_func_decode)}, { { C_STRING_WITH_LEN("DEGREES") }, BUILDER(Create_func_degrees)}, { { C_STRING_WITH_LEN("DECODE_HISTOGRAM") }, BUILDER(Create_func_decode_histogram)}, { { C_STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)}, diff --git a/sql/lex.h b/sql/lex.h index d258c9bac5b..8e946853c24 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -705,6 +705,7 @@ static SYMBOL sql_functions[] = { { "CURTIME", SYM(CURTIME)}, { "DATE_ADD", SYM(DATE_ADD_INTERVAL)}, { "DATE_SUB", SYM(DATE_SUB_INTERVAL)}, + { "DECODE", SYM(DECODE_SYM)}, { "DENSE_RANK", SYM(DENSE_RANK_SYM)}, { "EXTRACT", SYM(EXTRACT_SYM)}, { "FIRST_VALUE", SYM(FIRST_VALUE_SYM)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dd5b1f8cdfc..4edaa141326 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1041,6 +1041,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token DECIMAL_NUM %token DECIMAL_SYM /* SQL-2003-R */ %token DECLARE_SYM /* SQL-2003-R */ +%token DECODE_SYM /* Oracle function, non-reserved */ %token DEFAULT /* SQL-2003-R */ %token DEFINER_SYM %token DELAYED_SYM @@ -9370,6 +9371,12 @@ function_call_nonkeyword: if ($$ == NULL) MYSQL_YYABORT; } + | DECODE_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_decode(thd, $3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | EXTRACT_SYM '(' interval FROM expr ')' { $$=new (thd->mem_root) Item_extract(thd, $3, $5); @@ -14279,6 +14286,7 @@ keyword_sp: | DATETIME {} | DATE_SYM {} | DAY_SYM {} + | DECODE_SYM {} | DEFINER_SYM {} | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {} diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 417a140a918..72e5a16cc7d 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -415,6 +415,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token DECIMAL_NUM %token DECIMAL_SYM /* SQL-2003-R */ %token DECLARE_SYM /* SQL-2003-R */ +%token DECODE_SYM /* Oracle function, non-reserved */ %token DEFAULT /* SQL-2003-R */ %token DEFINER_SYM %token DELAYED_SYM @@ -1118,6 +1119,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type expr_list opt_udf_expr_list udf_expr_list when_list ident_list ident_list_arg opt_expr_list + decode_when_list %type option_type opt_var_type opt_var_ident_type @@ -8850,6 +8852,36 @@ column_default_non_parenthesized_expr: if ($$ == NULL) MYSQL_YYABORT; } + | DECODE_SYM '(' expr ',' decode_when_list ')' + { + if (($5->elements % 2) == 0) + { + // No default expression + $$= new (thd->mem_root) Item_func_case(thd, *$5, $3, NULL); + } + else + { + /* + There is a default expression at the end of the list $5. + Create a new list without the default expression. + */ + List tmp; + List_iterator_fast it(*$5); + for (uint i= 0; i < $5->elements - 1; i++) // copy all but last + { + Item *item= it++; + tmp.push_back(item); + } + /* + Now the new list "tmp" contains only WHEN-THEN pairs, + The default expression is pointed by the iterator "it" + and will be returned by the next call for it++ below. + */ + $$= new (thd->mem_root) Item_func_case(thd, tmp, $3, it++); + } + if ($$ == NULL) + MYSQL_YYABORT; + } | DEFAULT '(' simple_ident ')' { Item_splocal *il= $3->get_item_splocal(); @@ -10246,6 +10278,24 @@ when_list: } ; + +decode_when_list: + expr ',' expr + { + $$= new (thd->mem_root) List; + if ($$ == NULL) + MYSQL_YYABORT; + $$->push_back($1, thd->mem_root); + $$->push_back($3, thd->mem_root); + } + | decode_when_list ',' expr + { + $$= $1; + $$->push_back($3, thd->mem_root); + } + ; + + /* Equivalent to in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ table_ref: @@ -14190,6 +14240,7 @@ keyword_sp: | DATETIME {} | DATE_SYM {} | DAY_SYM {} + | DECODE_SYM {} | DEFINER_SYM {} | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {}