diff options
author | Alexander Barkov <bar@mariadb.com> | 2020-05-19 12:36:58 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2020-05-19 12:36:58 +0400 |
commit | 49b29e35b2099fcbc3342814fc0ce9c17ba1bdeb (patch) | |
tree | e830a8a54e6640c3e30d171f4ad6e37f347e146d | |
parent | 3ea05d08427dc3d679fef838e9334685f556cc32 (diff) | |
parent | 810b7f8ecbea0fbf52e03aa710a8059ea301f7dc (diff) | |
download | mariadb-git-49b29e35b2099fcbc3342814fc0ce9c17ba1bdeb.tar.gz |
Merge remote-tracking branch 'origin/10.4' into 10.5
-rw-r--r-- | mysql-test/main/table_value_constr.result | 11 | ||||
-rw-r--r-- | mysql-test/main/table_value_constr.test | 14 | ||||
-rw-r--r-- | sql/item.cc | 107 | ||||
-rw-r--r-- | sql/item.h | 147 | ||||
-rw-r--r-- | sql/mysqld.cc | 2 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 3 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 |
8 files changed, 190 insertions, 100 deletions
diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result index 321c7f8542a..51d97b9216c 100644 --- a/mysql-test/main/table_value_constr.result +++ b/mysql-test/main/table_value_constr.result @@ -2610,3 +2610,14 @@ $$ a 0 1 +# +# MDEV-21995 Server crashes in Item_field::real_type_handler with table value constructor +# +VALUES (IGNORE); +ERROR HY000: 'ignore' is not allowed in this context +VALUES (DEFAULT); +ERROR HY000: 'default' is not allowed in this context +EXECUTE IMMEDIATE 'VALUES (?)' USING IGNORE; +ERROR HY000: 'ignore' is not allowed in this context +EXECUTE IMMEDIATE 'VALUES (?)' USING DEFAULT; +ERROR HY000: 'default' is not allowed in this context diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test index e7843c604dd..a25984abfa7 100644 --- a/mysql-test/main/table_value_constr.test +++ b/mysql-test/main/table_value_constr.test @@ -1339,3 +1339,17 @@ BEGIN NOT ATOMIC END; $$ DELIMITER ;$$ + + +--echo # +--echo # MDEV-21995 Server crashes in Item_field::real_type_handler with table value constructor +--echo # + +--error ER_NOT_ALLOWED_IN_THIS_CONTEXT +VALUES (IGNORE); +--error ER_NOT_ALLOWED_IN_THIS_CONTEXT +VALUES (DEFAULT); +--error ER_NOT_ALLOWED_IN_THIS_CONTEXT +EXECUTE IMMEDIATE 'VALUES (?)' USING IGNORE; +--error ER_NOT_ALLOWED_IN_THIS_CONTEXT +EXECUTE IMMEDIATE 'VALUES (?)' USING DEFAULT; diff --git a/sql/item.cc b/sql/item.cc index 1a28563a229..5c9b8b3ea3f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -99,6 +99,13 @@ void item_init(void) } +void Item::raise_error_not_evaluable() +{ + Item::Print tmp(this, QT_ORDINARY); + my_error(ER_NOT_ALLOWED_IN_THIS_CONTEXT, MYF(0), tmp.ptr()); +} + + void Item::push_note_converted_to_negative_complement(THD *thd) { push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, @@ -4298,6 +4305,23 @@ int Item_param::save_in_field(Field *field, bool no_conversions) } +bool Item_param::is_evaluable_expression() const +{ + switch (state) { + case SHORT_DATA_VALUE: + case LONG_DATA_VALUE: + case NULL_VALUE: + return true; + case NO_VALUE: + return true; // Not assigned yet, so we don't know + case IGNORE_VALUE: + case DEFAULT_VALUE: + break; + } + return false; +} + + bool Item_param::can_return_value() const { // There's no "default". See comments in Item_param::save_in_field(). @@ -9229,12 +9253,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) Item_field *field_arg; Field *def_field; DBUG_ASSERT(fixed == 0); - - if (!arg) - { - fixed= 1; - return FALSE; - } + DBUG_ASSERT(arg); /* DEFAULT() do not need table field so should not ask handler to bring @@ -9309,11 +9328,7 @@ void Item_default_value::cleanup() void Item_default_value::print(String *str, enum_query_type query_type) { - if (!arg) - { - str->append(STRING_WITH_LEN("default")); - return; - } + DBUG_ASSERT(arg); str->append(STRING_WITH_LEN("default(")); /* We take DEFAULT from a field so do not need it value in case of const @@ -9327,6 +9342,7 @@ void Item_default_value::print(String *str, enum_query_type query_type) void Item_default_value::calculate() { + DBUG_ASSERT(arg); if (field->default_value) field->set_default(); DEBUG_SYNC(field->table->in_use, "after_Item_default_value_calculate"); @@ -9370,14 +9386,8 @@ bool Item_default_value::send(Protocol *protocol, st_value *buffer) int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { - if (arg) - { - calculate(); - return Item_field::save_in_field(field_arg, no_conversions); - } - - return field_arg->save_in_field_default_value(context->error_processor == - &view_error_processor); + calculate(); + return Item_field::save_in_field(field_arg, no_conversions); } table_map Item_default_value::used_tables() const @@ -9398,13 +9408,7 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer, uchar *args) { DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); - - /* - If the value of arg is NULL, then this object represents a constant, - so further transformation is unnecessary (and impossible). - */ - if (!arg) - return 0; + DBUG_ASSERT(arg); Item *new_item= arg->transform(thd, transformer, args); if (!new_item) @@ -9421,57 +9425,6 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer, return (this->*transformer)(thd, args); } -void Item_ignore_value::print(String *str, enum_query_type query_type) -{ - str->append(STRING_WITH_LEN("ignore")); -} - -int Item_ignore_value::save_in_field(Field *field_arg, bool no_conversions) -{ - return field_arg->save_in_field_ignore_value(context->error_processor == - &view_error_processor); -} - -String *Item_ignore_value::val_str(String *str) -{ - DBUG_ASSERT(0); // never should be called - null_value= 1; - return 0; -} - -double Item_ignore_value::val_real() -{ - DBUG_ASSERT(0); // never should be called - null_value= 1; - return 0.0; -} - -longlong Item_ignore_value::val_int() -{ - DBUG_ASSERT(0); // never should be called - null_value= 1; - return 0; -} - -my_decimal *Item_ignore_value::val_decimal(my_decimal *decimal_value) -{ - DBUG_ASSERT(0); // never should be called - null_value= 1; - return 0; -} - -bool Item_ignore_value::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) -{ - DBUG_ASSERT(0); // never should be called - null_value= 1; - return TRUE; -} - -bool Item_ignore_value::send(Protocol *protocol, st_value *buffer) -{ - DBUG_ASSERT(0); // never should be called - return TRUE; -} bool Item_insert_value::eq(const Item *item, bool binary_cmp) const { diff --git a/sql/item.h b/sql/item.h index cb11b5d8773..b6bed033499 100644 --- a/sql/item.h +++ b/sql/item.h @@ -763,6 +763,7 @@ public: CONST_ITEM, NULL_ITEM, // Item_null or Item_param bound to NULL COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, + CONTEXTUALLY_TYPED_VALUE_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, @@ -843,6 +844,7 @@ protected: const Tmp_field_param *param, bool is_explicit_null); + void raise_error_not_evaluable(); void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); @@ -1607,6 +1609,24 @@ public: positions. (And they can't be used before fix_fields is called for them). */ virtual bool is_order_clause_position() const { return false; } + /* + Determines if the Item is an evaluable expression, that is + it can return a value, so we can call methods val_xxx(), get_date(), etc. + Most items are evaluable expressions. + Examples of non-evaluable expressions: + - Item_contextually_typed_value_specification (handling DEFAULT and IGNORE) + - Item_type_param bound to DEFAULT and IGNORE + We cannot call the mentioned methods for these Items, + their method implementations typically have DBUG_ASSERT(0). + */ + virtual bool is_evaluable_expression() const { return true; } + bool check_is_evaluable_expression_or_error() + { + if (is_evaluable_expression()) + return false; // Ok + raise_error_not_evaluable(); + return true; // Error + } /* cloning of constant items (0 if it is not const) */ virtual Item *clone_item(THD *thd) { return 0; } /* deep copy item */ @@ -3858,6 +3878,7 @@ class Item_param :public Item_basic_value, const String *value_query_val_str(THD *thd, String* str) const; Item *value_clone_item(THD *thd); + bool is_evaluable_expression() const; bool can_return_value() const; public: @@ -6271,14 +6292,9 @@ class Item_default_value : public Item_field public: Item *arg= nullptr; Field *cached_field= nullptr; - Item_default_value(THD *thd, Name_resolution_context *context_arg) : - Item_field(thd, context_arg) {} Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) : Item_field(thd, context_arg), arg(a) {} - Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a) - :Item_field(thd, context_arg) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } - bool vcol_assignment_allowed_value() const { return arg == NULL; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); void cleanup(); @@ -6293,7 +6309,7 @@ public: bool save_in_param(THD *thd, Item_param *param) { // It should not be possible to have "EXECUTE .. USING DEFAULT(a)" - DBUG_ASSERT(arg == NULL); + DBUG_ASSERT(0); param->set_default(); return false; } @@ -6318,34 +6334,127 @@ public: Item *transform(THD *thd, Item_transformer transformer, uchar *args); }; + +class Item_contextually_typed_value_specification: public Item +{ +public: + Item_contextually_typed_value_specification(THD *thd) :Item(thd) + { } + enum Type type() const { return CONTEXTUALLY_TYPED_VALUE_ITEM; } + bool vcol_assignment_allowed_value() const { return true; } + bool eq(const Item *item, bool binary_cmp) const + { + return false; + } + bool is_evaluable_expression() const { return false; } + Field *create_tmp_field_ex(MEM_ROOT *root, + TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param) + { + DBUG_ASSERT(0); + return NULL; + } + String *val_str(String *str) + { + DBUG_ASSERT(0); // never should be called + null_value= true; + return 0; + } + double val_real() + { + DBUG_ASSERT(0); // never should be called + null_value= true; + return 0.0; + } + longlong val_int() + { + DBUG_ASSERT(0); // never should be called + null_value= true; + return 0; + } + my_decimal *val_decimal(my_decimal *decimal_value) + { + DBUG_ASSERT(0); // never should be called + null_value= true; + return 0; + } + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + { + DBUG_ASSERT(0); // never should be called + return null_value= true; + } + bool send(Protocol *protocol, st_value *buffer) + { + DBUG_ASSERT(0); + return true; + } + const Type_handler *type_handler() const + { + DBUG_ASSERT(0); + return &type_handler_null; + } +}; + + +/* + <default specification> ::= DEFAULT +*/ +class Item_default_specification: + public Item_contextually_typed_value_specification +{ +public: + Item_default_specification(THD *thd) + :Item_contextually_typed_value_specification(thd) + { } + void print(String *str, enum_query_type query_type) + { + str->append(STRING_WITH_LEN("default")); + } + int save_in_field(Field *field_arg, bool no_conversions) + { + return field_arg->save_in_field_default_value(false); + } + bool save_in_param(THD *thd, Item_param *param) + { + param->set_default(); + return false; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_default_specification>(thd, this); } +}; + + /** This class is used as bulk parameter INGNORE representation. It just do nothing when assigned to a field + This is a non-standard MariaDB extension. */ -class Item_ignore_value : public Item_default_value +class Item_ignore_specification: + public Item_contextually_typed_value_specification { public: - Item_ignore_value(THD *thd, Name_resolution_context *context_arg) - :Item_default_value(thd, context_arg) - {}; - - void print(String *str, enum_query_type query_type); - int save_in_field(Field *field_arg, bool no_conversions); + Item_ignore_specification(THD *thd) + :Item_contextually_typed_value_specification(thd) + { } + void print(String *str, enum_query_type query_type) + { + str->append(STRING_WITH_LEN("ignore")); + } + int save_in_field(Field *field_arg, bool no_conversions) + { + return field_arg->save_in_field_ignore_value(false); + } bool save_in_param(THD *thd, Item_param *param) { param->set_ignore(); return false; } - String *val_str(String *str); - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *decimal_value); - bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate); - bool send(Protocol *protocol, st_value *buffer); + Item *get_copy(THD *thd) + { return get_item_copy<Item_ignore_specification>(thd, this); } }; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9942e7efb7f..2ed732329d2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3607,7 +3607,7 @@ static void get_win_tzname(char* buf, size_t size) {0,0} }; DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - if (GetDynamicTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_UNKNOWN) + if (GetDynamicTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID) { strncpy(buf, "unknown", size); return; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 250da9948a0..02ba889aaa4 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7961,3 +7961,5 @@ ER_KEY_CONTAINS_PERIOD_FIELDS eng "Key %`s cannot explicitly include column %`s" ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS eng "Key %`s cannot have WITHOUT OVERLAPS" +ER_NOT_ALLOWED_IN_THIS_CONTEXT + eng "'%-.128s' is not allowed in this context" diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index e228b3ca211..999563275f4 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -59,7 +59,8 @@ bool fix_fields_for_tvc(THD *thd, List_iterator_fast<List_item> &li) while replacing their values to NAME_CONST()s. So fix only those that have not been. */ - if (item->fix_fields_if_needed(thd, 0)) + if (item->fix_fields_if_needed(thd, 0) || + item->check_is_evaluable_expression_or_error()) DBUG_RETURN(true); } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b946b8a9ee0..9984448da62 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13047,13 +13047,13 @@ expr_or_default: expr { $$= $1;} | DEFAULT { - $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context()); + $$= new (thd->mem_root) Item_default_specification(thd); if (unlikely($$ == NULL)) MYSQL_YYABORT; } | IGNORE_SYM { - $$= new (thd->mem_root) Item_ignore_value(thd, Lex->current_context()); + $$= new (thd->mem_root) Item_ignore_specification(thd); if (unlikely($$ == NULL)) MYSQL_YYABORT; } |