Commit 01b308c3 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12617 CASE and CASE-alike hybrid functions do not preserve exact data types

parent 78a891c8
This diff is collapsed.
...@@ -613,22 +613,22 @@ FROM t1; ...@@ -613,22 +613,22 @@ FROM t1;
SHOW CREATE TABLE t2; SHOW CREATE TABLE t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
`NULLIF(c_tinyint, 1)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, 1)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_smallint)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_smallint)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_tinyint)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_tinyint)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_int)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_int)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_bigint)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_bigint)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_float)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_float)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_double)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_double)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_decimal103)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_decimal103)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_varchar10)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_varchar10)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_text)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_text)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_blob)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_blob)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_enum)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_enum)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_datetime3)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_datetime3)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_timestamp3)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_timestamp3)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_date)` int(4) DEFAULT NULL, `NULLIF(c_tinyint, c_date)` tinyint(4) DEFAULT NULL,
`NULLIF(c_tinyint, c_time)` int(4) DEFAULT NULL `NULLIF(c_tinyint, c_time)` tinyint(4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2; DROP TABLE t2;
CREATE TABLE t2 AS SELECT CREATE TABLE t2 AS SELECT
...@@ -652,22 +652,22 @@ FROM t1; ...@@ -652,22 +652,22 @@ FROM t1;
SHOW CREATE TABLE t2; SHOW CREATE TABLE t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
`NULLIF(c_smallint, 1)` int(6) DEFAULT NULL, `NULLIF(c_smallint, 1)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_smallint)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_smallint)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_tinyint)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_tinyint)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_int)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_int)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_bigint)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_bigint)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_float)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_float)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_double)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_double)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_decimal103)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_decimal103)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_varchar10)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_varchar10)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_text)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_text)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_blob)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_blob)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_enum)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_enum)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_datetime3)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_datetime3)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_timestamp3)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_timestamp3)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_date)` int(6) DEFAULT NULL, `NULLIF(c_smallint, c_date)` smallint(6) DEFAULT NULL,
`NULLIF(c_smallint, c_time)` int(6) DEFAULT NULL `NULLIF(c_smallint, c_time)` smallint(6) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2; DROP TABLE t2;
CREATE TABLE t2 AS SELECT CREATE TABLE t2 AS SELECT
...@@ -769,22 +769,22 @@ FROM t1; ...@@ -769,22 +769,22 @@ FROM t1;
SHOW CREATE TABLE t2; SHOW CREATE TABLE t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
`NULLIF(c_float, 1)` double DEFAULT NULL, `NULLIF(c_float, 1)` float DEFAULT NULL,
`NULLIF(c_float, c_smallint)` double DEFAULT NULL, `NULLIF(c_float, c_smallint)` float DEFAULT NULL,
`NULLIF(c_float, c_tinyint)` double DEFAULT NULL, `NULLIF(c_float, c_tinyint)` float DEFAULT NULL,
`NULLIF(c_float, c_int)` double DEFAULT NULL, `NULLIF(c_float, c_int)` float DEFAULT NULL,
`NULLIF(c_float, c_bigint)` double DEFAULT NULL, `NULLIF(c_float, c_bigint)` float DEFAULT NULL,
`NULLIF(c_float, c_float)` double DEFAULT NULL, `NULLIF(c_float, c_float)` float DEFAULT NULL,
`NULLIF(c_float, c_double)` double DEFAULT NULL, `NULLIF(c_float, c_double)` float DEFAULT NULL,
`NULLIF(c_float, c_decimal103)` double DEFAULT NULL, `NULLIF(c_float, c_decimal103)` float DEFAULT NULL,
`NULLIF(c_float, c_varchar10)` double DEFAULT NULL, `NULLIF(c_float, c_varchar10)` float DEFAULT NULL,
`NULLIF(c_float, c_text)` double DEFAULT NULL, `NULLIF(c_float, c_text)` float DEFAULT NULL,
`NULLIF(c_float, c_blob)` double DEFAULT NULL, `NULLIF(c_float, c_blob)` float DEFAULT NULL,
`NULLIF(c_float, c_enum)` double DEFAULT NULL, `NULLIF(c_float, c_enum)` float DEFAULT NULL,
`NULLIF(c_float, c_datetime3)` double DEFAULT NULL, `NULLIF(c_float, c_datetime3)` float DEFAULT NULL,
`NULLIF(c_float, c_timestamp3)` double DEFAULT NULL, `NULLIF(c_float, c_timestamp3)` float DEFAULT NULL,
`NULLIF(c_float, c_date)` double DEFAULT NULL, `NULLIF(c_float, c_date)` float DEFAULT NULL,
`NULLIF(c_float, c_time)` double DEFAULT NULL `NULLIF(c_float, c_time)` float DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2; DROP TABLE t2;
CREATE TABLE t2 AS SELECT CREATE TABLE t2 AS SELECT
......
...@@ -510,6 +510,29 @@ SHOW CREATE TABLE t2; ...@@ -510,6 +510,29 @@ SHOW CREATE TABLE t2;
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-12617 CASE and CASE-alike hybrid functions do not preserve exact data types
--echo #
CREATE TABLE t1 (a FLOAT(10,2));
CREATE TABLE t2 AS SELECT COALESCE(a) FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2, t1;
CREATE TABLE t1 (a FLOAT(10,2));
CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2, t1;
CREATE TABLE t1 (a TINYINT(1));
CREATE TABLE t2 AS SELECT COALESCE(a) FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2, t1;
CREATE TABLE t1 (a TINYINT(1));
CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2, t1;
--echo # --echo #
--echo # End of 10.3 tests --echo # End of 10.3 tests
......
...@@ -2786,7 +2786,7 @@ Item_func_nullif::is_null() ...@@ -2786,7 +2786,7 @@ Item_func_nullif::is_null()
Item_func_case::Item_func_case(THD *thd, List<Item> &list, Item_func_case::Item_func_case(THD *thd, List<Item> &list,
Item *first_expr_arg, Item *else_expr_arg): Item *first_expr_arg, Item *else_expr_arg):
Item_func_hybrid_field_type(thd), Item_func_case_expression(thd),
Predicant_to_list_comparator(thd, list.elements/*QQ*/), Predicant_to_list_comparator(thd, list.elements/*QQ*/),
first_expr_num(-1), else_expr_num(-1), first_expr_num(-1), else_expr_num(-1),
left_cmp_type(INT_RESULT), m_found_types(0) left_cmp_type(INT_RESULT), m_found_types(0)
......
...@@ -965,13 +965,13 @@ class Item_func_interval :public Item_int_func ...@@ -965,13 +965,13 @@ class Item_func_interval :public Item_int_func
}; };
class Item_func_coalesce :public Item_func_hybrid_field_type class Item_func_coalesce :public Item_func_case_expression
{ {
public: public:
Item_func_coalesce(THD *thd, Item *a, Item *b): Item_func_coalesce(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b) {} Item_func_case_expression(thd, a, b) {}
Item_func_coalesce(THD *thd, List<Item> &list): Item_func_coalesce(THD *thd, List<Item> &list):
Item_func_hybrid_field_type(thd, list) {} Item_func_case_expression(thd, list) {}
double real_op(); double real_op();
longlong int_op(); longlong int_op();
String *str_op(String *); String *str_op(String *);
...@@ -995,7 +995,7 @@ class Item_func_coalesce :public Item_func_hybrid_field_type ...@@ -995,7 +995,7 @@ class Item_func_coalesce :public Item_func_hybrid_field_type
IF(switch, arg1, arg2) IF(switch, arg1, arg2)
NVL2(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_case_expression
{ {
protected: protected:
void fix_length_and_dec2(Item **items) void fix_length_and_dec2(Item **items)
...@@ -1034,9 +1034,9 @@ class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type ...@@ -1034,9 +1034,9 @@ class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type
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_case_expression(thd, a, b) { }
Item_func_case_abbreviation2(THD *thd, Item *a, Item *b, Item *c): Item_func_case_abbreviation2(THD *thd, Item *a, Item *b, Item *c):
Item_func_hybrid_field_type(thd, a, b, c) { } Item_func_case_expression(thd, a, b, c) { }
}; };
...@@ -1056,8 +1056,6 @@ class Item_func_ifnull :public Item_func_case_abbreviation2 ...@@ -1056,8 +1056,6 @@ class Item_func_ifnull :public Item_func_case_abbreviation2
maybe_null= args[1]->maybe_null; maybe_null= args[1]->maybe_null;
} }
const char *func_name() const { return "ifnull"; } const char *func_name() const { return "ifnull"; }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table); }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
uint decimal_precision() const uint decimal_precision() const
...@@ -1161,7 +1159,7 @@ class Item_func_nvl2 :public Item_func_case_abbreviation2_switch ...@@ -1161,7 +1159,7 @@ class Item_func_nvl2 :public Item_func_case_abbreviation2_switch
}; };
class Item_func_nullif :public Item_func_hybrid_field_type class Item_func_nullif :public Item_func_case_expression
{ {
Arg_comparator cmp; Arg_comparator cmp;
/* /*
...@@ -1199,7 +1197,7 @@ class Item_func_nullif :public Item_func_hybrid_field_type ...@@ -1199,7 +1197,7 @@ class Item_func_nullif :public Item_func_hybrid_field_type
See also Item_func_nullif::fix_length_and_dec(). See also Item_func_nullif::fix_length_and_dec().
*/ */
Item_func_nullif(THD *thd, Item *a, Item *b): Item_func_nullif(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b, a), Item_func_case_expression(thd, a, b, a),
m_cache(NULL), m_cache(NULL),
m_arg0(NULL) m_arg0(NULL)
{ arg_count--; } { arg_count--; }
...@@ -2031,7 +2029,7 @@ class Predicant_to_list_comparator ...@@ -2031,7 +2029,7 @@ class Predicant_to_list_comparator
function and only comparators for there result types are used. function and only comparators for there result types are used.
*/ */
class Item_func_case :public Item_func_hybrid_field_type, class Item_func_case :public Item_func_case_expression,
public Predicant_to_list_comparator public Predicant_to_list_comparator
{ {
int first_expr_num, else_expr_num; int first_expr_num, else_expr_num;
......
...@@ -599,6 +599,38 @@ class Item_func_hybrid_field_type: public Item_hybrid_func ...@@ -599,6 +599,38 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
}; };
/*
This class resembles SQL standard CASE-alike expressions:
CASE and its abbreviations COALESCE, NULLIF, IFNULL, IF.
<case expression> ::= <case abbreviation>
| <case specification>
*/
class Item_func_case_expression: public Item_func_hybrid_field_type
{
public:
Item_func_case_expression(THD *thd)
:Item_func_hybrid_field_type(thd)
{ }
Item_func_case_expression(THD *thd, Item *a)
:Item_func_hybrid_field_type(thd, a)
{ }
Item_func_case_expression(THD *thd, Item *a, Item *b)
:Item_func_hybrid_field_type(thd, a, b)
{ }
Item_func_case_expression(THD *thd, Item *a, Item *b, Item *c)
:Item_func_hybrid_field_type(thd, a, b, c)
{ }
Item_func_case_expression(THD *thd, List<Item> &list):
Item_func_hybrid_field_type(thd, list)
{ }
Field *create_tmp_field(bool group, TABLE *table)
{ return tmp_table_field_from_field_type(table); }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table); }
};
class Item_func_numhybrid: public Item_func_hybrid_field_type class Item_func_numhybrid: public Item_func_hybrid_field_type
{ {
protected: protected:
...@@ -1404,6 +1436,10 @@ class Item_func_min_max :public Item_hybrid_func ...@@ -1404,6 +1436,10 @@ class Item_func_min_max :public Item_hybrid_func
Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg): Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg):
Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg) Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg)
{} {}
Field *create_tmp_field(bool group, TABLE *table)
{ return tmp_table_field_from_field_type(table); }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table); }
String *val_str_native(String *str); String *val_str_native(String *str);
double val_real_native(); double val_real_native();
longlong val_int_native(); longlong val_int_native();
......
...@@ -513,6 +513,21 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other) ...@@ -513,6 +513,21 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
} }
/*
This method is called for CASE (and its abbreviations) and LEAST/GREATEST
when data type aggregation returned LONGLONG and there were some BIT
expressions. This helps to adjust the data type from LONGLONG to LONG
if all expressions fit.
*/
const Type_handler *
Type_handler::bit_and_int_mixture_handler(uint max_char_length)
{
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS)
return &type_handler_long;
return &type_handler_longlong;
}
/** /**
@brief Aggregates field types from the array of items. @brief Aggregates field types from the array of items.
...@@ -552,6 +567,8 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname, ...@@ -552,6 +567,8 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
Item **items, uint nitems, Item **items, uint nitems,
bool treat_bit_as_number) bool treat_bit_as_number)
{ {
bool bit_and_non_bit_mixture_found= false;
uint32 max_display_length;
if (!nitems || items[0]->result_type() == ROW_RESULT) if (!nitems || items[0]->result_type() == ROW_RESULT)
{ {
DBUG_ASSERT(0); DBUG_ASSERT(0);
...@@ -559,12 +576,15 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname, ...@@ -559,12 +576,15 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
return true; return true;
} }
set_handler(items[0]->type_handler()); set_handler(items[0]->type_handler());
max_display_length= items[0]->max_display_length();
for (uint i= 1 ; i < nitems ; i++) for (uint i= 1 ; i < nitems ; i++)
{ {
const Type_handler *cur= items[i]->type_handler(); const Type_handler *cur= items[i]->type_handler();
set_if_bigger(max_display_length, items[i]->max_display_length());
if (treat_bit_as_number && if (treat_bit_as_number &&
((type_handler() == &type_handler_bit) ^ (cur == &type_handler_bit))) ((type_handler() == &type_handler_bit) ^ (cur == &type_handler_bit)))
{ {
bit_and_non_bit_mixture_found= true;
if (type_handler() == &type_handler_bit) if (type_handler() == &type_handler_bit)
set_handler(&type_handler_longlong); // BIT + non-BIT set_handler(&type_handler_longlong); // BIT + non-BIT
else else
...@@ -577,6 +597,8 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname, ...@@ -577,6 +597,8 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
return true; return true;
} }
} }
if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
return false; return false;
} }
...@@ -728,7 +750,9 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h) ...@@ -728,7 +750,9 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
} }
else else
{ {
m_type_handler= &type_handler_double; // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
if (m_type_handler != &type_handler_float || h != &type_handler_float)
m_type_handler= &type_handler_double;
} }
return false; return false;
} }
...@@ -738,12 +762,19 @@ bool ...@@ -738,12 +762,19 @@ bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname, Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
Item **items, uint nitems) Item **items, uint nitems)
{ {
bool bit_and_non_bit_mixture_found= false;
uint32 max_display_length;
// LEAST/GREATEST require at least two arguments // LEAST/GREATEST require at least two arguments
DBUG_ASSERT(nitems > 1); DBUG_ASSERT(nitems > 1);
set_handler(items[0]->type_handler()); set_handler(items[0]->type_handler());
max_display_length= items[0]->max_display_length();
for (uint i= 1; i < nitems; i++) for (uint i= 1; i < nitems; i++)
{ {
const Type_handler *cur= items[i]->type_handler(); const Type_handler *cur= items[i]->type_handler();
set_if_bigger(max_display_length, items[i]->max_display_length());
// Check if BIT + non-BIT, or non-BIT + BIT
bit_and_non_bit_mixture_found|= (m_type_handler == &type_handler_bit) !=
(cur == &type_handler_bit);
if (aggregate_for_min_max(cur)) if (aggregate_for_min_max(cur))
{ {
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
...@@ -751,6 +782,8 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname, ...@@ -751,6 +782,8 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
return true; return true;
} }
} }
if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
return false; return false;
} }
......
...@@ -535,6 +535,7 @@ class Type_handler ...@@ -535,6 +535,7 @@ class Type_handler
public: public:
static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *blob_type_handler(uint max_octet_length);
static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length);
static const Type_handler *bit_and_int_mixture_handler(uint max_char_len);
/** /**
Return a string type handler for Item Return a string type handler for Item
If too_big_for_varchar() returns a BLOB variant, according to length. If too_big_for_varchar() returns a BLOB variant, according to length.
......
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