From 21ea14db8cc8c5d88ff804650de7caf984d08a98 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 22 Oct 2020 15:51:14 +0400 Subject: MDEV-20593 SIGSEGV in report_json_error_ex (on optimized builds). When first argument to the JSON_MERGE_PATCH was NULL and second - the invalid JSON line, the error code was garbage. So it should be set to 0 initially. --- sql/item_jsonfunc.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index b3c8366907a..7db1ae1ffaf 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -2429,6 +2429,8 @@ String *Item_func_json_merge_patch::val_str(String *str) uint n_arg; bool empty_result, merge_to_null; + /* To report errors properly if some JSON is invalid. */ + je1.s.error= je2.s.error= 0; merge_to_null= args[0]->null_value; for (n_arg=1; n_arg < arg_count; n_arg++) -- cgit v1.2.1 From 641f81baf45212569ec8a98072d62fd29e3fc8f0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Aug 2020 13:19:59 +0200 Subject: cleanup: use my_multi_malloc(), etc --- sql/sql_parse.cc | 2 +- sql/sql_select.cc | 18 ++++++------------ sql/sql_show.cc | 29 ++++++++++++----------------- 3 files changed, 19 insertions(+), 30 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8408771692d..88e6d01304f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7728,7 +7728,6 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool is_com_multi, bool is_next_command) { - int error __attribute__((unused)); DBUG_ENTER("mysql_parse"); DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on();); @@ -7808,6 +7807,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, (char *) thd->security_ctx->host_or_ip, 0); + int error __attribute__((unused)); error= mysql_execute_command(thd); MYSQL_QUERY_EXEC_DONE(error); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 738e1912994..461c7b18363 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17490,8 +17490,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, No need to change table name to lower case as we are only creating MyISAM, Aria or HEAP tables here */ - fn_format(path, path, mysql_tmpdir, "", - MY_REPLACE_EXT|MY_UNPACK_FILENAME); + fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME); if (group) { @@ -18673,14 +18672,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, } } - if (unlikely((error= maria_create(share->path.str, - file_type, - share->keys, &keydef, - (uint) (*recinfo-start_recinfo), - start_recinfo, - share->uniques, &uniquedef, - &create_info, - create_flags)))) + if (unlikely((error= maria_create(share->path.str, file_type, share->keys, + &keydef, (uint) (*recinfo-start_recinfo), + start_recinfo, share->uniques, &uniquedef, + &create_info, create_flags)))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ table->db_stat=0; @@ -18881,8 +18876,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, if (is_duplicate) *is_duplicate= FALSE; - if (table->s->db_type() != heap_hton || - error != HA_ERR_RECORD_FILE_FULL) + if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL) { /* We don't want this error to be converted to a warning, e.g. in case of diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0fe8b707472..2a569204908 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8165,7 +8165,7 @@ mark_all_fields_used_in_query(THD *thd, 0schema_table= 1; SELECT_LEX *select_lex= thd->lex->current_select; bool keep_row_order= is_show_command(thd); - if (!(table= create_tmp_table(thd, tmp_table_param, - field_list, (ORDER*) 0, 0, 0, - (select_lex->options | thd->variables.option_bits | - TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, - &table_list->alias, false, keep_row_order))) + if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, + 0, (select_lex->options | thd->variables.option_bits | + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, + &table_list->alias, false, keep_row_order))) DBUG_RETURN(0); my_bitmap_map* bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); @@ -8794,10 +8793,10 @@ bool optimize_schema_tables_reads(JOIN *join) cond= tab->cache_select->cond; } if (optimize_for_get_all_tables(thd, table_list, cond)) - DBUG_RETURN(TRUE); // Handle OOM + DBUG_RETURN(1); // Handle OOM } } - DBUG_RETURN(FALSE); + DBUG_RETURN(0); } @@ -8862,13 +8861,10 @@ bool get_schema_tables_result(JOIN *join, continue; /* - If schema table is already processed and - the statement is not a subselect then - we don't need to fill this table again. - If schema table is already processed and - schema_table_state != executed_place then - table is already processed and - we should skip second data processing. + If schema table is already processed and the statement is not a + subselect then we don't need to fill this table again. If schema table + is already processed and schema_table_state != executed_place then + table is already processed and we should skip second data processing. */ if (table_list->schema_table_state && (!is_subselect || table_list->schema_table_state != executed_place)) @@ -8930,8 +8926,7 @@ bool get_schema_tables_result(JOIN *join, It also means that an audit plugin cannot process the error correctly either. See also thd->clear_error() */ - thd->get_stmt_da()->push_warning(thd, - thd->get_stmt_da()->sql_errno(), + thd->get_stmt_da()->push_warning(thd, thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->get_sqlstate(), Sql_condition::WARN_LEVEL_ERROR, thd->get_stmt_da()->message()); -- cgit v1.2.1 From 6cefe7d31ef43cadb905d71be743462825c7b4ff Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Aug 2020 10:30:46 +0200 Subject: cleanup: use predefined CMAKE_DL_LIBS instead of, say, MY_SEARCH_LIBS(dlopen dl LIBDL) --- sql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8ed75f86067..5f5d7daf1a5 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -167,7 +167,7 @@ ADD_LIBRARY(sql STATIC ${SQL_SOURCE}) DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre - ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} + ${LIBWRAP} ${LIBCRYPT} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${WSREP_LIB} ${SSL_LIBRARIES} ${LIBSYSTEMD}) -- cgit v1.2.1 From e64084d5a3a72462fa6263d1d0a86e72c0ba0d47 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Aug 2020 13:12:50 +0200 Subject: MDEV-21201 No records produced in information_schema query, depending on projection Reimplement MDEV-14275 Improving memory utilization for information schema Postpone temp table instantiation until after setup_fields(). Replace all unused (not marked in read_set) columns in an I_S table with CHAR(0). This can drastically reduce the footprint of a MEMORY table (a TABLE_CATALOG alone is 1538 bytes per row). This does not change the engine. If the table was decided to be Aria (because of, say, blobs) then after optimization it'll stay Aria even if all blobs were removed. Note 1: when transforming table structure, share->blob_fields is preserved, otherwise Aria might switch from DYNAMIC to STATIC row format and expect a special field for a deleted mark, which create_tmp_tabe didn't provide. Note 2: optimizer was doing handler::info() (to know the number of rows) before the temp table is populated. That didn't make much sense. Now it's done before the table is even instantiated. Preserve the old behavior and report 0 rows. This reverts e2664ee8362 and a8458a2345e --- sql/set_var.cc | 3 - sql/sql_lex.cc | 16 ++--- sql/sql_parse.cc | 2 - sql/sql_select.cc | 20 +++--- sql/sql_show.cc | 180 +++++++++++++++++++++++------------------------------- sql/table.h | 1 - 6 files changed, 95 insertions(+), 127 deletions(-) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index eb2b9234db3..58b6b392449 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1068,7 +1068,6 @@ static void store_var(Field *field, sys_var *var, enum_var_type scope, int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) { char name_buffer[NAME_CHAR_LEN]; - enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; bool res= 1; CHARSET_INFO *scs= system_charset_info; StringBuffer strbuf(scs); @@ -1078,7 +1077,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_ASSERT(tables->table->in_use == thd); cond= make_cond_for_info_schema(thd, cond, tables); - thd->count_cuted_fields= CHECK_FIELD_WARN; mysql_prlock_rdlock(&LOCK_system_variables_hash); for (uint i= 0; i < system_variable_hash.records; i++) @@ -1243,7 +1241,6 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond) res= 0; end: mysql_prlock_unlock(&LOCK_system_variables_hash); - thd->count_cuted_fields= save_count_cuted_fields; return res; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4f64dbfbbf9..b5483c671de 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3312,21 +3312,21 @@ bool LEX::can_not_use_merged() } } -/* - Detect that we need only table structure of derived table/view +/** + Detect that we need only table structure of derived table/view. - SYNOPSIS - only_view_structure() + Also used by I_S tables (@see create_schema_table) to detect that + they need a full table structure and cannot optimize unused columns away - RETURN - TRUE yes, we need only structure - FALSE no, we need data + @retval TRUE yes, we need only structure + @retval FALSE no, we need data */ bool LEX::only_view_structure() { switch (sql_command) { case SQLCOM_SHOW_CREATE: + case SQLCOM_CHECKSUM: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_FIELDS: case SQLCOM_REVOKE_ALL: @@ -3334,6 +3334,8 @@ bool LEX::only_view_structure() case SQLCOM_GRANT: case SQLCOM_CREATE_VIEW: return TRUE; + case SQLCOM_CREATE_TABLE: + return create_info.like(); default: return FALSE; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 88e6d01304f..1b382ce0136 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8905,8 +8905,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields, SELECT_LEX *lex) { b->natural_join= a; - a->part_of_natural_join= TRUE; - b->part_of_natural_join= TRUE; lex->prev_join_using= using_fields; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 461c7b18363..37755387dda 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2468,6 +2468,10 @@ int JOIN::optimize_stage2() (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) | (select_lex->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0); + if (select_lex->options & OPTION_SCHEMA_TABLE && + optimize_schema_tables_reads(this)) + DBUG_RETURN(1); + if (make_join_readinfo(this, select_opts_for_readinfo, no_jbuf_after)) DBUG_RETURN(1); @@ -2644,10 +2648,6 @@ int JOIN::optimize_stage2() having_is_correlated= MY_TEST(having->used_tables() & OUTER_REF_TABLE_BIT); tmp_having= having; - if ((select_lex->options & OPTION_SCHEMA_TABLE) && - optimize_schema_tables_reads(this)) - DBUG_RETURN(TRUE); - if (unlikely(thd->is_error())) DBUG_RETURN(TRUE); @@ -17138,15 +17138,11 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) { Field *field; if (max_length > MAX_FIELD_VARCHARLENGTH) - field= new (thd->mem_root) Field_blob(max_length, maybe_null, &name, - collation.collation); - else if (max_length > 0) - field= new (thd->mem_root) Field_varstring(max_length, maybe_null, &name, - table->s, - collation.collation); - else - field= new Field_null((uchar*) 0, 0, Field::NONE, &name, + field= new Field_blob(max_length, maybe_null, &name, collation.collation); + else + field= new Field_varstring(max_length, maybe_null, &name, + table->s, collation.collation); if (field) field->init(table); return field; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2a569204908..6bd8c9b5c27 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3700,8 +3700,6 @@ static bool show_status_array(THD *thd, const char *wild, CHARSET_INFO *charset= system_charset_info; DBUG_ENTER("show_status_array"); - thd->count_cuted_fields= CHECK_FIELD_WARN; - prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1); if (*prefix) *prefix_end++= '_'; @@ -3801,6 +3799,8 @@ static bool show_status_array(THD *thd, const char *wild, pos= get_one_variable(thd, var, scope, show_type, status_var, &charset, buff, &length); + if (table->field[1]->field_length) + thd->count_cuted_fields= CHECK_FIELD_WARN; table->field[1]->store(pos, (uint32) length, charset); thd->count_cuted_fields= CHECK_FIELD_IGNORE; table->field[1]->set_notnull(); @@ -8108,51 +8108,6 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx) return &schema_tables[schema_table_idx]; } -static void -mark_all_fields_used_in_query(THD *thd, - ST_FIELD_INFO *schema_fields, - MY_BITMAP *bitmap, - Item *all_items) -{ - Item *item; - DBUG_ENTER("mark_all_fields_used_in_query"); - - /* If not SELECT command, return all columns */ - if (thd->lex->sql_command != SQLCOM_SELECT && - thd->lex->sql_command != SQLCOM_SET_OPTION) - { - bitmap_set_all(bitmap); - DBUG_VOID_RETURN; - } - - for (item= all_items ; item ; item= item->next) - { - if (item->type() == Item::FIELD_ITEM) - { - ST_FIELD_INFO *fields= schema_fields; - uint count; - Item_field *item_field= (Item_field*) item; - - /* item_field can be '*' as this function is called before fix_fields */ - if (item_field->field_name.str == star_clex_str.str) - { - bitmap_set_all(bitmap); - break; - } - for (count=0; fields->field_name; fields++, count++) - { - if (!my_strcasecmp(system_charset_info, fields->field_name, - item_field->field_name.str)) - { - bitmap_set_bit(bitmap, count); - break; - } - } - } - } - DBUG_VOID_RETURN; -} - /** Create information_schema table using schema_table data. @@ -8176,37 +8131,19 @@ mark_all_fields_used_in_query(THD *thd, TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) { - uint field_count; - Item *item, *all_items; + uint field_count= 0; + Item *item; TABLE *table; List field_list; ST_SCHEMA_TABLE *schema_table= table_list->schema_table; ST_FIELD_INFO *fields_info= schema_table->fields_info; - ST_FIELD_INFO *fields; CHARSET_INFO *cs= system_charset_info; MEM_ROOT *mem_root= thd->mem_root; - MY_BITMAP bitmap; - my_bitmap_map *buf; + bool need_all_fieds= table_list->schema_table_reformed || // SHOW command + thd->lex->only_view_structure(); // need table structure DBUG_ENTER("create_schema_table"); - for (field_count= 0, fields= fields_info; fields->field_name; fields++) - field_count++; - if (!(buf= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)))) - DBUG_RETURN(NULL); - my_bitmap_init(&bitmap, buf, field_count, 0); - - if (!thd->stmt_arena->is_conventional() && - thd->mem_root != thd->stmt_arena->mem_root) - all_items= thd->stmt_arena->free_list; - else - all_items= thd->free_list; - - if (table_list->part_of_natural_join) - bitmap_set_all(&bitmap); - else - mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items); - - for (field_count=0; fields_info->field_name; fields_info++) + for (; fields_info->field_name; fields_info++) { size_t field_name_length= strlen(fields_info->field_name); switch (fields_info->field_type) { @@ -8283,44 +8220,19 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: - if (bitmap_is_set(&bitmap, field_count)) - { - if (!(item= new (mem_root) - Item_blob(thd, fields_info->field_name, - fields_info->field_length))) - { - DBUG_RETURN(0); - } - } - else - { - if (!(item= new (mem_root) - Item_empty_string(thd, "", 0, cs))) - { - DBUG_RETURN(0); - } - item->set_name(thd, fields_info->field_name, - field_name_length, cs); - } + if (!(item= new (mem_root) Item_blob(thd, fields_info->field_name, + fields_info->field_length))) + DBUG_RETURN(0); break; default: - { - bool show_field; /* Don't let unimplemented types pass through. Could be a grave error. */ DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING); - - show_field= bitmap_is_set(&bitmap, field_count); - if (!(item= new (mem_root) - Item_empty_string(thd, "", - show_field ? fields_info->field_length : 0, cs))) - { + if (!(item= new (mem_root) Item_empty_string(thd, "", + fields_info->field_length, cs))) DBUG_RETURN(0); - } - item->set_name(thd, fields_info->field_name, - field_name_length, cs); + item->set_name(thd, fields_info->field_name, field_name_length, cs); break; } - } field_list.push_back(item, thd->mem_root); item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL); field_count++; @@ -8335,7 +8247,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, - &table_list->alias, false, keep_row_order))) + &table_list->alias, !need_all_fieds, keep_row_order))) DBUG_RETURN(0); my_bitmap_map* bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); @@ -8751,6 +8663,67 @@ end: } +static int optimize_schema_tables_memory_usage(TABLE_LIST *table_list) +{ + TABLE *table= table_list->table; + THD *thd=table->in_use; + if (!table->is_created()) + { + TMP_TABLE_PARAM *p= table_list->schema_table_param; + TMP_ENGINE_COLUMNDEF *from_recinfo, *to_recinfo; + DBUG_ASSERT(table->s->keys == 0); + DBUG_ASSERT(table->s->uniques == 0); + + // XXX HACK HACK HACK: in a stored function, RETURN (SELECT ...) + // enables warnings (in THD::sp_eval_expr) for the whole val_xxx/store pair, + // while the intention is to warn only for store(). Until this is + // fixed let's avoid data truncation warnings in I_S->fill_table() + if (thd->count_cuted_fields == CHECK_FIELD_IGNORE) + { + + uchar *cur= table->field[0]->ptr; + /* first recinfo could be a NULL bitmap, not an actual Field */ + from_recinfo= to_recinfo= p->start_recinfo + (cur != table->record[0]); + for (uint i=0; i < table->s->fields; i++, from_recinfo++) + { + Field *field= table->field[i]; + DBUG_ASSERT(field->vcol_info == 0); + DBUG_ASSERT(from_recinfo->length= field->pack_length_in_rec()); + if (bitmap_is_set(table->read_set, i)) + { + field->move_field(cur); + *to_recinfo++= *from_recinfo; + cur+= from_recinfo->length; + } + else + { + field= new (thd->mem_root) Field_string(cur, 0, field->null_ptr, + field->null_bit, Field::NONE, + &field->field_name, field->dtcollation()); + field->init(table); + field->field_index= i; + DBUG_ASSERT(field->pack_length_in_rec() == 0); + table->field[i]= field; + } + } + if ((table->s->reclength= (ulong)(cur - table->record[0])) == 0) + { + /* all fields were optimized away. Force a non-0-length row */ + table->s->reclength= to_recinfo->length= 1; + to_recinfo++; + } + p->recinfo= to_recinfo; + } // XXX end of HACK HACK HACK + + // TODO switch from Aria to Memory if all blobs were optimized away? + if (instantiate_tmp_table(table, p->keyinfo, p->start_recinfo, &p->recinfo, + table_list->select_lex->options | thd->variables.option_bits)) + return 1; + } + return 0; +} + + /* This is the optimizer part of get_schema_tables_result(). */ @@ -8771,6 +8744,9 @@ bool optimize_schema_tables_reads(JOIN *join) TABLE_LIST *table_list= tab->table->pos_in_table_list; if (table_list->schema_table && thd->fill_information_schema_tables()) { + if (optimize_schema_tables_memory_usage(table_list)) + DBUG_RETURN(1); + /* A value of 0 indicates a dummy implementation */ if (table_list->schema_table->fill_table == 0) continue; diff --git a/sql/table.h b/sql/table.h index a42feba68c4..c7e7a39b46f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2190,7 +2190,6 @@ struct TABLE_LIST parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ TABLE_LIST *natural_join; - bool part_of_natural_join; /* True if 'this' represents a nested join that is a NATURAL JOIN. For one of the operands of 'this', the member 'natural_join' points -- cgit v1.2.1 From 15f03c204159325c343bd8c793f71edad0be3347 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 31 Aug 2020 09:54:46 +0200 Subject: MDEV-23492 performance_schema_digests_size changing from default to 5000 when enabling performance_schema max allowed value limit should be larger than any auto-sized value --- sql/sys_vars.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index af261299496..2a582a098fb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -323,7 +323,7 @@ static Sys_var_long Sys_pfs_digest_size( "Size of the statement digest." " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing), - CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 200), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024 * 1024), DEFAULT(-1), BLOCK_SIZE(1)); -- cgit v1.2.1 From 2cd5df8c83d018d1aa58c8426b8406c3c6528d7e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 1 Oct 2020 16:35:55 +0200 Subject: MDEV-23656 view: removal of parentheses results in wrong result Item_ref should have the precedence of the item it's referencing --- sql/item.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 4a761bfd70a..6c48d570203 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4541,7 +4541,11 @@ public: { (*ref)->restore_to_before_no_rows_in_result(); } - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type); + enum precedence precedence() const + { + return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE; + } void cleanup(); Item_field *field_for_view_update() { return (*ref)->field_for_view_update(); } -- cgit v1.2.1 From 8c83e6eadf496267762313d577653d56bf98d945 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Oct 2020 14:32:14 +0200 Subject: cleanup: remove redundant ADDINTERVAL_PRECEDENCE expression between INTERVAL and the unit doesns not need any precedence rules, there's no ambiguity there --- sql/item.h | 3 +-- sql/item_timefunc.cc | 4 ++-- sql/item_timefunc.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 6c48d570203..604f656aa7a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -87,7 +87,7 @@ enum precedence { BITOR_PRECEDENCE, // | BITAND_PRECEDENCE, // & SHIFT_PRECEDENCE, // <<, >> - ADDINTERVAL_PRECEDENCE, // first argument in +INTERVAL + INTERVAL_PRECEDENCE, // first argument in +INTERVAL ADD_PRECEDENCE, // +, - MUL_PRECEDENCE, // *, /, DIV, %, MOD BITXOR_PRECEDENCE, // ^ @@ -95,7 +95,6 @@ enum precedence { NEG_PRECEDENCE, // unary -, ~ BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE) COLLATE_PRECEDENCE, // BINARY, COLLATE - INTERVAL_PRECEDENCE, // INTERVAL DEFAULT_PRECEDENCE, HIGHEST_PRECEDENCE }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 194933a4c54..a40c2e18b91 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2250,9 +2250,9 @@ static const char *interval_names[]= void Item_date_add_interval::print(String *str, enum_query_type query_type) { - args[0]->print_parenthesised(str, query_type, ADDINTERVAL_PRECEDENCE); + args[0]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE); str->append(date_sub_interval?" - interval ":" + interval "); - args[1]->print_parenthesised(str, query_type, INTERVAL_PRECEDENCE); + args[1]->print(str, query_type); str->append(' '); str->append(interval_names[int_type]); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index f25fe3a551f..5c2c2ebe1ac 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -942,7 +942,7 @@ public: bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); - enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; } + enum precedence precedence() const { return INTERVAL_PRECEDENCE; } bool need_parentheses_in_default() { return true; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } -- cgit v1.2.1 From 7f974e5ad3317168f174465dc61c0feb27c04162 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Oct 2020 15:07:34 +0200 Subject: cleanup: remove redundant BANG_PRECEDENCE prefix unary operators don't need to have different precedence, the syntax unambiguously specifies in what order they apply --- sql/item.h | 3 +-- sql/item_cmpfunc.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 604f656aa7a..b789f703c2e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -92,8 +92,7 @@ enum precedence { MUL_PRECEDENCE, // *, /, DIV, %, MOD BITXOR_PRECEDENCE, // ^ PIPES_PRECEDENCE, // || (if PIPES_AS_CONCAT) - NEG_PRECEDENCE, // unary -, ~ - BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE) + NEG_PRECEDENCE, // unary -, ~, !, NOT (if HIGH_NOT_PRECEDENCE) COLLATE_PRECEDENCE, // BINARY, COLLATE DEFAULT_PRECEDENCE, HIGHEST_PRECEDENCE diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index cad179dff74..579b1bde1ce 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -574,7 +574,7 @@ public: longlong val_int(); enum Functype functype() const { return NOT_FUNC; } const char *func_name() const { return "not"; } - enum precedence precedence() const { return BANG_PRECEDENCE; } + enum precedence precedence() const { return NEG_PRECEDENCE; } Item *neg_transformer(THD *thd); bool fix_fields(THD *, Item **); virtual void print(String *str, enum_query_type query_type); -- cgit v1.2.1 From 05a878c139963d4859ef8f2c974fee5dae56ee51 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Oct 2020 12:50:51 +0200 Subject: precedence bugfixing fix printing precedence for BETWEEN, LIKE/ESCAPE, REGEXP, IN don't use precedence for printing CASE/WHEN/THEN/ELSE/END fix parsing precedence of BETWEEN, LIKE/ESCAPE, REGEXP, IN support predicate arguments for IN, BETWEEN, SOUNDS LIKE, LIKE/ESCAPE, REGEXP use %nonassoc for unary operators fix parsing of IS TRUE/FALSE/UNKNOWN/NULL remove parser_precedence test as superseded by the precedence test --- sql/item.h | 7 ++- sql/item_cmpfunc.cc | 14 +++--- sql/item_cmpfunc.h | 7 ++- sql/item_func.cc | 3 +- sql/item_subselect.cc | 2 +- sql/item_subselect.h | 2 +- sql/sql_yacc.yy | 115 ++++++++++++++++++++++++++------------------------ 7 files changed, 79 insertions(+), 71 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index b789f703c2e..a49f9e8e5e4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -82,8 +82,9 @@ enum precedence { XOR_PRECEDENCE, // XOR AND_PRECEDENCE, // AND, && NOT_PRECEDENCE, // NOT (unless HIGH_NOT_PRECEDENCE) - BETWEEN_PRECEDENCE, // BETWEEN, CASE, WHEN, THEN, ELSE - CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN + CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS + BETWEEN_PRECEDENCE, // BETWEEN + IN_PRECEDENCE, // IN, LIKE, REGEXP BITOR_PRECEDENCE, // | BITAND_PRECEDENCE, // & SHIFT_PRECEDENCE, // <<, >> @@ -1381,6 +1382,8 @@ public: mysql_register_view(). */ virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; } + enum precedence higher_precedence() const + { return (enum precedence)(precedence() + 1); } void print_parenthesised(String *str, enum_query_type query_type, enum precedence parent_prec); /** diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 69c7eb33852..d3a59e5b4f0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2312,7 +2312,7 @@ longlong Item_func_between::val_int() void Item_func_between::print(String *str, enum_query_type query_type) { - args[0]->print_parenthesised(str, query_type, precedence()); + args[0]->print_parenthesised(str, query_type, higher_precedence()); if (negated) str->append(STRING_WITH_LEN(" not")); str->append(STRING_WITH_LEN(" between ")); @@ -3375,15 +3375,15 @@ void Item_func_case::print(String *str, enum_query_type query_type) for (uint i= first_expr_num + 1 ; i < nwhens + first_expr_num + 1; i++) { str->append(STRING_WITH_LEN("when ")); - args[i]->print_parenthesised(str, query_type, precedence()); + args[i]->print(str, query_type); str->append(STRING_WITH_LEN(" then ")); - args[i+nwhens]->print_parenthesised(str, query_type, precedence()); + args[i+nwhens]->print(str, query_type); str->append(' '); } if (else_expr_num != -1) { str->append(STRING_WITH_LEN("else ")); - args[else_expr_num]->print_parenthesised(str, query_type, precedence()); + args[else_expr_num]->print(str, query_type); str->append(' '); } str->append(STRING_WITH_LEN("end")); @@ -5243,12 +5243,14 @@ void Item_func_like::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN(" not ")); str->append(func_name()); str->append(' '); - args[1]->print_parenthesised(str, query_type, precedence()); if (escape_used_in_parsing) { + args[1]->print_parenthesised(str, query_type, precedence()); str->append(STRING_WITH_LEN(" escape ")); - escape_item->print(str, query_type); + escape_item->print_parenthesised(str, query_type, higher_precedence()); } + else + args[1]->print_parenthesised(str, query_type, higher_precedence()); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 579b1bde1ce..22736339bf6 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1590,7 +1590,6 @@ public: uint decimal_precision() const; table_map not_null_tables() const { return 0; } const char *func_name() const { return "case"; } - enum precedence precedence() const { return BETWEEN_PRECEDENCE; } virtual void print(String *str, enum_query_type query_type); Item *find_item(String *str); CHARSET_INFO *compare_collation() const { return cmp_collation.collation; } @@ -1704,7 +1703,7 @@ public: virtual void print(String *str, enum_query_type query_type); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return "in"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool eval_not_null_tables(void *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool count_sargable_conds(void *arg); @@ -1999,7 +1998,7 @@ public: return this; } const char *func_name() const { return "like"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec() { @@ -2127,7 +2126,7 @@ public: bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec(); const char *func_name() const { return "regexp"; } - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } void print(String *str, enum_query_type query_type) { diff --git a/sql/item_func.cc b/sql/item_func.cc index 9d588ce0eb1..cc4a0157d1a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -481,8 +481,7 @@ void Item_func::print_op(String *str, enum_query_type query_type) str->append(func_name()); str->append(' '); } - args[arg_count-1]->print_parenthesised(str, query_type, - (enum precedence)(precedence() + 1)); + args[arg_count-1]->print_parenthesised(str, query_type, higher_precedence()); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0499a677be9..802bfca64b7 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3283,7 +3283,7 @@ void Item_in_subselect::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("")); else { - left_expr->print(str, query_type); + left_expr->print_parenthesised(str, query_type, precedence()); str->append(STRING_WITH_LEN(" in ")); } Item_subselect::print(str, query_type); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 816073ed5d3..2292c22480f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -628,7 +628,7 @@ public: bool val_bool(); bool test_limit(st_select_lex_unit *unit); void print(String *str, enum_query_type query_type); - enum precedence precedence() const { return CMP_PRECEDENCE; } + enum precedence precedence() const { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref); bool fix_length_and_dec(); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 138d5e13701..2eabc4f0a6d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -149,6 +149,14 @@ void LEX::parse_error() } +static Item* escape(THD *thd) +{ + thd->lex->escape_used= false; + const char *esc= thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES ? "" : "\\"; + return new (thd->mem_root) Item_string_ascii(thd, esc, MY_TEST(esc[0])); +} + + /** @brief Bison callback to report a syntax/OOM error @@ -1022,10 +1030,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 102 shift/reduce conflicts. + Currently there are 105 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 101 +%expect 105 /* Comments for TOKENS. @@ -1721,17 +1729,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %left OR_OR_SYM OR_SYM OR2_SYM %left XOR %left AND_SYM AND_AND_SYM -%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE -%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE REGEXP IN_SYM +%nonassoc NOT_SYM +%left '=' EQUAL_SYM GE '>' LE '<' NE +%nonassoc IS +%right BETWEEN_SYM +%left LIKE REGEXP IN_SYM %left '|' %left '&' %left SHIFT_LEFT SHIFT_RIGHT %left '-' '+' %left '*' '/' '%' DIV_SYM MOD_SYM %left '^' -%left NEG '~' -%right NOT_SYM NOT2_SYM -%right BINARY COLLATE_SYM +%nonassoc NEG '~' NOT2_SYM BINARY +%nonassoc COLLATE_SYM %left INTERVAL_SYM %type @@ -1831,7 +1841,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); table_wild simple_expr column_default_non_parenthesized_expr udf_expr expr_or_default set_expr_or_default geometry_function signed_literal expr_or_literal - opt_escape sp_opt_default simple_ident_nospvar simple_ident_q field_or_var limit_option @@ -8915,59 +8924,59 @@ expr: if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS TRUE_SYM %prec IS + | expr IS TRUE_SYM %prec IS { $$= new (thd->mem_root) Item_func_istrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not TRUE_SYM %prec IS + | expr IS not TRUE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnottrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS FALSE_SYM %prec IS + | expr IS FALSE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not FALSE_SYM %prec IS + | expr IS not FALSE_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS UNKNOWN_SYM %prec IS + | expr IS UNKNOWN_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not UNKNOWN_SYM %prec IS + | expr IS not UNKNOWN_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri - ; - -bool_pri: - bool_pri IS NULL_SYM %prec IS + | expr IS NULL_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri IS not NULL_SYM %prec IS + | expr IS not NULL_SYM %prec IS { $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } - | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM + | bool_pri + ; + +bool_pri: + bool_pri EQUAL_SYM predicate %prec EQUAL_SYM { $$= new (thd->mem_root) Item_func_equal(thd, $1, $3); if ($$ == NULL) @@ -8989,13 +8998,13 @@ bool_pri: ; predicate: - bit_expr IN_SYM '(' subselect ')' + predicate IN_SYM '(' subselect ')' { $$= new (thd->mem_root) Item_in_subselect(thd, $1, $4); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' subselect ')' + | predicate not IN_SYM '(' subselect ')' { Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $5); if (item == NULL) @@ -9004,13 +9013,13 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr IN_SYM '(' expr ')' + | predicate IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(thd, $1, true, $4); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr IN_SYM '(' expr ',' expr_list ')' + | predicate IN_SYM '(' expr ',' expr_list ')' { $6->push_front($4, thd->mem_root); $6->push_front($1, thd->mem_root); @@ -9018,13 +9027,13 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' expr ')' + | predicate not IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(thd, $1, false, $5); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not IN_SYM '(' expr ',' expr_list ')' + | predicate not IN_SYM '(' expr ',' expr_list ')' { $7->push_front($5, thd->mem_root); $7->push_front($1, thd->mem_root); @@ -9033,13 +9042,13 @@ predicate: MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate + | predicate BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM { $$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate + | predicate not BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM { Item_func_between *item; item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6); @@ -9047,7 +9056,7 @@ predicate: MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr SOUNDS_SYM LIKE bit_expr + | predicate SOUNDS_SYM LIKE predicate { Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1); Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4); @@ -9057,28 +9066,41 @@ predicate: if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr LIKE simple_expr opt_escape + | predicate LIKE predicate + { + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, escape(thd), false); + if ($$ == NULL) + MYSQL_YYABORT; + } + | predicate LIKE predicate ESCAPE_SYM predicate %prec LIKE { - $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4, - Lex->escape_used); + Lex->escape_used= true; + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $5, true); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not LIKE simple_expr opt_escape + | predicate not LIKE predicate + { + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, escape(thd), false); + if (item == NULL) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate not LIKE predicate ESCAPE_SYM predicate %prec LIKE { - Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5, - Lex->escape_used); + Lex->escape_used= true; + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $6, true); if (item == NULL) MYSQL_YYABORT; $$= item->neg_transformer(thd); } - | bit_expr REGEXP bit_expr + | predicate REGEXP predicate { $$= new (thd->mem_root) Item_func_regex(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } - | bit_expr not REGEXP bit_expr + | predicate not REGEXP predicate { Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4); if (item == NULL) @@ -11468,23 +11490,6 @@ opt_having_clause: } ; -opt_escape: - ESCAPE_SYM simple_expr - { - Lex->escape_used= TRUE; - $$= $2; - } - | /* empty */ - { - Lex->escape_used= FALSE; - $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? - new (thd->mem_root) Item_string_ascii(thd, "", 0) : - new (thd->mem_root) Item_string_ascii(thd, "\\", 1)); - if ($$ == NULL) - MYSQL_YYABORT; - } - ; - /* group by statement in select */ -- cgit v1.2.1 From b94e8e4b25e039b5f165339b8ee0fd4af856459c Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 23 Oct 2020 12:32:49 +0530 Subject: MDEV-23867: insert... select crash in compute_window_func There are 2 issues here: Issue #1: memory allocation. An IO_CACHE that uses encryption uses a larger buffer (it needs space for the encrypted data, decrypted data, IO_CACHE_CRYPT struct to describe encryption parameters etc). Issue #2: IO_CACHE::seek_not_done When IO_CACHE objects are cloned, they still share the file descriptor. This means, operation on one IO_CACHE may change the file read position which will confuse other IO_CACHEs using it. The fix of these issues would be: Allocate the buffer to also include the extra size needed for encryption. Perform seek again after one IO_CACHE reads the file. --- sql/mf_iocache_encr.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sql') diff --git a/sql/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc index d741cf8b837..29d7074aeb1 100644 --- a/sql/mf_iocache_encr.cc +++ b/sql/mf_iocache_encr.cc @@ -71,6 +71,16 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count) DBUG_RETURN(1); } info->seek_not_done= 0; + if (info->next_file_user) + { + IO_CACHE *c; + for (c= info->next_file_user; + c!= info; + c= c->next_file_user) + { + c->seek_not_done= 1; + } + } } do -- cgit v1.2.1 From 4e987b1c6ba7a0d73c5df54ae0af2805c081b0c3 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 22 Apr 2020 20:13:21 +0200 Subject: MDEV-22313: Neither SHOW CREATE USER nor SHOW GRANTS prints a user's default role Reviewed-by: serg@mariadb.com --- sql/sql_acl.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 894988c4931..641ab69c2a7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -353,8 +353,9 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname); static ulong get_sort(uint count,...); static bool show_proxy_grants (THD *, const char *, const char *, char *, size_t); -static bool show_role_grants(THD *, const char *, const char *, +static bool show_role_grants(THD *, const char *, ACL_USER_BASE *, char *, size_t); +static bool show_default_role(THD *, ACL_USER *, char *, size_t); static bool show_global_privileges(THD *, ACL_USER_BASE *, bool, char *, size_t); static bool show_database_privileges(THD *, const char *, const char *, @@ -8531,7 +8532,7 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role) { char buff[1024]; - if (show_role_grants(thd, role->user.str, "", role, buff, sizeof(buff))) + if (show_role_grants(thd, "", role, buff, sizeof(buff))) return TRUE; if (show_global_privileges(thd, role, TRUE, buff, sizeof(buff))) @@ -8746,7 +8747,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) } /* Show granted roles to acl_user */ - if (show_role_grants(thd, username, hostname, acl_user, buff, sizeof(buff))) + if (show_role_grants(thd, hostname, acl_user, buff, sizeof(buff))) goto end; /* Add first global access grants */ @@ -8795,6 +8796,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) } } + if (username) + { + /* Show default role to acl_user */ + if (show_default_role(thd, acl_user, buff, sizeof(buff))) + goto end; + } + + error= 0; end: mysql_mutex_unlock(&acl_cache->lock); @@ -8821,15 +8830,44 @@ static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_STRING *u, my_hash_search(&acl_roles_mappings, (uchar*)pair_key.ptr(), key_length); } -static bool show_role_grants(THD *thd, const char *username, - const char *hostname, ACL_USER_BASE *acl_entry, +static bool show_default_role(THD *thd, ACL_USER *acl_entry, + char *buff, size_t buffsize) +{ + Protocol *protocol= thd->protocol; + LEX_STRING def_rolename= acl_entry->default_rolename; + + if (def_rolename.length) + { + String def_str(buff, buffsize, system_charset_info); + def_str.length(0); + def_str.append(STRING_WITH_LEN("SET DEFAULT ROLE ")); + def_str.append(&def_rolename); + def_str.append(" FOR '"); + def_str.append(&acl_entry->user); + DBUG_ASSERT(!(acl_entry->flags & IS_ROLE)); + def_str.append(STRING_WITH_LEN("'@'")); + def_str.append(acl_entry->host.hostname, acl_entry->hostname_length, + system_charset_info); + def_str.append('\''); + protocol->prepare_for_resend(); + protocol->store(def_str.ptr(),def_str.length(),def_str.charset()); + if (protocol->write()) + { + return TRUE; + } + } + return FALSE; +} + +static bool show_role_grants(THD *thd, const char *hostname, + ACL_USER_BASE *acl_entry, char *buff, size_t buffsize) { uint counter; Protocol *protocol= thd->protocol; LEX_STRING host= {const_cast(hostname), strlen(hostname)}; - String grant(buff,sizeof(buff),system_charset_info); + String grant(buff, buffsize, system_charset_info); for (counter= 0; counter < acl_entry->role_grants.elements; counter++) { grant.length(0); @@ -8873,7 +8911,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, ulong want_access; Protocol *protocol= thd->protocol; - String global(buff,sizeof(buff),system_charset_info); + String global(buff, buffsize, system_charset_info); global.length(0); global.append(STRING_WITH_LEN("GRANT ")); @@ -8952,7 +8990,7 @@ static bool show_database_privileges(THD *thd, const char *username, want_access=acl_db->initial_access; if (want_access) { - String db(buff,sizeof(buff),system_charset_info); + String db(buff, buffsize, system_charset_info); db.length(0); db.append(STRING_WITH_LEN("GRANT ")); -- cgit v1.2.1 From 6a614d6934a85e8228957fe1d7242928a00dc5ff Mon Sep 17 00:00:00 2001 From: mkaruza Date: Wed, 21 Oct 2020 09:48:52 +0200 Subject: MDEV-22707: galera got stuck after flush tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deadlock is possible between applier thread and local committing thread with active FLUSH TABLE. Applier thread should skip table share checks and locks when opening table. Reviewed-by: Jan Lindström --- sql/sql_base.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cc77b58cb3e..497c6a0322f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1859,7 +1859,12 @@ retry_share: DBUG_RETURN(FALSE); } +#ifdef WITH_WSREP + if (!((flags & MYSQL_OPEN_IGNORE_FLUSH) || + (wsrep_on(thd) && thd->wsrep_applier))) +#else if (!(flags & MYSQL_OPEN_IGNORE_FLUSH)) +#endif { if (share->tdc->flushed) { -- cgit v1.2.1 From 97b10b7fdc268c25dc52d1e960b1f89b1c7db38c Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Tue, 27 Oct 2020 18:55:22 +0700 Subject: MDEV-22805: SIGSEGV in check_fields on UPDATE For debug build of MariaDB server running of the following test case will hit the assert `thd->lex->sql_command == SQLCOM_UPDATE' in the function check_fields() on attempt to execute the UPDATE statement. CREATE TABLE t1 (a INT); UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT 1 FROM t1) TO 2 SET a = 1; Stack trace to the fired assert statement DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE) listed below: mysql_execute_command() -> mysql_multi_update_prepare() --> Multiupdate_prelocking_strategy::handle_end() --> check_fiels() It's worth to note that this stack trace looks like a multi update statement is being executed. The fired assert is checked inside the function check_fields() in case table->has_period() returns the value true that in turns happens when temporal period specified in the UPDATE statement. Condition specified in the DEBUG_ASSERT statement returns the false value since the data member thd->lex->sql_command have the value SQLCOM_UPDATE_MULTI. So, the main question is why a program control flow go to the path prescribed for handling MULTI update statement despite of the fact that the ordinary UPDATE statement being executed. The answer is a way that SQL grammar rules written. When the statement UPDATE t1 FOR PORTION OF APPTIME FROM (SELECT 1 FROM t1) TO 2 SET a = 1; being parsed an action for the rule 'table_primary_ident' (part of this action is listed below to simplify description) is invoked to handle the table name 't1' specified in the clause 'SELECT 1 FROM t1'. table_primary_ident: table_ident opt_use_partition opt_for_system_time_clause opt_table_alias_clause opt_key_definition { SELECT_LEX *sel= Select; sel->table_join_options= 0; if (!($$= Select->add_table_to_list(thd, $1, $4, This action calls the method st_select_lex::add_table_to_list() to add the table name 't1' to the list of tables being used by the statement. Later, an action for the following grammar rule update_table_list: table_ident opt_use_partition for_portion_of_time_clause opt_table_alias_clause opt_key_definition { SELECT_LEX *sel= Select; sel->table_join_options= 0; if (!($$= Select->add_table_to_list(thd, $1, $4, is invoked to handle the clause 't1 FOR PORTION OF APPTIME FROM ... TO 2'. This action also calls the method st_select_lex::add_table_to_list() to add the table name 't1' to the list of tables being used by the statement. In result the table name 't1' contained twice in this list. Presence of duplicate names for the table 't1' in a list of table used by a statement leads to the fact that the function unique_table() called from the function mysql_update() returns the value true that forces implementation of the function mysql_update() to return the value 2 as a signal to fall through the case boundary of the switch statement placed in the function mysql_execute_statement() and start handling of the case for sql_command SQLCOM_UPDATE_MULTI. The compound statement block for the case SQLCOM_UPDATE_MULTI invokes the function mysql_multi_update_prepare() that executes the statement set thd->lex->sql_command= SQLCOM_UPDATE_MULTI; and after that calls the method Multiupdate_prelocking_strategy::handle_end(). Finally, this method invokes the check_field() function and assert is fired. The above analysis shows that update for a table that simultaneously specified both as a destination table of UPDATE statement and as a table taking part in subquery is actually treated by MariaDB server as multi-update statement. Taking into account that multi-update statement for temporal period table is not supported yet by MariaDB, correct way to fix the bug is to return the error ER_NOT_SUPPORTED_YET for this case. --- sql/sql_parse.cc | 5 +++++ sql/sql_update.cc | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7504863f394..e8c94c6b363 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4373,6 +4373,11 @@ mysql_execute_command(THD *thd) /* mysql_update return 2 if we need to switch to multi-update */ if (up_result != 2) break; + if (thd->lex->period_conditions.is_set()) + { + DBUG_ASSERT(0); // Should never happen + goto error; + } } /* fall through */ case SQLCOM_UPDATE_MULTI: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 31a015dd0e2..c687b6ca2f5 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -420,6 +420,14 @@ int mysql_update(THD *thd, DBUG_PRINT("info", ("Switch to multi-update")); /* pass counter value */ thd->lex->table_count= table_count; + if (thd->lex->period_conditions.is_set()) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "updating and querying the same temporal periods table"); + + DBUG_RETURN(1); + } + /* convert to multiupdate */ DBUG_RETURN(2); } -- cgit v1.2.1 From 8761571a71f0d628c5a82abed115e170d63e34c0 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 27 Oct 2020 00:30:39 +0400 Subject: MDEV-22524 SIGABRT in safe_mutex_unlock with session_track_system_variables and max_relay_log_size. lock LOCK_global_system_variables around the get_one_variable() call in the Session_sysvars_tracker::store_variable(). --- sql/session_tracker.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index b73bd1d1d4a..4ef8cbfd706 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -772,8 +772,11 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr) show.name= svar->name.str; show.value= (char *) svar; + mysql_mutex_lock(&LOCK_global_system_variables); const char *value= get_one_variable(thd, &show, OPT_SESSION, SHOW_SYS, NULL, &charset, val_buf, &val_length); + mysql_mutex_unlock(&LOCK_global_system_variables); + if (is_plugin) mysql_mutex_unlock(&LOCK_plugin); -- cgit v1.2.1 From ec0e9d6f76b1715bb7e229f8361b42476c016734 Mon Sep 17 00:00:00 2001 From: Teemu Ollakka Date: Sun, 25 Oct 2020 11:17:27 +0200 Subject: MDEV-22681 EXECUTE IMMEDIATE crashes server if wsrep is on. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A wsrep transaction was started for EXECUTE IMMEDIATE, which caused assertion failure when the executed statement was CREATE TABLE which should be executed in TOI mode. As a fix, don't start wsrep transaction for EXECUTE IMMEDIATE to let the wsrep state logic to be handled from inside stored procedure codepath. Reviewed-by: Jan Lindström --- sql/sql_parse.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e8c94c6b363..05a1ee57d63 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3792,6 +3792,7 @@ mysql_execute_command(THD *thd) lex->sql_command != SQLCOM_BEGIN && lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE && + lex->sql_command != SQLCOM_EXECUTE_IMMEDIATE && !(sql_command_flags[lex->sql_command] & CF_AUTO_COMMIT_TRANS)) { wsrep_start_trx_if_not_started(thd); -- cgit v1.2.1