Commit 30bec863 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10342 Providing compatibility for basic SQL built-in functions

Adding functions NVL() and NVL2().
parent 7e7ba7cb
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
#
# 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');
...@@ -543,6 +543,47 @@ class Item: public Value_source, ...@@ -543,6 +543,47 @@ class Item: public Value_source,
void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_negative_complement(THD *thd);
void push_note_converted_to_positive_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: public:
/* /*
Cache val_str() into the own buffer, e.g. to evaluate constant Cache val_str() into the own buffer, e.g. to evaluate constant
......
...@@ -2365,91 +2365,6 @@ void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref) ...@@ -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, void Item_func_nullif::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags) List<Item> &fields, uint flags)
{ {
......
...@@ -993,6 +993,7 @@ class Item_func_coalesce :public Item_func_hybrid_field_type ...@@ -993,6 +993,7 @@ class Item_func_coalesce :public Item_func_hybrid_field_type
Case abbreviations that aggregate its result field type by two arguments: Case abbreviations that aggregate its result field type by two arguments:
IFNULL(arg1, arg2) IFNULL(arg1, arg2)
IF(switch, arg1, arg2) IF(switch, arg1, arg2)
NVL2(switch, arg1, arg2)
*/ */
class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type
{ {
...@@ -1003,6 +1004,34 @@ class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type ...@@ -1003,6 +1004,34 @@ class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type
fix_attributes(items, 2); fix_attributes(items, 2);
} }
uint decimal_precision2(Item **args) const; 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: public:
Item_func_case_abbreviation2(THD *thd, Item *a, Item *b): Item_func_case_abbreviation2(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b) { } Item_func_hybrid_field_type(thd, a, b) { }
...@@ -1040,19 +1069,61 @@ class Item_func_ifnull :public Item_func_case_abbreviation2 ...@@ -1040,19 +1069,61 @@ class Item_func_ifnull :public Item_func_case_abbreviation2
}; };
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: public:
Item_func_if(THD *thd, Item *a, Item *b, Item *c): 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 **); 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 uint decimal_precision() const
{ {
return Item_func_case_abbreviation2::decimal_precision2(args + 1); return Item_func_case_abbreviation2::decimal_precision2(args + 1);
...@@ -1067,6 +1138,29 @@ class Item_func_if :public Item_func_case_abbreviation2 ...@@ -1067,6 +1138,29 @@ class Item_func_if :public Item_func_case_abbreviation2
}; };
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 class Item_func_nullif :public Item_func_hybrid_field_type
{ {
Arg_comparator cmp; Arg_comparator cmp;
......
...@@ -711,6 +711,19 @@ class Create_func_contains : public Create_func_arg2 ...@@ -711,6 +711,19 @@ class Create_func_contains : public Create_func_arg2
#endif #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 class Create_func_conv : public Create_func_arg3
{ {
public: public:
...@@ -3931,6 +3944,15 @@ Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2) ...@@ -3931,6 +3944,15 @@ Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
#endif #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; Create_func_conv Create_func_conv::s_singleton;
Item* Item*
...@@ -6884,6 +6906,8 @@ static Native_func_registry func_array[] = ...@@ -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("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { 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("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("NULLIF") }, BUILDER(Create_func_nullif)},
{ { C_STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)}, { { C_STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
{ { C_STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)}, { { C_STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment