Commit 49b29e35 authored by Alexander Barkov's avatar Alexander Barkov

Merge remote-tracking branch 'origin/10.4' into 10.5

parents 3ea05d08 810b7f8e
...@@ -2610,3 +2610,14 @@ $$ ...@@ -2610,3 +2610,14 @@ $$
a a
0 0
1 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
...@@ -1339,3 +1339,17 @@ BEGIN NOT ATOMIC ...@@ -1339,3 +1339,17 @@ BEGIN NOT ATOMIC
END; END;
$$ $$
DELIMITER ;$$ 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;
...@@ -99,6 +99,13 @@ void item_init(void) ...@@ -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) void Item::push_note_converted_to_negative_complement(THD *thd)
{ {
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, 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) ...@@ -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 bool Item_param::can_return_value() const
{ {
// There's no "default". See comments in Item_param::save_in_field(). // 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) ...@@ -9229,12 +9253,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
Item_field *field_arg; Item_field *field_arg;
Field *def_field; Field *def_field;
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
DBUG_ASSERT(arg);
if (!arg)
{
fixed= 1;
return FALSE;
}
/* /*
DEFAULT() do not need table field so should not ask handler to bring DEFAULT() do not need table field so should not ask handler to bring
...@@ -9309,11 +9328,7 @@ void Item_default_value::cleanup() ...@@ -9309,11 +9328,7 @@ void Item_default_value::cleanup()
void Item_default_value::print(String *str, enum_query_type query_type) void Item_default_value::print(String *str, enum_query_type query_type)
{ {
if (!arg) DBUG_ASSERT(arg);
{
str->append(STRING_WITH_LEN("default"));
return;
}
str->append(STRING_WITH_LEN("default(")); str->append(STRING_WITH_LEN("default("));
/* /*
We take DEFAULT from a field so do not need it value in case of const 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) ...@@ -9327,6 +9342,7 @@ void Item_default_value::print(String *str, enum_query_type query_type)
void Item_default_value::calculate() void Item_default_value::calculate()
{ {
DBUG_ASSERT(arg);
if (field->default_value) if (field->default_value)
field->set_default(); field->set_default();
DEBUG_SYNC(field->table->in_use, "after_Item_default_value_calculate"); 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) ...@@ -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) 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);
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);
} }
table_map Item_default_value::used_tables() const table_map Item_default_value::used_tables() const
...@@ -9398,13 +9408,7 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer, ...@@ -9398,13 +9408,7 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer,
uchar *args) uchar *args)
{ {
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
DBUG_ASSERT(arg);
/*
If the value of arg is NULL, then this object represents a constant,
so further transformation is unnecessary (and impossible).
*/
if (!arg)
return 0;
Item *new_item= arg->transform(thd, transformer, args); Item *new_item= arg->transform(thd, transformer, args);
if (!new_item) if (!new_item)
...@@ -9421,57 +9425,6 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer, ...@@ -9421,57 +9425,6 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer,
return (this->*transformer)(thd, args); 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 bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
{ {
......
...@@ -763,6 +763,7 @@ class Item: public Value_source, ...@@ -763,6 +763,7 @@ class Item: public Value_source,
CONST_ITEM, CONST_ITEM,
NULL_ITEM, // Item_null or Item_param bound to NULL NULL_ITEM, // Item_null or Item_param bound to NULL
COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
CONTEXTUALLY_TYPED_VALUE_ITEM,
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
...@@ -843,6 +844,7 @@ class Item: public Value_source, ...@@ -843,6 +844,7 @@ class Item: public Value_source,
const Tmp_field_param *param, const Tmp_field_param *param,
bool is_explicit_null); bool is_explicit_null);
void raise_error_not_evaluable();
void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_negative_complement(THD *thd);
void push_note_converted_to_positive_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd);
...@@ -1607,6 +1609,24 @@ class Item: public Value_source, ...@@ -1607,6 +1609,24 @@ class Item: public Value_source,
positions. (And they can't be used before fix_fields is called for them). positions. (And they can't be used before fix_fields is called for them).
*/ */
virtual bool is_order_clause_position() const { return false; } 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) */ /* cloning of constant items (0 if it is not const) */
virtual Item *clone_item(THD *thd) { return 0; } virtual Item *clone_item(THD *thd) { return 0; }
/* deep copy item */ /* deep copy item */
...@@ -3858,6 +3878,7 @@ class Item_param :public Item_basic_value, ...@@ -3858,6 +3878,7 @@ class Item_param :public Item_basic_value,
const String *value_query_val_str(THD *thd, String* str) const; const String *value_query_val_str(THD *thd, String* str) const;
Item *value_clone_item(THD *thd); Item *value_clone_item(THD *thd);
bool is_evaluable_expression() const;
bool can_return_value() const; bool can_return_value() const;
public: public:
...@@ -6271,14 +6292,9 @@ class Item_default_value : public Item_field ...@@ -6271,14 +6292,9 @@ class Item_default_value : public Item_field
public: public:
Item *arg= nullptr; Item *arg= nullptr;
Field *cached_field= 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_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) :
Item_field(thd, context_arg), arg(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; } 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 eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
void cleanup(); void cleanup();
...@@ -6293,7 +6309,7 @@ class Item_default_value : public Item_field ...@@ -6293,7 +6309,7 @@ class Item_default_value : public Item_field
bool save_in_param(THD *thd, Item_param *param) bool save_in_param(THD *thd, Item_param *param)
{ {
// It should not be possible to have "EXECUTE .. USING DEFAULT(a)" // It should not be possible to have "EXECUTE .. USING DEFAULT(a)"
DBUG_ASSERT(arg == NULL); DBUG_ASSERT(0);
param->set_default(); param->set_default();
return false; return false;
} }
...@@ -6318,34 +6334,127 @@ class Item_default_value : public Item_field ...@@ -6318,34 +6334,127 @@ class Item_default_value : public Item_field
Item *transform(THD *thd, Item_transformer transformer, uchar *args); 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. This class is used as bulk parameter INGNORE representation.
It just do nothing when assigned to a field 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: public:
Item_ignore_value(THD *thd, Name_resolution_context *context_arg) Item_ignore_specification(THD *thd)
:Item_default_value(thd, context_arg) :Item_contextually_typed_value_specification(thd)
{}; { }
void print(String *str, enum_query_type query_type)
void print(String *str, enum_query_type query_type); {
int save_in_field(Field *field_arg, bool no_conversions); 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) bool save_in_param(THD *thd, Item_param *param)
{ {
param->set_ignore(); param->set_ignore();
return false; return false;
} }
String *val_str(String *str); Item *get_copy(THD *thd)
double val_real(); { return get_item_copy<Item_ignore_specification>(thd, this); }
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);
}; };
......
...@@ -3607,7 +3607,7 @@ static void get_win_tzname(char* buf, size_t size) ...@@ -3607,7 +3607,7 @@ static void get_win_tzname(char* buf, size_t size)
{0,0} {0,0}
}; };
DYNAMIC_TIME_ZONE_INFORMATION tzinfo; DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
if (GetDynamicTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_UNKNOWN) if (GetDynamicTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
{ {
strncpy(buf, "unknown", size); strncpy(buf, "unknown", size);
return; return;
......
...@@ -7961,3 +7961,5 @@ ER_KEY_CONTAINS_PERIOD_FIELDS ...@@ -7961,3 +7961,5 @@ ER_KEY_CONTAINS_PERIOD_FIELDS
eng "Key %`s cannot explicitly include column %`s" eng "Key %`s cannot explicitly include column %`s"
ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS
eng "Key %`s cannot have WITHOUT OVERLAPS" eng "Key %`s cannot have WITHOUT OVERLAPS"
ER_NOT_ALLOWED_IN_THIS_CONTEXT
eng "'%-.128s' is not allowed in this context"
...@@ -59,7 +59,8 @@ bool fix_fields_for_tvc(THD *thd, List_iterator_fast<List_item> &li) ...@@ -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. while replacing their values to NAME_CONST()s.
So fix only those that have not been. 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); DBUG_RETURN(true);
} }
} }
......
...@@ -13047,13 +13047,13 @@ expr_or_default: ...@@ -13047,13 +13047,13 @@ expr_or_default:
expr { $$= $1;} expr { $$= $1;}
| DEFAULT | DEFAULT
{ {
$$= new (thd->mem_root) Item_default_value(thd, Lex->current_context()); $$= new (thd->mem_root) Item_default_specification(thd);
if (unlikely($$ == NULL)) if (unlikely($$ == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| IGNORE_SYM | IGNORE_SYM
{ {
$$= new (thd->mem_root) Item_ignore_value(thd, Lex->current_context()); $$= new (thd->mem_root) Item_ignore_specification(thd);
if (unlikely($$ == NULL)) if (unlikely($$ == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
......
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