diff options
author | Alexander Barkov <bar@mariadb.org> | 2016-09-17 08:24:05 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-04-05 15:02:48 +0400 |
commit | 30bec863cf710f9135439f410e1c31e4df873fd1 (patch) | |
tree | 6f78961390733bfadec431053e9f909eeb88e2b5 | |
parent | 7e7ba7cb948910e138922d6524cc125f9aa02848 (diff) | |
download | mariadb-git-30bec863cf710f9135439f410e1c31e4df873fd1.tar.gz |
MDEV-10342 Providing compatibility for basic SQL built-in functions
Adding functions NVL() and NVL2().
-rw-r--r-- | mysql-test/suite/compat/oracle/r/func_case.result | 7 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/func_case.test | 9 | ||||
-rw-r--r-- | sql/item.h | 41 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 85 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 110 | ||||
-rw-r--r-- | sql/item_create.cc | 24 |
6 files changed, 183 insertions, 93 deletions
diff --git a/mysql-test/suite/compat/oracle/r/func_case.result b/mysql-test/suite/compat/oracle/r/func_case.result new file mode 100644 index 00000000000..dfe2d165b88 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/func_case.result @@ -0,0 +1,7 @@ +SET sql_mode=ORACLE; +SELECT NVL(NULL, 'a'), NVL('a', 'b'); +NVL(NULL, 'a') NVL('a', 'b') +a a +SELECT NVL2(NULL, 'a', 'b'), NVL2('a', 'b', 'c'); +NVL2(NULL, 'a', 'b') NVL2('a', 'b', 'c') +b b diff --git a/mysql-test/suite/compat/oracle/t/func_case.test b/mysql-test/suite/compat/oracle/t/func_case.test new file mode 100644 index 00000000000..d5e0d650975 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_case.test @@ -0,0 +1,9 @@ +# +# Testing CASE and its abbreviations +# + +SET sql_mode=ORACLE; + +SELECT NVL(NULL, 'a'), NVL('a', 'b'); + +SELECT NVL2(NULL, 'a', 'b'), NVL2('a', 'b', 'c'); diff --git a/sql/item.h b/sql/item.h index 6f22c05b308..a02cf8f0d57 100644 --- a/sql/item.h +++ b/sql/item.h @@ -543,6 +543,47 @@ protected: void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); + + /* Helper methods, to get an Item value from another Item */ + double val_real_from_item(Item *item) + { + DBUG_ASSERT(fixed == 1); + double value= item->val_real(); + null_value= item->null_value; + return value; + } + longlong val_int_from_item(Item *item) + { + DBUG_ASSERT(fixed == 1); + longlong value= item->val_int(); + null_value= item->null_value; + return value; + } + String *val_str_from_item(Item *item, String *str) + { + DBUG_ASSERT(fixed == 1); + String *res= item->val_str(str); + if (res) + res->set_charset(collation.collation); + if ((null_value= item->null_value)) + res= NULL; + return res; + } + my_decimal *val_decimal_from_item(Item *item, my_decimal *decimal_value) + { + DBUG_ASSERT(fixed == 1); + my_decimal *value= item->val_decimal(decimal_value); + if ((null_value= item->null_value)) + value= NULL; + return value; + } + bool get_date_with_conversion_from_item(Item *item, + MYSQL_TIME *ltime, uint fuzzydate) + { + DBUG_ASSERT(fixed == 1); + return (null_value= item->get_date_with_conversion(ltime, fuzzydate)); + } + public: /* Cache val_str() into the own buffer, e.g. to evaluate constant diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7457708948f..f5ba6f206c2 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2365,91 +2365,6 @@ void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref) } -void Item_func_if::cache_type_info(Item *source) -{ - Type_std_attributes::set(source); - set_handler_by_field_type(source->field_type()); - maybe_null= source->maybe_null; -} - - -void -Item_func_if::fix_length_and_dec() -{ - // Let IF(cond, expr, NULL) and IF(cond, NULL, expr) inherit type from expr. - if (args[1]->type() == NULL_ITEM) - { - cache_type_info(args[2]); - maybe_null= true; - // If both arguments are NULL, make resulting type BINARY(0). - if (args[2]->type() == NULL_ITEM) - set_handler_by_field_type(MYSQL_TYPE_STRING); - return; - } - if (args[2]->type() == NULL_ITEM) - { - cache_type_info(args[1]); - maybe_null= true; - return; - } - Item_func_case_abbreviation2::fix_length_and_dec2(args + 1); -} - - -double -Item_func_if::real_op() -{ - DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_bool() ? args[1] : args[2]; - double value= arg->val_real(); - null_value=arg->null_value; - return value; -} - -longlong -Item_func_if::int_op() -{ - DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_bool() ? args[1] : args[2]; - longlong value=arg->val_int(); - null_value=arg->null_value; - return value; -} - -String * -Item_func_if::str_op(String *str) -{ - DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_bool() ? args[1] : args[2]; - String *res=arg->val_str(str); - if (res) - res->set_charset(collation.collation); - if ((null_value=arg->null_value)) - res= NULL; - return res; -} - - -my_decimal * -Item_func_if::decimal_op(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_bool() ? args[1] : args[2]; - my_decimal *value= arg->val_decimal(decimal_value); - if ((null_value= arg->null_value)) - value= NULL; - return value; -} - - -bool Item_func_if::date_op(MYSQL_TIME *ltime, uint fuzzydate) -{ - DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_bool() ? args[1] : args[2]; - return (null_value= arg->get_date_with_conversion(ltime, fuzzydate)); -} - - void Item_func_nullif::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2af4a32d844..a94105b352d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -993,6 +993,7 @@ public: Case abbreviations that aggregate its result field type by two arguments: IFNULL(arg1, arg2) IF(switch, arg1, arg2) + NVL2(switch, arg1, arg2) */ class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type { @@ -1003,6 +1004,34 @@ protected: fix_attributes(items, 2); } uint decimal_precision2(Item **args) const; + + void cache_type_info(const Item *source, bool maybe_null_arg) + { + Type_std_attributes::set(source); + set_handler_by_field_type(source->field_type()); + maybe_null= maybe_null_arg; + } + + void fix_length_and_dec2_eliminate_null(Item **items) + { + // Let IF(cond, expr, NULL) and IF(cond, NULL, expr) inherit type from expr. + if (items[0]->type() == NULL_ITEM) + { + cache_type_info(items[1], true); + // If both arguments are NULL, make resulting type BINARY(0). + if (items[1]->type() == NULL_ITEM) + set_handler_by_field_type(MYSQL_TYPE_STRING); + } + else if (items[1]->type() == NULL_ITEM) + { + cache_type_info(items[0], true); + } + else + { + fix_length_and_dec2(items); + } + } + public: Item_func_case_abbreviation2(THD *thd, Item *a, Item *b): Item_func_hybrid_field_type(thd, a, b) { } @@ -1040,19 +1069,61 @@ public: }; -class Item_func_if :public Item_func_case_abbreviation2 +/** + Case abbreviations that have a switch argument and + two return arguments to choose from. Returns the value + of either of the two return arguments depending on the switch argument value. + + IF(switch, arg1, arg2) + NVL(switch, arg1, arg2) +*/ +class Item_func_case_abbreviation2_switch: public Item_func_case_abbreviation2 { +protected: + virtual Item *find_item() const= 0; + +public: + Item_func_case_abbreviation2_switch(THD *thd, Item *a, Item *b, Item *c) + :Item_func_case_abbreviation2(thd, a, b, c) + { } + + bool date_op(MYSQL_TIME *ltime, uint fuzzydate) + { + return get_date_with_conversion_from_item(find_item(), ltime, fuzzydate); + } + longlong int_op() + { + return val_int_from_item(find_item()); + } + double real_op() + { + return val_real_from_item(find_item()); + } + my_decimal *decimal_op(my_decimal *decimal_value) + { + return val_decimal_from_item(find_item(), decimal_value); + } + String *str_op(String *str) + { + return val_str_from_item(find_item(), str); + } +}; + + +class Item_func_if :public Item_func_case_abbreviation2_switch +{ +protected: + Item *find_item() const { return args[0]->val_bool() ? args[1] : args[2]; } + public: Item_func_if(THD *thd, Item *a, Item *b, Item *c): - Item_func_case_abbreviation2(thd, a, b, c) + Item_func_case_abbreviation2_switch(thd, a, b, c) {} - bool date_op(MYSQL_TIME *ltime, uint fuzzydate); - longlong int_op(); - double real_op(); - my_decimal *decimal_op(my_decimal *); - String *str_op(String *); bool fix_fields(THD *, Item **); - void fix_length_and_dec(); + void fix_length_and_dec() + { + fix_length_and_dec2_eliminate_null(args + 1); + } uint decimal_precision() const { return Item_func_case_abbreviation2::decimal_precision2(args + 1); @@ -1067,6 +1138,29 @@ private: }; +class Item_func_nvl2 :public Item_func_case_abbreviation2_switch +{ +protected: + Item *find_item() const { return args[0]->is_null() ? args[2] : args[1]; } + +public: + Item_func_nvl2(THD *thd, Item *a, Item *b, Item *c): + Item_func_case_abbreviation2_switch(thd, a, b, c) + {} + const char *func_name() const { return "nvl2"; } + void fix_length_and_dec() + { + fix_length_and_dec2_eliminate_null(args + 1); + } + uint decimal_precision() const + { + return Item_func_case_abbreviation2::decimal_precision2(args + 1); + } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_func_nvl2>(thd, mem_root, this); } +}; + + class Item_func_nullif :public Item_func_hybrid_field_type { Arg_comparator cmp; diff --git a/sql/item_create.cc b/sql/item_create.cc index 455da1f5ba5..978459acf0e 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -711,6 +711,19 @@ protected: #endif +class Create_func_nvl2 : public Create_func_arg3 +{ +public: + virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3); + + static Create_func_nvl2 s_singleton; + +protected: + Create_func_nvl2() {} + virtual ~Create_func_nvl2() {} +}; + + class Create_func_conv : public Create_func_arg3 { public: @@ -3931,6 +3944,15 @@ Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2) #endif +Create_func_nvl2 Create_func_nvl2::s_singleton; + +Item* +Create_func_nvl2::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) +{ + return new (thd->mem_root) Item_func_nvl2(thd, arg1, arg2, arg3); +} + + Create_func_conv Create_func_conv::s_singleton; Item* @@ -6884,6 +6906,8 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { C_STRING_WITH_LEN("NAME_CONST") }, BUILDER(Create_func_name_const)}, + { { C_STRING_WITH_LEN("NVL") }, BUILDER(Create_func_ifnull)}, + { { C_STRING_WITH_LEN("NVL2") }, BUILDER(Create_func_nvl2)}, { { C_STRING_WITH_LEN("NULLIF") }, BUILDER(Create_func_nullif)}, { { C_STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)}, { { C_STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)}, |