From ffe83e8e7bef32eb2a80aad2d382f0b023dd3a44 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 31 May 2018 18:52:32 +0400 Subject: [PATCH] MDEV-16351 JSON_OBJECT() treats hybrid functions with boolean arguments as numbers Now the boolean data type is preserved in hybrid functions and MIN/MAX, so COALESCE(bool_expr,bool_expr) and MAX(bool_expr) are correctly detected by JSON_OBJECT() as being boolean rather than numeric expressions. --- mysql-test/main/func_json.result | 88 ++++++++++++++++++++ mysql-test/main/func_json.test | 50 +++++++++++ mysql-test/main/gis-precise.result | 2 +- mysql-test/main/gis.result | 22 +++++ mysql-test/main/gis.test | 28 ++++++- mysql-test/suite/innodb_gis/r/precise.result | 2 +- sql/field.cc | 21 +++++ sql/item.h | 21 ++++- sql/item_cmpfunc.h | 4 +- sql/item_jsonfunc.cc | 2 +- sql/item_xmlfunc.cc | 7 +- sql/opt_range.cc | 3 +- sql/sql_parse.cc | 3 +- sql/sql_type.cc | 26 +++++- sql/sql_type.h | 12 +++ 15 files changed, 277 insertions(+), 14 deletions(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 9b41c1f9d61..915ae6edbc8 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -768,3 +768,91 @@ json_length json_depnth # # End of 10.3 tests # +# +# Start of 10.4 tests +# +# +# MDEV-16351 JSON_OBJECT() treats hybrid functions with boolean arguments as numbers +# +SELECT +JSON_OBJECT("cond", true) AS j1, +JSON_OBJECT("cond", COALESCE(true, false)) j2, +JSON_OBJECT("cond", COALESCE(COALESCE(true, false))) j3; +j1 {"cond": true} +j2 {"cond": true} +j3 {"cond": true} +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT JSON_OBJECT('x',(SELECT MAX(a)=4 FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a)=4 FROM t1)) +{"x": false} +SELECT JSON_OBJECT('x',(SELECT MAX(a)=3 FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a)=3 FROM t1)) +{"x": true} +SELECT JSON_OBJECT('x',(SELECT MAX(a)=2 FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a)=2 FROM t1)) +{"x": false} +SELECT JSON_OBJECT('x',MAX(a=4)) FROM t1; +JSON_OBJECT('x',MAX(a=4)) +{"x": false} +SELECT JSON_OBJECT('x',MAX(a=3)) FROM t1; +JSON_OBJECT('x',MAX(a=3)) +{"x": true} +SELECT JSON_OBJECT('x',MAX(a=2)) FROM t1; +JSON_OBJECT('x',MAX(a=2)) +{"x": true} +SELECT JSON_OBJECT('x',(SELECT MAX(a=4) FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a=4) FROM t1)) +{"x": false} +SELECT JSON_OBJECT('x',(SELECT MAX(a=3) FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a=3) FROM t1)) +{"x": true} +SELECT JSON_OBJECT('x',(SELECT MAX(a=2) FROM t1)); +JSON_OBJECT('x',(SELECT MAX(a=2) FROM t1)) +{"x": true} +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=4 FROM t1))='{"x": true}' THEN a END; +a +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=4 FROM t1))='{"x": false}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=3 FROM t1))='{"x": true}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=3 FROM t1))='{"x": false}' THEN a END; +a +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=2 FROM t1))='{"x": true}' THEN a END; +a +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=2 FROM t1))='{"x": false}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=4) FROM t1))='{"x": true}' THEN a END; +a +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=4) FROM t1))='{"x": false}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=3) FROM t1))='{"x": true}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=3) FROM t1))='{"x": false}' THEN a END; +a +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=2) FROM t1))='{"x": true}' THEN a END; +a +1 +2 +3 +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=2) FROM t1))='{"x": false}' THEN a END; +a +DROP TABLE t1; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 2669408fdce..83a0f4eac74 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -424,3 +424,53 @@ SELECT --echo # --echo # End of 10.3 tests --echo # + +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-16351 JSON_OBJECT() treats hybrid functions with boolean arguments as numbers +--echo # + +--vertical_results +SELECT + JSON_OBJECT("cond", true) AS j1, + JSON_OBJECT("cond", COALESCE(true, false)) j2, + JSON_OBJECT("cond", COALESCE(COALESCE(true, false))) j3; +--horizontal_results + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT JSON_OBJECT('x',(SELECT MAX(a)=4 FROM t1)); +SELECT JSON_OBJECT('x',(SELECT MAX(a)=3 FROM t1)); +SELECT JSON_OBJECT('x',(SELECT MAX(a)=2 FROM t1)); + +SELECT JSON_OBJECT('x',MAX(a=4)) FROM t1; +SELECT JSON_OBJECT('x',MAX(a=3)) FROM t1; +SELECT JSON_OBJECT('x',MAX(a=2)) FROM t1; + +SELECT JSON_OBJECT('x',(SELECT MAX(a=4) FROM t1)); +SELECT JSON_OBJECT('x',(SELECT MAX(a=3) FROM t1)); +SELECT JSON_OBJECT('x',(SELECT MAX(a=2) FROM t1)); + +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=4 FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=4 FROM t1))='{"x": false}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=3 FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=3 FROM t1))='{"x": false}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=2 FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a)=2 FROM t1))='{"x": false}' THEN a END; + +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=4) FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=4) FROM t1))='{"x": false}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=3) FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=3) FROM t1))='{"x": false}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=2) FROM t1))='{"x": true}' THEN a END; +SELECT * FROM t1 WHERE CASE WHEN JSON_OBJECT('x', (SELECT MAX(a=2) FROM t1))='{"x": false}' THEN a END; + + +DROP TABLE t1; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/mysql-test/main/gis-precise.result b/mysql-test/main/gis-precise.result index 292dfe0462c..7b553387fde 100644 --- a/mysql-test/main/gis-precise.result +++ b/mysql-test/main/gis-precise.result @@ -223,7 +223,7 @@ st_u MULTIPOLYGON(((525400 18370,525000.9677614468 183300,525400 183300,525400 18370)),((525000 183300,525000 183700,525000.9677614468 183300,525000 183300)),((525265.58 183481.95,525263.95 183484.75,525260.7 183491.55,525276.79 183500,525278.39 183500.84,525278.63 183500.97,525280.98 183502.26,525283.17 183503.47,525289.11 183506.62,525296.42 183510.31,525296.57 183510.39,525298.67 183511.53,525302.81 183513.8,525304.5 183510.83,525307.85 183504.95,525304.45 183504.25,525301.75 183509.35,525283.55 183500,525282.2 183499.3,525282.3 183499.1,525280.35 183498.2,525275.5 183495.7,525276.5 183493.45,525278.97 183488.73,525265.58 183481.95),(525266.99 183484.33,525263.26 183491.55,525266.15 183493.04,525269.88 183485.82,525266.99 183484.33),(525272.06 183488.37,525268.94 183494.51,525271.94 183496.03,525275.06 183489.89,525272.06 183488.37))) SET @a=0x0000000001030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F00000000000000400000000000000040000000000000F03F0000000000000040000000000000F03F000000000000F03F; SELECT ASTEXT(TOUCHES(@a, GEOMFROMTEXT('point(0 0)'))) t; -ERROR HY000: Illegal parameter data type int for operation 'st_astext' +ERROR HY000: Illegal parameter data type boolean for operation 'st_astext' SELECT astext(ST_UNION ( PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))); diff --git a/mysql-test/main/gis.result b/mysql-test/main/gis.result index 3f2e6d39db8..1cc4e45629b 100644 --- a/mysql-test/main/gis.result +++ b/mysql-test/main/gis.result @@ -4920,3 +4920,25 @@ ERROR HY000: Illegal parameter data type geometry for operation 'is_used_lock' # # End of 10.3 tests # +# +# Start of 10.4 tests +# +# +# MDEV-16351 JSON_OBJECT() treats hybrid functions with boolean arguments as numbers +# +SELECT ST_SRID(TRUE); +ERROR HY000: Illegal parameter data type boolean for operation 'srid' +SELECT ST_SRID(COALESCE(TRUE,TRUE)); +ERROR HY000: Illegal parameter data type boolean for operation 'srid' +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT ST_SRID((SELECT MAX(a)>3 FROM t1)); +ERROR HY000: Illegal parameter data type boolean for operation 'srid' +SELECT ST_SRID(MAX(a>3)) FROM t1; +ERROR HY000: Illegal parameter data type boolean for operation 'srid' +SELECT ST_SRID((SELECT MAX(a>3) FROM t1)); +ERROR HY000: Illegal parameter data type boolean for operation 'srid' +DROP TABLE t1; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index ca806778f0e..1bac831ac22 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -2595,7 +2595,6 @@ SELECT ST_SRID(1); --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION SELECT ST_SRID('test'); - --echo # Item_bool_func_args_geometry --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION @@ -2990,3 +2989,30 @@ SELECT IS_USED_LOCK(POINT(1,1)); --echo # --echo # End of 10.3 tests --echo # + +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-16351 JSON_OBJECT() treats hybrid functions with boolean arguments as numbers +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT ST_SRID(TRUE); +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT ST_SRID(COALESCE(TRUE,TRUE)); + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT ST_SRID((SELECT MAX(a)>3 FROM t1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT ST_SRID(MAX(a>3)) FROM t1; +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT ST_SRID((SELECT MAX(a>3) FROM t1)); +DROP TABLE t1; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/mysql-test/suite/innodb_gis/r/precise.result b/mysql-test/suite/innodb_gis/r/precise.result index 3c05b814602..6cc0368fbb4 100644 --- a/mysql-test/suite/innodb_gis/r/precise.result +++ b/mysql-test/suite/innodb_gis/r/precise.result @@ -216,7 +216,7 @@ st_u MULTIPOLYGON(((525400 18370,525000.9677614468 183300,525400 183300,525400 18370)),((525000 183300,525000 183700,525000.9677614468 183300,525000 183300)),((525265.58 183481.95,525263.95 183484.75,525260.7 183491.55,525276.79 183500,525278.39 183500.84,525278.63 183500.97,525280.98 183502.26,525283.17 183503.47,525289.11 183506.62,525296.42 183510.31,525296.57 183510.39,525298.67 183511.53,525302.81 183513.8,525304.5 183510.83,525307.85 183504.95,525304.45 183504.25,525301.75 183509.35,525283.55 183500,525282.2 183499.3,525282.3 183499.1,525280.35 183498.2,525275.5 183495.7,525276.5 183493.45,525278.97 183488.73,525265.58 183481.95),(525266.99 183484.33,525263.26 183491.55,525266.15 183493.04,525269.88 183485.82,525266.99 183484.33),(525272.06 183488.37,525268.94 183494.51,525271.94 183496.03,525275.06 183489.89,525272.06 183488.37))) SET @a=0x0000000001030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F00000000000000400000000000000040000000000000F03F0000000000000040000000000000F03F000000000000F03F; SELECT ST_ASTEXT(ST_TOUCHES(@a, ST_GEOMFROMTEXT('point(0 0)'))) t; -ERROR HY000: Illegal parameter data type int for operation 'st_astext' +ERROR HY000: Illegal parameter data type boolean for operation 'st_astext' DROP TABLE IF EXISTS p1; CREATE PROCEDURE p1(dist DOUBLE, geom TEXT) BEGIN diff --git a/sql/field.cc b/sql/field.cc index 059b06b5dba..4f04fef1a26 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -917,6 +917,27 @@ const Type_handler * Type_handler::aggregate_for_result_traditional(const Type_handler *a, const Type_handler *b) { + if (a == b) + { + /* + If two traditional handlers are equal, quickly return "a". + Some handlers (e.g. Type_handler_bool) pretend to be traditional, + but in fact they are not traditional in full extent, they are + only sub-types for now (and don't have a corresponding Field_xxx yet). + Here we preserve such handlers during aggregation. + As a result, COALESCE(true,true) preserves the "boolean" data type. + + Need to do this conversion for deprecated data types, + similar to what field_type_merge_rules[][] does. + */ + switch (a->field_type()) { + case MYSQL_TYPE_DECIMAL: return &type_handler_newdecimal; + case MYSQL_TYPE_DATE: return &type_handler_newdate; + case MYSQL_TYPE_VAR_STRING: return &type_handler_varchar; + default: break; + } + return a; + } enum_field_types ta= a->traditional_merge_field_type(); enum_field_types tb= b->traditional_merge_field_type(); enum_field_types res= field_types_merge_rules[merge_type2index(ta)] diff --git a/sql/item.h b/sql/item.h index 71e5ec6c6b4..117c6b5c6d5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -918,6 +918,21 @@ public: return type_handler()->field_type(); } virtual const Type_handler *type_handler() const= 0; + /** + Detects if an Item has a fixed data type which is known + even before fix_fields(). + Currently it's important only to find Items with a fixed boolean + data type. More item types can be marked in the future as having + a fixed data type (e.g. all literals, all fixed type functions, etc). + + @retval NULL if the Item type is not known before fix_fields() + @retval the pointer to the data type handler, if the data type + is known before fix_fields(). + */ + virtual const Type_handler *fixed_type_handler() const + { + return NULL; + } virtual uint field_flags() const { return 0; @@ -1633,7 +1648,6 @@ public: table during query processing (grouping and so on) */ virtual bool is_result_field() { return 0; } - virtual bool is_bool_type() { return false; } virtual bool is_json_type() { return false; } virtual bool is_bool_literal() const { return false; } /* This is to handle printing of default values */ @@ -3862,9 +3876,12 @@ public: Item_bool(THD *thd, const char *str_arg, longlong i): Item_int(thd, str_arg, i, 1) {} Item_bool(THD *thd, bool i) :Item_int(thd, (longlong) i, 1) { } - bool is_bool_type() { return true; } bool is_bool_literal() const { return true; } Item *neg_transformer(THD *thd); + const Type_handler *type_handler() const + { return &type_handler_bool; } + const Type_handler *fixed_type_handler() const + { return &type_handler_bool; } }; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 34988be520b..1cdc48c8962 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -215,8 +215,8 @@ public: Item_bool_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_bool_func(THD *thd, List &list): Item_int_func(thd, list) { } Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} - const Type_handler *type_handler() const { return &type_handler_long; } - bool is_bool_type() { return true; } + const Type_handler *type_handler() const { return &type_handler_bool; } + const Type_handler *fixed_type_handler() const { return &type_handler_bool; } virtual CHARSET_INFO *compare_collation() const { return NULL; } void fix_length_and_dec() { decimals=0; max_length=1; } uint decimal_precision() const { return 1; } diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 4b2de7cf28b..be1d84982de 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1397,7 +1397,7 @@ null_return: static int append_json_value(String *str, Item *item, String *tmp_val) { - if (item->is_bool_type()) + if (item->type_handler()->is_bool_type()) { longlong v_int= item->val_int(); const char *t_f; diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index ab41b496cde..a4221661ae4 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -855,7 +855,9 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) flt->pos, size); int index= (int) (args[1]->val_int()) - 1; - if (index >= 0 && (flt->pos == (uint) index || args[1]->is_bool_type())) + if (index >= 0 && + (flt->pos == (uint) index || + (args[1]->type_handler()->is_bool_type()))) ((XPathFilter*)nodeset)->append_element(flt->num, pos++); } return nodeset; @@ -1803,7 +1805,8 @@ my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath) xpath->item= nodeset2bool(xpath, xpath->item); - if (xpath->item->is_bool_type()) + const Type_handler *fh; + if ((fh= xpath->item->fixed_type_handler()) && fh->is_bool_type()) { xpath->context= new (xpath->thd->mem_root) Item_nodeset_func_predicate(xpath->thd, prev_context, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 07a76cc7333..9ccffd13bfc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -13031,7 +13031,8 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item, if (args[0] && args[1]) // this is a binary function or BETWEEN { - DBUG_ASSERT(pred->is_bool_type()); + DBUG_ASSERT(pred->fixed_type_handler()); + DBUG_ASSERT(pred->fixed_type_handler()->is_bool_type()); Item_bool_func *bool_func= (Item_bool_func*) pred; Field *field= min_max_arg_item->field; if (!args[2]) // this is a binary function diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fbcf09758e6..09ef7a587ba 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9664,8 +9664,9 @@ Item *negate_expression(THD *thd, Item *expr) { /* it is NOT(NOT( ... )) */ Item *arg= ((Item_func *) expr)->arguments()[0]; + const Type_handler *fh= arg->fixed_type_handler(); enum_parsing_place place= thd->lex->current_select->parsing_place; - if (arg->is_bool_type() || place == IN_WHERE || place == IN_HAVING) + if ((fh && fh->is_bool_type()) || place == IN_WHERE || place == IN_HAVING) return arg; /* if it is not boolean function then we have to emulate value of diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 154b63a9ce6..0c9dc57dcd3 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -26,6 +26,7 @@ Type_handler_row type_handler_row; Type_handler_null type_handler_null; +Type_handler_bool type_handler_bool; Type_handler_tiny type_handler_tiny; Type_handler_short type_handler_short; Type_handler_long type_handler_long; @@ -452,6 +453,7 @@ const Name Type_handler_set::m_name_set(STRING_WITH_LEN("set")); const Name + Type_handler_bool::m_name_bool(STRING_WITH_LEN("boolean")), Type_handler_tiny::m_name_tiny(STRING_WITH_LEN("tinyint")), Type_handler_short::m_name_short(STRING_WITH_LEN("smallint")), Type_handler_long::m_name_int(STRING_WITH_LEN("int")), @@ -2818,8 +2820,21 @@ bool Type_handler_typelib:: TYPELIB *typelib= NULL; for (uint i= 0; i < nitems; i++) { - if ((typelib= items[i]->get_typelib())) - break; + TYPELIB *typelib2; + if ((typelib2= items[i]->get_typelib())) + { + if (typelib) + { + /* + Two ENUM/SET columns found. We convert such combinations to VARCHAR. + This may change in the future to preserve ENUM/SET + if typelib definitions are equal. + */ + handler->set_handler(&type_handler_varchar); + return func->aggregate_attributes_string(func_name, items, nitems); + } + typelib= typelib2; + } } DBUG_ASSERT(typelib); // There must be at least one typelib func->set_typelib(typelib); @@ -2977,6 +2992,13 @@ bool Type_handler_int_result:: } +bool Type_handler_bool:: + Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const +{ + return Item_sum_hybrid_fix_length_and_dec_numeric(func, &type_handler_bool); +} + + bool Type_handler_real_result:: Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const { diff --git a/sql/sql_type.h b/sql/sql_type.h index 274194f52fe..b9d739be8b9 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1125,6 +1125,7 @@ public: virtual bool can_return_text() const { return true; } virtual bool can_return_date() const { return true; } virtual bool can_return_time() const { return true; } + virtual bool is_bool_type() const { return false; } virtual bool is_general_purpose_string_type() const { return false; } virtual uint Item_time_precision(Item *item) const; virtual uint Item_datetime_precision(Item *item) const; @@ -2333,6 +2334,16 @@ public: }; +class Type_handler_bool: public Type_handler_long +{ + static const Name m_name_bool; +public: + const Name name() const { return m_name_bool; } + bool is_bool_type() const { return true; } + bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const; +}; + + class Type_handler_longlong: public Type_handler_general_purpose_int { static const Name m_name_longlong; @@ -3615,6 +3626,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob; extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob; +extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool; extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_tiny; extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short; extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24;