summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2020-05-19 12:36:58 +0400
committerAlexander Barkov <bar@mariadb.com>2020-05-19 12:36:58 +0400
commit49b29e35b2099fcbc3342814fc0ce9c17ba1bdeb (patch)
treee830a8a54e6640c3e30d171f4ad6e37f347e146d
parent3ea05d08427dc3d679fef838e9334685f556cc32 (diff)
parent810b7f8ecbea0fbf52e03aa710a8059ea301f7dc (diff)
downloadmariadb-git-49b29e35b2099fcbc3342814fc0ce9c17ba1bdeb.tar.gz
Merge remote-tracking branch 'origin/10.4' into 10.5
-rw-r--r--mysql-test/main/table_value_constr.result11
-rw-r--r--mysql-test/main/table_value_constr.test14
-rw-r--r--sql/item.cc107
-rw-r--r--sql/item.h147
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/sql_tvc.cc3
-rw-r--r--sql/sql_yacc.yy4
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;
}