Re: [Maria-developers] 7311586ca25: MDEV-15703 Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
Hi, Oleksandr! On Jul 29, Oleksandr Byelkin wrote:
revision-id: 7311586ca25 (mariadb-10.2.31-317-g7311586ca25) parent(s): a1e52e7f32c author: Oleksandr Byelkin <sanja@mariadb.com> committer: Oleksandr Byelkin <sanja@mariadb.com> timestamp: 2020-07-17 13:47:26 +0200 message:
MDEV-15703 Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
Part 1: make better asserts.
diff --git a/sql/field.cc b/sql/field.cc index 65bd9d22857..cf0cc655888 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -11138,6 +11138,16 @@ bool Field::save_in_field_default_value(bool view_error_processing) { THD *thd= table->in_use;
+ if ( // table is not opened properly + table == NULL || table->pos_in_table_list == NULL || + table->pos_in_table_list->select_lex == NULL || + // we are in subquery/derived/CTE + !table->pos_in_table_list->top_table()->select_lex->is_top_level_select()) + { + DBUG_ASSERT(0); // shoud not happened + my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; + }
that's kind of questionable. if this condition can never be true, why do you have my_error() there? Just do asserts, like DBUG_ASSERT(table); DBUG_ASSERT(table->pos_in_table_list); DBUG_ASSERT(table->pos_in_table_list->select_lex); DBUG_ASSERT(table->pos_in_table_list->top_table()->select_lex->is_top_level_select());
if (flags & NO_DEFAULT_VALUE_FLAG && real_type() != MYSQL_TYPE_ENUM) { @@ -11177,12 +11187,29 @@ bool Field::save_in_field_default_value(bool view_error_processing) bool Field::save_in_field_ignore_value(bool view_error_processing) { enum_sql_command com= table->in_use->lex->sql_command; + + if ( // table is not opened properly + table == NULL || table->pos_in_table_list == NULL || + table->pos_in_table_list->select_lex == NULL || + // we are in subquery/derived/CTE + !table->pos_in_table_list->top_table()->select_lex->is_top_level_select()) + { + DBUG_ASSERT(0); // shoud not happened + my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; + }
ditto
// All insert-like commands if (com == SQLCOM_INSERT || com == SQLCOM_REPLACE || com == SQLCOM_INSERT_SELECT || com == SQLCOM_REPLACE_SELECT || com == SQLCOM_LOAD) return save_in_field_default_value(view_error_processing); - return 0; // ignore + if (com == SQLCOM_UPDATE || com == SQLCOM_UPDATE_MULTI) + return 0; // ignore + + // unexpected command + DBUG_ASSERT(0); // shoud not happened
ditto but why it should not happen? What if one does SELECT DEFAULT(f) FROM t?
+ my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; }
diff --git a/sql/item.cc b/sql/item.cc index 9451d4203ca..382eb3ac47a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3930,13 +3930,19 @@ int Item_param::save_in_field(Field *field, bool no_conversions) case NULL_VALUE: return set_field_to_null_with_conversions(field, no_conversions); case DEFAULT_VALUE: - return field->save_in_field_default_value(field->table->pos_in_table_list-> + return field->save_in_field_default_value((field->table && + field->table->pos_in_table_list)?
in what case can field->table be NULL here?
+ field->table->pos_in_table_list-> top_table() != - field->table->pos_in_table_list); + field->table->pos_in_table_list: + FALSE); case IGNORE_VALUE: - return field->save_in_field_ignore_value(field->table->pos_in_table_list-> + return field->save_in_field_ignore_value((field->table && + field->table->pos_in_table_list)? + field->table->pos_in_table_list-> top_table() != - field->table->pos_in_table_list); + field->table->pos_in_table_list: + FALSE); case NO_VALUE: DBUG_ASSERT(0); // Should not be possible return true;
Regards, Sergei VP of MariaDB Server Engineering and security@mariadb.org
Hi! On Wed, Jul 29, 2020 at 2:39 PM Sergei Golubchik <serg@mariadb.org> wrote:
Hi, Oleksandr!
On Jul 29, Oleksandr Byelkin wrote:
revision-id: 7311586ca25 (mariadb-10.2.31-317-g7311586ca25) parent(s): a1e52e7f32c author: Oleksandr Byelkin <sanja@mariadb.com> committer: Oleksandr Byelkin <sanja@mariadb.com> timestamp: 2020-07-17 13:47:26 +0200 message:
MDEV-15703 Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
Part 1: make better asserts.
diff --git a/sql/field.cc b/sql/field.cc index 65bd9d22857..cf0cc655888 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -11138,6 +11138,16 @@ bool Field::save_in_field_default_value(bool view_error_processing) { THD *thd= table->in_use;
+ if ( // table is not opened properly + table == NULL || table->pos_in_table_list == NULL || + table->pos_in_table_list->select_lex == NULL || + // we are in subquery/derived/CTE + !table->pos_in_table_list->top_table()->select_lex->is_top_level_select()) + { + DBUG_ASSERT(0); // shoud not happened + my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; + }
that's kind of questionable. if this condition can never be true, why do you have my_error() there? Just do asserts, like
DBUG_ASSERT(table); DBUG_ASSERT(table->pos_in_table_list); DBUG_ASSERT(table->pos_in_table_list->select_lex);
DBUG_ASSERT(table->pos_in_table_list->top_table()->select_lex->is_top_level_select());
It was the first solution to catch the problem on the low level, now we catch it earlier and in many places, but if we forget something on non-debug builds it will just work.
if (flags & NO_DEFAULT_VALUE_FLAG && real_type() != MYSQL_TYPE_ENUM) { @@ -11177,12 +11187,29 @@ bool Field::save_in_field_default_value(bool view_error_processing) bool Field::save_in_field_ignore_value(bool view_error_processing) { enum_sql_command com= table->in_use->lex->sql_command; + + if ( // table is not opened properly + table == NULL || table->pos_in_table_list == NULL || + table->pos_in_table_list->select_lex == NULL || + // we are in subquery/derived/CTE + !table->pos_in_table_list->top_table()->select_lex->is_top_level_select()) + { + DBUG_ASSERT(0); // shoud not happened + my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; + }
ditto
the same as above
// All insert-like commands if (com == SQLCOM_INSERT || com == SQLCOM_REPLACE || com == SQLCOM_INSERT_SELECT || com == SQLCOM_REPLACE_SELECT || com == SQLCOM_LOAD) return save_in_field_default_value(view_error_processing); - return 0; // ignore + if (com == SQLCOM_UPDATE || com == SQLCOM_UPDATE_MULTI) + return 0; // ignore + + // unexpected command + DBUG_ASSERT(0); // shoud not happened
ditto
but why it should not happen? What if one does SELECT DEFAULT(f) FROM t?
we think that we caught all cases with: 1) calls of Item_(param|default|ignore)::val_* (it is old way, was here for long time) 2) checks Item::is_evaluable_expression() before save_in_fields() where it is possible
+ my_error(ER_INVALID_DEFAULT_PARAM, MYF(0)); + return false; }
diff --git a/sql/item.cc b/sql/item.cc index 9451d4203ca..382eb3ac47a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3930,13 +3930,19 @@ int Item_param::save_in_field(Field *field, bool no_conversions) case NULL_VALUE: return set_field_to_null_with_conversions(field, no_conversions); case DEFAULT_VALUE: - return field->save_in_field_default_value(field->table->pos_in_table_list-> + return field->save_in_field_default_value((field->table && + field->table->pos_in_table_list)?
in what case can field->table be NULL here?
probably impossible (I thought it is for fake fields in SP, but it looks like they have fake table also)
+ field->table->pos_in_table_list-> top_table() != - field->table->pos_in_table_list); + field->table->pos_in_table_list: + FALSE); case IGNORE_VALUE: - return field->save_in_field_ignore_value(field->table->pos_in_table_list-> + return field->save_in_field_ignore_value((field->table && + field->table->pos_in_table_list)? + field->table->pos_in_table_list-> top_table() != - field->table->pos_in_table_list); + field->table->pos_in_table_list: + FALSE); case NO_VALUE: DBUG_ASSERT(0); // Should not be possible return true;
Regards, Sergei VP of MariaDB Server Engineering and security@mariadb.org
Hi, Oleksandr! On Jul 29, Oleksandr Byelkin wrote:
@@ -3930,13 +3930,19 @@ int Item_param::save_in_field(Field *field, bool no_conversions) case NULL_VALUE: return set_field_to_null_with_conversions(field, no_conversions); case DEFAULT_VALUE: - return field->save_in_field_default_value(field->table->pos_in_table_list-> + return field->save_in_field_default_value((field->table && + field->table->pos_in_table_list)?
in what case can field->table be NULL here?
probably impossible (I thought it is for fake fields in SP, but it looks like they have fake table also)
revert the change, then? Regards, Sergei VP of MariaDB Server Engineering and security@mariadb.org
participants (2)
-
Oleksandr Byelkin
-
Sergei Golubchik