diff --git a/mysql-test/main/sp-row.result b/mysql-test/main/sp-row.result index 4b87798e0bb..7c257297934 100644 --- a/mysql-test/main/sp-row.result +++ b/mysql-test/main/sp-row.result @@ -189,7 +189,7 @@ SELECT a+1; END; $$ CALL p1(); -ERROR 21000: Operand should contain 1 column(s) +ERROR HY000: Illegal parameter data types row and int for operation '+' DROP PROCEDURE p1; CREATE PROCEDURE p1() BEGIN @@ -198,7 +198,7 @@ SELECT a+1; END; $$ CALL p1(); -ERROR 21000: Operand should contain 1 column(s) +ERROR HY000: Illegal parameter data types row and int for operation '+' DROP PROCEDURE p1; # # Comparing the entire ROW to a scalar value diff --git a/mysql-test/main/sp-row.test b/mysql-test/main/sp-row.test index 3352c940cb6..b9143b1113b 100644 --- a/mysql-test/main/sp-row.test +++ b/mysql-test/main/sp-row.test @@ -244,7 +244,7 @@ BEGIN END; $$ DELIMITER ;$$ ---error ER_OPERAND_COLUMNS +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION CALL p1(); DROP PROCEDURE p1; @@ -257,7 +257,7 @@ BEGIN END; $$ DELIMITER ;$$ ---error ER_OPERAND_COLUMNS +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION CALL p1(); DROP PROCEDURE p1; diff --git a/mysql-test/main/type_row.result b/mysql-test/main/type_row.result new file mode 100644 index 00000000000..dc74cfc88a4 --- /dev/null +++ b/mysql-test/main/type_row.result @@ -0,0 +1,51 @@ +# +# Start of 10.5 tests +# +# +# MDEV-20175 Move Type_handler_row from Type_collection_std to Type_collection_row +# +SELECT LEAST(ROW(1,1), ROW(1,1)); +ERROR HY000: Illegal parameter data types row and row for operation 'least' +SELECT GREATEST(ROW(1,1), ROW(1,1)); +ERROR HY000: Illegal parameter data types row and row for operation 'greatest' +SELECT LEAST(ROW(1,1), 1); +ERROR HY000: Illegal parameter data types row and int for operation 'least' +SELECT GREATEST(ROW(1,1), 1); +ERROR HY000: Illegal parameter data types row and int for operation 'greatest' +SELECT LEAST(1, ROW(1,1)); +ERROR HY000: Illegal parameter data types int and row for operation 'least' +SELECT GREATEST(1, ROW(1,1)); +ERROR HY000: Illegal parameter data types int and row for operation 'greatest' +SELECT ROW(1,1) + ROW(1,1); +ERROR HY000: Illegal parameter data types row and row for operation '+' +SELECT 1 + ROW(1,1); +ERROR HY000: Illegal parameter data types int and row for operation '+' +SELECT ROW(1,1) + 1; +ERROR HY000: Illegal parameter data types row and int for operation '+' +SELECT ROW(1,1) - ROW(1,1); +ERROR HY000: Illegal parameter data types row and row for operation '-' +SELECT 1 - ROW(1,1); +ERROR HY000: Illegal parameter data types int and row for operation '-' +SELECT ROW(1,1) - 1; +ERROR HY000: Illegal parameter data types row and int for operation '-' +SELECT ROW(1,1) * ROW(1,1); +ERROR HY000: Illegal parameter data types row and row for operation '*' +SELECT 1 * ROW(1,1); +ERROR HY000: Illegal parameter data types int and row for operation '*' +SELECT ROW(1,1) * 1; +ERROR HY000: Illegal parameter data types row and int for operation '*' +SELECT ROW(1,1) / ROW(1,1); +ERROR HY000: Illegal parameter data types row and row for operation '/' +SELECT 1 / ROW(1,1); +ERROR HY000: Illegal parameter data types int and row for operation '/' +SELECT ROW(1,1) / 1; +ERROR HY000: Illegal parameter data types row and int for operation '/' +SELECT ROW(1,1) % ROW(1,1); +ERROR HY000: Illegal parameter data types row and row for operation 'MOD' +SELECT 1 % ROW(1,1); +ERROR HY000: Illegal parameter data types int and row for operation 'MOD' +SELECT ROW(1,1) % 1; +ERROR HY000: Illegal parameter data types row and int for operation 'MOD' +# +# End of 10.5 tests +# diff --git a/mysql-test/main/type_row.test b/mysql-test/main/type_row.test new file mode 100644 index 00000000000..2a5902351e2 --- /dev/null +++ b/mysql-test/main/type_row.test @@ -0,0 +1,62 @@ +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-20175 Move Type_handler_row from Type_collection_std to Type_collection_row +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT LEAST(ROW(1,1), ROW(1,1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT GREATEST(ROW(1,1), ROW(1,1)); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT LEAST(ROW(1,1), 1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT GREATEST(ROW(1,1), 1); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT LEAST(1, ROW(1,1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT GREATEST(1, ROW(1,1)); + + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) + ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT 1 + ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) + 1; + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) - ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT 1 - ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) - 1; + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) * ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT 1 * ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) * 1; + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) / ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT 1 / ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) / 1; + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) % ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT 1 % ROW(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ROW(1,1) % 1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/r/sp-row.result b/mysql-test/suite/compat/oracle/r/sp-row.result index 218fb5d463a..323b0c684f3 100644 --- a/mysql-test/suite/compat/oracle/r/sp-row.result +++ b/mysql-test/suite/compat/oracle/r/sp-row.result @@ -209,7 +209,7 @@ SELECT a+1; END; $$ CALL p1(); -ERROR 21000: Operand should contain 1 column(s) +ERROR HY000: Illegal parameter data types row and int for operation '+' DROP PROCEDURE p1; CREATE PROCEDURE p1() AS @@ -219,7 +219,7 @@ SELECT a+1; END; $$ CALL p1(); -ERROR 21000: Operand should contain 1 column(s) +ERROR HY000: Illegal parameter data types row and int for operation '+' DROP PROCEDURE p1; # # Comparing the entire ROW to a scalar value diff --git a/mysql-test/suite/compat/oracle/t/sp-row.test b/mysql-test/suite/compat/oracle/t/sp-row.test index 469494ad228..8abf317708a 100644 --- a/mysql-test/suite/compat/oracle/t/sp-row.test +++ b/mysql-test/suite/compat/oracle/t/sp-row.test @@ -263,7 +263,7 @@ BEGIN END; $$ DELIMITER ;$$ ---error ER_OPERAND_COLUMNS +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION CALL p1(); DROP PROCEDURE p1; @@ -277,7 +277,7 @@ BEGIN END; $$ DELIMITER ;$$ ---error ER_OPERAND_COLUMNS +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION CALL p1(); DROP PROCEDURE p1; diff --git a/sql/item.cc b/sql/item.cc index 41af37a3a42..42bcb216935 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -978,7 +978,7 @@ bool Item::check_type_general_purpose_string(const char *opname) const bool Item::check_type_traditional_scalar(const char *opname) const { const Type_handler *handler= type_handler(); - if (handler->is_traditional_type() && handler->is_scalar_type()) + if (handler->is_traditional_scalar_type()) return false; my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), handler->name().ptr(), opname); diff --git a/sql/item_func.h b/sql/item_func.h index 54087a17127..00ed688e9e3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -936,7 +936,12 @@ public: /* Base class for operations like '+', '-', '*' */ class Item_num_op :public Item_func_numhybrid { - public: +protected: + bool check_arguments() const + { + return false; // Checked by aggregate_for_num_op() + } +public: Item_num_op(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {} virtual void result_precision()= 0; @@ -1798,6 +1803,10 @@ class Item_func_min_max :public Item_hybrid_func String tmp_value; int cmp_sign; protected: + bool check_arguments() const + { + return false; // Checked by aggregate_for_min_max() + } bool fix_attributes(Item **item, uint nitems); public: Item_func_min_max(THD *thd, List &list, int cmp_sign_arg): diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index de0c5bd520b..82446cdd0da 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2001,7 +2001,7 @@ bool Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; - if (!args[0]->type_handler()->is_traditional_type()) + if (!args[0]->type_handler()->is_traditional_scalar_type()) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), args[0]->type_handler()->name().ptr(), @@ -2505,8 +2505,8 @@ bool Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; - if (!args[0]->type_handler()->is_traditional_type() || - !args[1]->type_handler()->is_traditional_type()) + if (!args[0]->type_handler()->is_traditional_scalar_type() || + !args[1]->type_handler()->is_traditional_scalar_type()) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), args[0]->type_handler()->name().ptr(), @@ -2916,8 +2916,8 @@ get_date_time_result_type(const char *format, uint length) bool Item_func_str_to_date::fix_length_and_dec() { - if (!args[0]->type_handler()->is_traditional_type() || - !args[1]->type_handler()->is_traditional_type()) + if (!args[0]->type_handler()->is_traditional_scalar_type() || + !args[1]->type_handler()->is_traditional_scalar_type()) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), args[0]->type_handler()->name().ptr(), diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 5cecd9f50f7..103cd255b94 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -109,6 +109,58 @@ const Type_collection *Type_handler::type_collection() const } +bool Type_handler::is_traditional_scalar_type() const +{ + return type_collection() == &type_collection_std; +} + + +class Type_collection_row: public Type_collection +{ +public: + bool init(Type_handler_data *data) override + { + return false; + } + const Type_handler *handler_by_name(const LEX_CSTRING &name) const override + { + return NULL; + } + const Type_handler *aggregate_for_result(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } + const Type_handler *aggregate_for_comparison(const Type_handler *a, + const Type_handler *b) + const override + { + DBUG_ASSERT(a == &type_handler_row); + DBUG_ASSERT(b == &type_handler_row); + return &type_handler_row; + } + const Type_handler *aggregate_for_min_max(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } + const Type_handler *aggregate_for_num_op(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } +}; + + +static Type_collection_row type_collection_row; + +const Type_collection *Type_handler_row::type_collection() const +{ + return &type_collection_row; +} bool Type_handler_data::init() @@ -1752,15 +1804,12 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname, Item **items, uint nitems) { bool bit_and_non_bit_mixture_found= false; - uint32 max_display_length; // LEAST/GREATEST require at least two arguments DBUG_ASSERT(nitems > 1); set_handler(items[0]->type_handler()); - max_display_length= items[0]->max_display_length(); for (uint i= 1; i < nitems; i++) { 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); @@ -1772,7 +1821,12 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname, } } if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong) + { + uint32 max_display_length= items[0]->max_display_length(); + for (uint i= 1; i < nitems; i++) + set_if_bigger(max_display_length, items[i]->max_display_length()); set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length)); + } return false; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 8f2d4d0c49d..7a578a28168 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3314,7 +3314,7 @@ public: */ virtual enum_field_types traditional_merge_field_type() const { - DBUG_ASSERT(is_traditional_type()); + DBUG_ASSERT(is_traditional_scalar_type()); return field_type(); } virtual enum_field_types type_code_for_protocol() const @@ -3413,13 +3413,10 @@ public: } virtual ~Type_handler() {} /** - Determines MariaDB traditional data types that always present + Determines MariaDB traditional scalar data types that always present in the server. */ - virtual bool is_traditional_type() const - { - return true; - } + bool is_traditional_scalar_type() const; virtual bool is_scalar_type() const { return true; } virtual bool can_return_int() const { return true; } virtual bool can_return_decimal() const { return true; } @@ -3899,6 +3896,7 @@ public: DBUG_ASSERT(0); return true; } + const Type_collection *type_collection() const override; bool is_scalar_type() const { return false; } bool can_return_int() const { return false; } bool can_return_decimal() const { return false; } diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h index 3955172e39b..53064bf143d 100644 --- a/sql/sql_type_geom.h +++ b/sql/sql_type_geom.h @@ -136,7 +136,6 @@ public: bool can_return_text() const override { return false; } bool can_return_date() const override { return false; } bool can_return_time() const override { return false; } - bool is_traditional_type() const override { return false; } bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;