diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 15 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_subselect.cc | 44 | ||||
-rw-r--r-- | sql/item_subselect.h | 1 | ||||
-rw-r--r-- | sql/parse_file.cc | 21 | ||||
-rw-r--r-- | sql/semisync_master.cc | 6 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 38 | ||||
-rw-r--r-- | sql/sp_head.cc | 2 | ||||
-rw-r--r-- | sql/sql_acl.cc | 13 | ||||
-rw-r--r-- | sql/sql_analyse.cc | 60 | ||||
-rw-r--r-- | sql/sql_base.cc | 23 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 5 | ||||
-rw-r--r-- | sql/sql_cte.cc | 100 | ||||
-rw-r--r-- | sql/sql_cte.h | 20 | ||||
-rw-r--r-- | sql/sql_debug.h | 168 | ||||
-rw-r--r-- | sql/sql_lex.cc | 18 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 24 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 4 | ||||
-rw-r--r-- | sql/sql_repl.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 30 | ||||
-rw-r--r-- | sql/sql_string.cc | 11 | ||||
-rw-r--r-- | sql/sql_string.h | 51 | ||||
-rw-r--r-- | sql/sql_table.cc | 8 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 25 | ||||
-rw-r--r-- | sql/sql_trigger.h | 4 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 9 | ||||
-rw-r--r-- | sql/sql_view.cc | 84 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 | ||||
-rw-r--r-- | sql/table.cc | 67 | ||||
-rw-r--r-- | sql/table.h | 67 |
33 files changed, 669 insertions, 263 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 09f494268d5..e39ee8246a6 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3772,7 +3772,22 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) for (i= 0; i < m_tot_parts; i++) { if (!bitmap_is_set(&m_is_clone_of->m_opened_partitions, i)) + { + /* Here we should just create the handler instance, not open it. */ + if (!(m_file[i]= get_new_handler(table->s, m_clone_mem_root, + file[i]->ht))) + { + error= HA_ERR_INITIALIZATION; + file= &m_file[i]; + goto err_handler; + } + if (m_file[i]->set_ha_share_ref(file[i]->ha_share)) + { + error= HA_ERR_INITIALIZATION; + goto err_handler; + } continue; + } if (unlikely((error= create_partition_name(name_buff, sizeof(name_buff), name, name_buffer_ptr, diff --git a/sql/item.h b/sql/item.h index e38860dfbbb..bc7f72e971b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2163,7 +2163,6 @@ public: virtual bool enumerate_field_refs_processor(void *arg) { return 0; } virtual bool mark_as_eliminated_processor(void *arg) { return 0; } virtual bool eliminate_subselect_processor(void *arg) { return 0; } - virtual bool set_fake_select_as_master_processor(void *arg) { return 0; } virtual bool view_used_tables_processor(void *arg) { return 0; } virtual bool eval_not_null_tables(void *arg) { return 0; } virtual bool is_subquery_processor(void *arg) { return 0; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index afd060d576a..bc71d8cf159 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -399,50 +399,6 @@ bool Item_subselect::eliminate_subselect_processor(void *arg) } -/** - Adjust the master select of the subquery to be the fake_select which - represents the whole UNION right above the subquery, instead of the - last query of the UNION. - - @param arg pointer to the fake select - - @return - FALSE to force the evaluation of the processor for the subsequent items. -*/ - -bool Item_subselect::set_fake_select_as_master_processor(void *arg) -{ - SELECT_LEX *fake_select= (SELECT_LEX*) arg; - /* - Move the st_select_lex_unit of a subquery from a global ORDER BY clause to - become a direct child of the fake_select of a UNION. In this way the - ORDER BY that is applied to the temporary table that contains the result of - the whole UNION, and all columns in the subquery are resolved against this - table. The transformation is applied only for immediate child subqueries of - a UNION query. - */ - if (unit->outer_select()->master_unit()->fake_select_lex == fake_select) - { - /* - Set the master of the subquery to be the fake select (i.e. the whole - UNION), instead of the last query in the UNION. - */ - fake_select->add_slave(unit); - DBUG_ASSERT(unit->outer_select() == fake_select); - /* Adjust the name resolution context hierarchy accordingly. */ - for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) - sl->context.outer_context= &(fake_select->context); - /* - Undo Item_subselect::eliminate_subselect_processor because at that phase - we don't know yet that the ORDER clause will be moved to the fake select. - */ - unit->item= this; - eliminated= FALSE; - } - return FALSE; -} - - bool Item_subselect::mark_as_dependent(THD *thd, st_select_lex *select, Item *item) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 426b76f8067..69154fef8e8 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -240,7 +240,6 @@ public: bool unknown_splocal_processor(void *arg) override; bool mark_as_eliminated_processor(void *arg) override; bool eliminate_subselect_processor(void *arg) override; - bool set_fake_select_as_master_processor(void *arg) override; bool enumerate_field_refs_processor(void *arg) override; bool check_vcol_func_processor(void *arg) override { diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 57140019341..f4aae1300e2 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -175,11 +175,12 @@ write_parameter(IO_CACHE *file, const uchar* base, File_option *parameter) { /* string have to be allocated already */ LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset); - time_t tm= my_time(0); - - get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH, - tm); - val_s->length= PARSE_FILE_TIMESTAMPLENGTH; + // number of microseconds since Epoch, timezone-independent + my_hrtime_t tm= my_hrtime(); + // Paded to 19 characters for compatibility + val_s->length= snprintf(val_s->str, MICROSECOND_TIMESTAMP_BUFFER_SIZE, + "%019lld", tm.val); + DBUG_ASSERT(val_s->length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1); if (my_b_write(file, (const uchar *)val_s->str, PARSE_FILE_TIMESTAMPLENGTH)) DBUG_RETURN(TRUE); @@ -884,16 +885,16 @@ File_parser::parse(uchar* base, MEM_ROOT *mem_root, { /* string have to be allocated already */ LEX_STRING *val= (LEX_STRING *)(base + parameter->offset); - /* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */ - if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n') + /* 19 characters of timestamp */ + if (ptr[MICROSECOND_TIMESTAMP_BUFFER_SIZE-1] != '\n') { my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), parameter->name.str, line); DBUG_RETURN(TRUE); } - memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH); - val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0'; - ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1); + memcpy(val->str, ptr, MICROSECOND_TIMESTAMP_BUFFER_SIZE-1); + val->str[val->length= MICROSECOND_TIMESTAMP_BUFFER_SIZE-1]= '\0'; + ptr+= MICROSECOND_TIMESTAMP_BUFFER_SIZE; break; } case FILE_OPTIONS_STRLIST: diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc index 0e72ff441c4..b57fc199826 100644 --- a/sql/semisync_master.cc +++ b/sql/semisync_master.cc @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Google Inc. Copyright (c) 2008, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB + Copyright (c) 2011, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -275,12 +275,16 @@ void Active_tranx::clear_active_tranx_nodes(const char *log_file_name, Tranx_node *curr_node, *next_node; /* Delete all transaction nodes before the confirmation point. */ +#ifdef DBUG_TRACE int n_frees = 0; +#endif curr_node = m_trx_front; while (curr_node != new_front) { next_node = curr_node->next; +#ifdef DBUG_TRACE n_frees++; +#endif /* Remove the node from the hash table. */ unsigned int hash_val = get_hash_value(curr_node->log_name, curr_node->log_pos); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index de3f0e74155..53814b16578 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -3389,25 +3389,25 @@ ER_NONEXISTING_GRANT 42000 swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'" ukr "Повноважень не визначено для користувача '%-.48s' з хосту '%-.64s'" ER_TABLEACCESS_DENIED_ERROR 42000 - chi "%-.100T 命令的权限拒绝用户 '%s'@'%s' 用在表 '%-.192s'" - cze "%-.100T příkaz nepřístupný pro uživatele: '%s'@'%s' pro tabulku '%-.192s'" - dan "%-.100T-kommandoen er ikke tilladt for brugeren '%s'@'%s' for tabellen '%-.192s'" - eng "%-.100T command denied to user '%s'@'%s' for table '%-.192s'" - est "%-.100T käsk ei ole lubatud kasutajale '%s'@'%s' tabelis '%-.192s'" - fre "La commande '%-.100T' est interdite à l'utilisateur: '%s'@'%s' sur la table '%-.192s'" - ger "%-.100T Befehl nicht erlaubt für Benutzer '%s'@'%s' auf Tabelle '%-.192s'" - hun "%-.100T parancs a '%s'@'%s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban" - ita "Comando %-.100T negato per l'utente: '%s'@'%s' sulla tabella '%-.192s'" - jpn "コマンド %-.100T は ユーザー '%s'@'%s' ,テーブル '%-.192s' に対して許可されていません" - kor "'%-.100T' 명령은 다음 사용자에게 거부되었습니다. : '%s'@'%s' for 테이블 '%-.192s'" - nla "%-.100T commando geweigerd voor gebruiker: '%s'@'%s' voor tabel '%-.192s'" - por "Comando '%-.100T' negado para o usuário '%s'@'%s' na tabela '%-.192s'" - rum "Comanda %-.100T interzisa utilizatorului: '%s'@'%s' pentru tabela '%-.192s'" - rus "Команда %-.100T запрещена пользователю '%s'@'%s' для таблицы '%-.192s'" - serbian "%-.100T komanda zabranjena za korisnika '%s'@'%s' za tabelu '%-.192s'" - spa "%-.100T comando denegado a usuario '%s'@'%s' para la tabla '%-.192s'" - swe "%-.100T ej tillåtet för '%s'@'%s' för tabell '%-.192s'" - ukr "%-.100T команда заборонена користувачу: '%s'@'%s' у таблиці '%-.192s'" + chi "%-.100T 命令的权限拒绝用户 '%s'@'%s' 用在表 %`s.%`s" + cze "%-.100T příkaz nepřístupný pro uživatele: '%s'@'%s' pro tabulku %`s.%`s" + dan "%-.100T-kommandoen er ikke tilladt for brugeren '%s'@'%s' for tabellen %`s.%`s" + nla "%-.100T commando geweigerd voor gebruiker: '%s'@'%s' voor tabel %`s.%`s" + eng "%-.100T command denied to user '%s'@'%s' for table %`s.%`s" + est "%-.100T käsk ei ole lubatud kasutajale '%s'@'%s' tabelis %`s.%`s" + fre "La commande '%-.100T' est interdite à l'utilisateur: '%s'@'%s' sur la table %`s.%`s" + ger "%-.100T Befehl nicht erlaubt für Benutzer '%s'@'%s' auf Tabelle %`s.%`s" + hun "%-.100T parancs a '%s'@'%s' felhasznalo szamara nem engedelyezett a %`s.%`s tablaban" + ita "Comando %-.100T negato per l'utente: '%s'@'%s' sulla tabella %`s.%`s" + jpn "コマンド %-.100T は ユーザー '%s'@'%s' ,テーブル %`s.%`s に対して許可されていません" + kor "'%-.100T' 명령은 다음 사용자에게 거부되었습니다. : '%s'@'%s' for 테이블 %`s.%`s" + por "Comando '%-.100T' negado para o usuário '%s'@'%s' na tabela %`s.%`s" + rum "Comanda %-.100T interzisa utilizatorului: '%s'@'%s' pentru tabela %`s.%`s" + rus "Команда %-.100T запрещена пользователю '%s'@'%s' для таблицы %`s.%`s" + serbian "%-.100T komanda zabranjena za korisnika '%s'@'%s' za tabelu %`s.%`s" + spa "%-.100T comando denegado a usuario '%s'@'%s' para la tabla %`s.%`s" + swe "%-.100T ej tillåtet för '%s'@'%s' för tabell %`s.%`s" + ukr "%-.100T команда заборонена користувачу: '%s'@'%s' у таблиці %`s.%`s" ER_COLUMNACCESS_DENIED_ERROR 42000 chi "%-.32s 命令的权限拒绝用户 '%s'@'%s' 用在列 '%-.192s' 在表 '%-.192s'" cze "%-.32s příkaz nepřístupný pro uživatele: '%s'@'%s' pro sloupec '%-.192s' v tabulce '%-.192s'" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index de7fa61bfa1..0fec4c9f3d7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1883,7 +1883,7 @@ sp_head::execute_trigger(THD *thd, my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc, thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - table_name->str); + db_name->str, table_name->str); m_security_ctx.restore_security_context(thd, save_ctx); DBUG_RETURN(TRUE); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c77fbfceaa1..ba3cafa69ab 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7124,7 +7124,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, table_list->grant.want_privilege); my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), command, thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, table_list->alias.str); + thd->security_ctx->host_or_ip, table_list->db.str, + table_list->alias.str); DBUG_RETURN(-1); } } @@ -8176,8 +8177,8 @@ bool grant_reload(THD *thd) @see check_table_access @note - This functions assumes that either number of tables to be inspected - by it is limited explicitly (i.e. is is not UINT_MAX) or table list + This function assumes that either number of tables to be inspected + by it is limited explicitly (i.e. is not UINT_MAX) or table list used and thd->lex->query_tables_own_last value correspond to each other (the latter should be either 0 or point to next_global member of one of elements of this table list). @@ -8382,7 +8383,7 @@ err: my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), command, sctx->priv_user, - sctx->host_or_ip, + sctx->host_or_ip, tl ? tl->db.str : "unknown", tl ? tl->get_table_name() : "unknown"); } DBUG_RETURN(TRUE); @@ -8566,7 +8567,7 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg, Security_context *sctx= thd->security_ctx; privilege_t want_access(NO_ACL); const char *table_name= NULL; - const char* db_name; + const char* db_name= NULL; GRANT_INFO *grant; GRANT_TABLE *UNINIT_VAR(grant_table); GRANT_TABLE *UNINIT_VAR(grant_table_role); @@ -8655,7 +8656,7 @@ err: if (using_column_privileges) my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), command, sctx->priv_user, - sctx->host_or_ip, table_name); + sctx->host_or_ip, db_name, table_name); else my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), command, diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index d609fff5487..a0d32145abe 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -409,7 +409,7 @@ void field_real::add() if ((decs = decimals()) >= FLOATING_POINT_DECIMALS) { - length= sprintf(buff, "%g", num); + length= snprintf(buff, sizeof(buff), "%g", num); if (rint(num) != num) max_notzero_dec_len = 1; } @@ -420,7 +420,7 @@ void field_real::add() snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num); length = (uint) strlen(buff); #else - length= sprintf(buff, "%-.*f", (int) decs, num); + length= snprintf(buff, sizeof(buff), "%-.*f", (int) decs, num); #endif // We never need to check further than this @@ -814,32 +814,32 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) if (can_be_still_num) { if (num_info.is_float) - sprintf(buff, "DOUBLE"); // number was like 1e+50... TODO: + snprintf(buff, sizeof(buff), "DOUBLE"); // number was like 1e+50... TODO: else if (num_info.decimals) // DOUBLE(%d,%d) sometime { if (num_info.dval > -FLT_MAX && num_info.dval < FLT_MAX) - sprintf(buff, "FLOAT(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals); + snprintf(buff, sizeof(buff), "FLOAT(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals); else - sprintf(buff, "DOUBLE(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals); + snprintf(buff, sizeof(buff), "DOUBLE(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals); } else if (ev_num_info.llval >= -128 && ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ? 255 : 127)) - sprintf(buff, "TINYINT(%d)", num_info.integers); + snprintf(buff, sizeof(buff), "TINYINT(%d)", num_info.integers); else if (ev_num_info.llval >= INT_MIN16 && ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ? UINT_MAX16 : INT_MAX16)) - sprintf(buff, "SMALLINT(%d)", num_info.integers); + snprintf(buff, sizeof(buff), "SMALLINT(%d)", num_info.integers); else if (ev_num_info.llval >= INT_MIN24 && ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ? UINT_MAX24 : INT_MAX24)) - sprintf(buff, "MEDIUMINT(%d)", num_info.integers); + snprintf(buff, sizeof(buff), "MEDIUMINT(%d)", num_info.integers); else if (ev_num_info.llval >= INT_MIN32 && ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ? UINT_MAX32 : INT_MAX32)) - sprintf(buff, "INT(%d)", num_info.integers); + snprintf(buff, sizeof(buff), "INT(%d)", num_info.integers); else - sprintf(buff, "BIGINT(%d)", num_info.integers); + snprintf(buff, sizeof(buff), "BIGINT(%d)", num_info.integers); answer->append(buff, (uint) strlen(buff)); if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0) answer->append(STRING_WITH_LEN(" UNSIGNED")); @@ -857,12 +857,12 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) } else if ((max_length * (total_rows - nulls)) < (sum + total_rows)) { - sprintf(buff, "CHAR(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "CHAR(%d)", (int) max_length); answer->append(buff, (uint) strlen(buff)); } else { - sprintf(buff, "VARCHAR(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "VARCHAR(%d)", (int) max_length); answer->append(buff, (uint) strlen(buff)); } } @@ -901,18 +901,18 @@ void field_real::get_opt_type(String *answer, 0 : (item->decimals + 1)); if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127)) - sprintf(buff, "TINYINT(%d)", len); + snprintf(buff, sizeof(buff), "TINYINT(%d)", len); else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ? UINT_MAX16 : INT_MAX16)) - sprintf(buff, "SMALLINT(%d)", len); + snprintf(buff, sizeof(buff), "SMALLINT(%d)", len); else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ? UINT_MAX24 : INT_MAX24)) - sprintf(buff, "MEDIUMINT(%d)", len); + snprintf(buff, sizeof(buff), "MEDIUMINT(%d)", len); else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ? UINT_MAX32 : INT_MAX32)) - sprintf(buff, "INT(%d)", len); + snprintf(buff, sizeof(buff), "INT(%d)", len); else - sprintf(buff, "BIGINT(%d)", len); + snprintf(buff, sizeof(buff), "BIGINT(%d)", len); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) answer->append(STRING_WITH_LEN(" UNSIGNED")); @@ -927,10 +927,10 @@ void field_real::get_opt_type(String *answer, else { if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX) - sprintf(buff, "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len, + snprintf(buff, sizeof(buff), "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len, max_notzero_dec_len); else - sprintf(buff, "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len, + snprintf(buff, sizeof(buff), "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len, max_notzero_dec_len); answer->append(buff, (uint) strlen(buff)); } @@ -949,18 +949,18 @@ void field_longlong::get_opt_type(String *answer, char buff[MAX_FIELD_WIDTH]; if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127)) - sprintf(buff, "TINYINT(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "TINYINT(%d)", (int) max_length); else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ? UINT_MAX16 : INT_MAX16)) - sprintf(buff, "SMALLINT(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "SMALLINT(%d)", (int) max_length); else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ? UINT_MAX24 : INT_MAX24)) - sprintf(buff, "MEDIUMINT(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "MEDIUMINT(%d)", (int) max_length); else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ? UINT_MAX32 : INT_MAX32)) - sprintf(buff, "INT(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "INT(%d)", (int) max_length); else - sprintf(buff, "BIGINT(%d)", (int) max_length); + snprintf(buff, sizeof(buff), "BIGINT(%d)", (int) max_length); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) answer->append(STRING_WITH_LEN(" UNSIGNED")); @@ -980,15 +980,15 @@ void field_ulonglong::get_opt_type(String *answer, char buff[MAX_FIELD_WIDTH]; if (max_arg < 256) - sprintf(buff, "TINYINT(%d) UNSIGNED", (int) max_length); + snprintf(buff, sizeof(buff), "TINYINT(%d) UNSIGNED", (int) max_length); else if (max_arg <= ((2 * INT_MAX16) + 1)) - sprintf(buff, "SMALLINT(%d) UNSIGNED", (int) max_length); + snprintf(buff, sizeof(buff), "SMALLINT(%d) UNSIGNED", (int) max_length); else if (max_arg <= ((2 * INT_MAX24) + 1)) - sprintf(buff, "MEDIUMINT(%d) UNSIGNED", (int) max_length); + snprintf(buff, sizeof(buff), "MEDIUMINT(%d) UNSIGNED", (int) max_length); else if (max_arg < (((ulonglong) 1) << 32)) - sprintf(buff, "INT(%d) UNSIGNED", (int) max_length); + snprintf(buff, sizeof(buff), "INT(%d) UNSIGNED", (int) max_length); else - sprintf(buff, "BIGINT(%d) UNSIGNED", (int) max_length); + snprintf(buff, sizeof(buff), "BIGINT(%d) UNSIGNED", (int) max_length); // if item is FIELD_ITEM, it _must_be_ Field_num in this class answer->append(buff, (uint) strlen(buff)); if (item->type() == Item::FIELD_ITEM && @@ -1009,7 +1009,7 @@ void field_decimal::get_opt_type(String *answer, my_decimal_set_zero(&zero); my_bool is_unsigned= (zero.cmp(&min_arg) >= 0); - length= sprintf(buff, "DECIMAL(%d, %d)", + length= snprintf(buff, sizeof(buff), "DECIMAL(%d, %d)", (int) (max_length - (item->decimals ? 1 : 0)), item->decimals); if (is_unsigned) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 90fd7953124..3defb1f7d69 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1933,6 +1933,11 @@ retry_share: table_list->alias.str); goto err_lock; } + + /* Open view */ + if (mysql_make_view(thd, share, table_list, false)) + goto err_lock; + /* This table is a view. Validate its metadata version: in particular, that it was a view when the statement was prepared. @@ -1940,10 +1945,6 @@ retry_share: if (check_and_update_table_version(thd, table_list, share)) goto err_lock; - /* Open view */ - if (mysql_make_view(thd, share, table_list, false)) - goto err_lock; - /* TODO: Don't free this */ tdc_release_share(share); @@ -2836,7 +2837,7 @@ static bool inject_reprepare(THD *thd) @sa Execute_observer @sa check_prepared_statement() to see cases when an observer is installed - @sa TABLE_LIST::is_table_ref_id_equal() + @sa TABLE_LIST::is_the_same_definition() @sa TABLE_SHARE::get_table_ref_id() @param[in] thd used to report errors @@ -2859,7 +2860,7 @@ check_and_update_table_version(THD *thd, created with TABLE_LIST::init_one_table() have a short life time and aren't linked anywhere. */ - if (tables->prev_global && !tables->is_table_ref_id_equal(table_share)) + if (tables->prev_global && !tables->is_the_same_definition(thd, table_share)) { if (thd->m_reprepare_observer && thd->m_reprepare_observer->report_error(thd)) @@ -2965,7 +2966,9 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags) DBUG_ASSERT(share->is_view); - if (flags & CHECK_METADATA_VERSION) + err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE)); + + if (!err && (flags & CHECK_METADATA_VERSION)) { /* Check TABLE_SHARE-version of view only if we have been instructed to do @@ -2980,7 +2983,6 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags) goto ret; } - err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE)); ret: tdc_release_share(share); @@ -8293,19 +8295,20 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tables->is_natural_join); DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *fld= (Item_field*) item; + const char *field_db_name= field_iterator.get_db_name(); const char *field_table_name= field_iterator.get_table_name(); if (!tables->schema_table && !(fld->have_privileges= (get_column_grant(thd, field_iterator.grant(), - field_iterator.get_db_name(), + field_db_name, field_table_name, fld->field_name.str) & VIEW_ANY_ACL))) { my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - field_table_name); + field_db_name, field_table_name); DBUG_RETURN(TRUE); } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 961e1d0ae8e..a61a7d97746 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3955,6 +3955,7 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, lex(lex_arg), db(null_clex_str) { + hr_prepare_time.val= 0, name= null_clex_str; } @@ -3971,6 +3972,7 @@ void Statement::set_statement(Statement *stmt) column_usage= stmt->column_usage; lex= stmt->lex; query_string= stmt->query_string; + hr_prepare_time= stmt->hr_prepare_time; } diff --git a/sql/sql_class.h b/sql/sql_class.h index c0aa56f5355..9ad576f07c6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -120,8 +120,8 @@ enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY, SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY}; /* - MARK_COLUMNS_READ: A column is goind to be read. - MARK_COLUMNS_WRITE: A column is going to be written to. + COLUMNS_READ: A column is goind to be read. + COLUMNS_WRITE: A column is going to be written to. MARK_COLUMNS_READ: A column is goind to be read. A bit in read set is set to inform handler that the field is to be read. If field list contains duplicates, then @@ -1334,6 +1334,7 @@ public: LEX_CSTRING name; /* name for named prepared statements */ LEX *lex; // parse tree descriptor + my_hrtime_t hr_prepare_time; // time of preparation in microseconds /* Points to the query associated with this statement. It's const, but we need to declare it char * because all table handlers are written diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 445bc97a3b5..a526bfee2d2 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -410,9 +410,17 @@ bool With_element::check_dependencies_in_spec() { for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select()) { - st_unit_ctxt_elem ctxt0= {NULL, owner->owner}; - st_unit_ctxt_elem ctxt1= {&ctxt0, spec}; - check_dependencies_in_select(sl, &ctxt1, false, &sl->with_dep); + if (owner->with_recursive) + { + st_unit_ctxt_elem ctxt0= {NULL, owner->owner}; + st_unit_ctxt_elem ctxt1= {&ctxt0, spec}; + check_dependencies_in_select(sl, &ctxt1, false, &sl->with_dep); + } + else + { + st_unit_ctxt_elem ctxt= {NULL, spec}; + check_dependencies_in_select(sl, &ctxt, false, &sl->with_dep); + } base_dep_map|= sl->with_dep; } return false; @@ -480,29 +488,50 @@ With_element *With_clause::find_table_def(TABLE_LIST *table, With_element *find_table_def_in_with_clauses(TABLE_LIST *tbl, st_unit_ctxt_elem *ctxt) { - With_element *barrier= NULL; + With_element *found= 0; for (st_unit_ctxt_elem *unit_ctxt_elem= ctxt; unit_ctxt_elem; unit_ctxt_elem= unit_ctxt_elem->prev) { st_select_lex_unit *unit= unit_ctxt_elem->unit; With_clause *with_clause= unit->with_clause; - if (with_clause && - (tbl->with= with_clause->find_table_def(tbl, barrier))) - return tbl->with; - barrier= NULL; - if (unit->with_element && !unit->with_element->get_owner()->with_recursive) + /* + First look for the table definition in the with clause attached to 'unit' + if there is any such clause. + */ + if (with_clause) { - /* - This unit is the specification if the with element unit->with_element. - The with element belongs to a with clause without the specifier RECURSIVE. - So when searching for the matching definition of tbl this with clause must - be looked up to this with element - */ - barrier= unit->with_element; + found= with_clause->find_table_def(tbl, NULL); + if (found) + break; + } + /* + If 'unit' is the unit that defines a with element then reset 'unit' + to the unit whose attached with clause contains this with element. + */ + With_element *with_elem= unit->with_element; + if (with_elem) + { + if (!(unit_ctxt_elem= unit_ctxt_elem->prev)) + break; + unit= unit_ctxt_elem->unit; + } + with_clause= unit->with_clause; + /* + Now look for the table definition in this with clause. If the with clause + contains RECURSIVE the search is performed through all CTE definitions in + clause, otherwise up to the definition of 'with_elem' unless it is NULL. + */ + if (with_clause) + { + found= with_clause->find_table_def(tbl, + with_clause->with_recursive ? + NULL : with_elem); + if (found) + break; } } - return NULL; + return found; } @@ -532,22 +561,30 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, bool in_subq, table_map *dep_map) { - With_clause *with_clause= sl->get_with_clause(); + bool is_spec_select= sl->get_with_element() == this; + for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local) { - if (tbl->derived || tbl->nested_join) + if (tbl->with || tbl->derived || tbl->nested_join) continue; tbl->with_internal_reference_map= 0; /* - If there is a with clause attached to the unit containing sl - look first for the definition of tbl in this with clause. - If such definition is not found there look in the with - clauses of the upper levels. + Look first for the definition of tbl in the with clause to which + this with element belongs. If such definition is not found there + look in the with clauses of the upper levels via the context + chain of embedding with elements. If the definition of tbl is found somewhere in with clauses - then tbl->with is set to point to this definition + then tbl->with is set to point to this definition. */ - if (with_clause && !tbl->with) - tbl->with= with_clause->find_table_def(tbl, NULL); + if (is_spec_select) + { + With_clause *with_clause= sl->master_unit()->with_clause; + if (with_clause) + tbl->with= with_clause->find_table_def(tbl, NULL); + if (!tbl->with) + tbl->with= owner->find_table_def(tbl, + owner->with_recursive ? NULL : this); + } if (!tbl->with) tbl->with= find_table_def_in_with_clauses(tbl, ctxt); @@ -574,8 +611,7 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, st_select_lex_unit *inner_unit= sl->first_inner_unit(); for (; inner_unit; inner_unit= inner_unit->next_unit()) { - if (!inner_unit->with_element) - check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); + check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map); } } @@ -653,10 +689,14 @@ void With_element::check_dependencies_in_unit(st_select_lex_unit *unit, bool in_subq, table_map *dep_map) { + st_unit_ctxt_elem unit_ctxt_elem= {ctxt, unit}; if (unit->with_clause) - check_dependencies_in_with_clause(unit->with_clause, ctxt, in_subq, dep_map); + { + (void) unit->with_clause->check_dependencies(); + check_dependencies_in_with_clause(unit->with_clause, &unit_ctxt_elem, + in_subq, dep_map); + } in_subq |= unit->item != NULL; - st_unit_ctxt_elem unit_ctxt_elem= {ctxt, unit}; st_select_lex *sl= unit->first_select(); for (; sl; sl= sl->next_select()) { diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 4cec1240d1f..e0fbd79803b 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -393,10 +393,24 @@ public: bool add_with_element(With_element *elem); /* Add this with clause to the list of with clauses used in the statement */ - void add_to_list(With_clause ** &last_next) + void add_to_list(With_clause **ptr, With_clause ** &last_next) { - *last_next= this; - last_next= &this->next_with_clause; + if (embedding_with_clause) + { + /* + An embedded with clause is always placed before the embedding one + in the list of with clauses used in the query. + */ + while (*ptr != embedding_with_clause) + ptr= &(*ptr)->next_with_clause; + *ptr= this; + next_with_clause= embedding_with_clause; + } + else + { + *last_next= this; + last_next= &this->next_with_clause; + } } st_select_lex_unit *get_owner() { return owner; } diff --git a/sql/sql_debug.h b/sql/sql_debug.h new file mode 100644 index 00000000000..cb4bfcec3ed --- /dev/null +++ b/sql/sql_debug.h @@ -0,0 +1,168 @@ +#ifndef SQL_DEBUG_INCLUDED +#define SQL_DEBUG_INCLUDED +/* + Copyright (c) 2022, MariaDB + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +*/ + + +class Debug_key: public String +{ +public: + Debug_key() { }; + void print(THD *thd) const + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "DBUG: %.*s", length(), ptr()); + } + + bool append_key_type(ha_base_keytype type) + { + static LEX_CSTRING names[20]= + { + STRING_WITH_LEN("END"), + STRING_WITH_LEN("TEXT"), + STRING_WITH_LEN("BINARY"), + STRING_WITH_LEN("SHORT_INT"), + STRING_WITH_LEN("LONG_INT"), + STRING_WITH_LEN("FLOAT"), + STRING_WITH_LEN("DOUBLE"), + STRING_WITH_LEN("NUM"), + STRING_WITH_LEN("USHORT_INT"), + STRING_WITH_LEN("ULONG_INT"), + STRING_WITH_LEN("LONGLONG"), + STRING_WITH_LEN("ULONGLONG"), + STRING_WITH_LEN("INT24"), + STRING_WITH_LEN("UINT24"), + STRING_WITH_LEN("INT8"), + STRING_WITH_LEN("VARTEXT1"), + STRING_WITH_LEN("VARBINARY1"), + STRING_WITH_LEN("VARTEXT2"), + STRING_WITH_LEN("VARBINARY2"), + STRING_WITH_LEN("BIT") + }; + if ((uint) type >= array_elements(names)) + return append(STRING_WITH_LEN("???")); + return append(names[(uint) type]); + } + + bool append_KEY_flag_names(ulong flags) + { + static LEX_CSTRING names[17]= + { + STRING_WITH_LEN("HA_NOSAME"), + STRING_WITH_LEN("HA_PACK_KEY"), + STRING_WITH_LEN("HA_SPACE_PACK_USED"), + STRING_WITH_LEN("HA_VAR_LENGTH_KEY"), + STRING_WITH_LEN("HA_AUTO_KEY"), + STRING_WITH_LEN("HA_BINARY_PACK_KEY"), + STRING_WITH_LEN("HA_NULL_PART_KEY"), + STRING_WITH_LEN("HA_FULLTEXT"), + STRING_WITH_LEN("HA_UNIQUE_CHECK"), + STRING_WITH_LEN("HA_SORT_ALLOWS_SAME"), + STRING_WITH_LEN("HA_SPATIAL"), + STRING_WITH_LEN("HA_NULL_ARE_EQUAL"), + STRING_WITH_LEN("HA_GENERATED_KEY"), + STRING_WITH_LEN("HA_USES_COMMENT"), + STRING_WITH_LEN("HA_USES_PARSER"), + STRING_WITH_LEN("HA_USES_BLOCK_SIZE"), + STRING_WITH_LEN("HA_KEY_HAS_PART_KEY_SEG") + }; + return append_flag32_names((uint) flags, names, array_elements(names)); + } + + bool append_HA_KEYSEG_flag_names(uint32 flags) + { + static LEX_CSTRING names[]= + { + STRING_WITH_LEN("HA_SPACE_PACK"), // 1 + STRING_WITH_LEN("??? 2 ???"), // 2 + STRING_WITH_LEN("HA_PART_KEY_SEG"), // 4 + STRING_WITH_LEN("HA_VAR_LENGTH_PART"), // 8 + STRING_WITH_LEN("HA_NULL_PART"), // 16 + STRING_WITH_LEN("HA_BLOB_PART"), // 32 + STRING_WITH_LEN("HA_SWAP_KEY"), // 64 + STRING_WITH_LEN("HA_REVERSE_SORT"), // 128 + STRING_WITH_LEN("HA_NO_SORT"), // 256 + STRING_WITH_LEN("??? 512 ???"), // 512 + STRING_WITH_LEN("HA_BIT_PART"), // 1024 + STRING_WITH_LEN("HA_CAN_MEMCMP") // 2048 + }; + return append_flag32_names(flags, names, array_elements(names)); + } + + bool append_HA_KEYSEG_type(ha_base_keytype type) + { + return append_ulonglong(type) || + append(' ') || + append_key_type(type); + } + + bool append_HA_KEYSEG_flags(uint32 flags) + { + return append_hex_uint32(flags) || + append(' ') || + append_HA_KEYSEG_flag_names(flags); + } + + bool append_key(const LEX_CSTRING &name, uint32 flags) + { + return + append_name_value(Lex_cstring(STRING_WITH_LEN("name")), name, '`') || + append(Lex_cstring(STRING_WITH_LEN(" flags="))) || + append_hex_uint32(flags) || + append(' ') || + append_KEY_flag_names(flags); + } + + bool append_KEY(const KEY &key) + { + return append_key(key.name, key.flags); + } + + static void print_keysegs(THD *thd, const HA_KEYSEG *seg, uint count) + { + for (uint i= 0; i < count; i++) + { + Debug_key tmp; + if (!tmp.append(Lex_cstring(STRING_WITH_LEN(" seg["))) && + !tmp.append_ulonglong(i) && + !tmp.append(Lex_cstring(STRING_WITH_LEN("].type="))) && + !tmp.append_HA_KEYSEG_type((ha_base_keytype) seg[i].type)) + tmp.print(thd); + tmp.length(0); + if (!tmp.append(Lex_cstring(STRING_WITH_LEN(" seg["))) && + !tmp.append_ulonglong(i) && + !tmp.append(Lex_cstring(STRING_WITH_LEN("].flag="))) && + !tmp.append_HA_KEYSEG_flags(seg[i].flag)) + tmp.print(thd); + } + } + + static void print_keys(THD *thd, const char *where, + const KEY *keys, uint key_count) + { + for (uint i= 0; i < key_count; i++) + { + Debug_key tmp; + if (!tmp.append(where, strlen(where)) && !tmp.append_KEY(keys[i])) + tmp.print(thd); + } + } +}; + + +#endif // SQL_DEBUG_INCLUDED diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e638305eaf4..7576b644810 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3074,23 +3074,9 @@ void st_select_lex_node::include_down(st_select_lex_node *upper) } -void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) +void st_select_lex_node::attach_single(st_select_lex_node *slave_arg) { - for (; slave; slave= slave->next) - if (slave == slave_arg) - return; - - if (slave) - { - st_select_lex_node *slave_arg_slave= slave_arg->slave; - /* Insert in the front of list of slaves if any. */ - slave_arg->include_neighbour(slave); - /* include_neighbour() sets slave_arg->slave=0, restore it. */ - slave_arg->slave= slave_arg_slave; - /* Count on include_neighbour() setting the master. */ - DBUG_ASSERT(slave_arg->master == this); - } - else + DBUG_ASSERT(slave == 0); { slave= slave_arg; slave_arg->master= this; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c2636b46ee9..e4fe1465c57 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -768,7 +768,7 @@ public: inline st_select_lex_node* get_master() { return master; } void include_down(st_select_lex_node *upper); - void add_slave(st_select_lex_node *slave_arg); + void attach_single(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); void link_chain_down(st_select_lex_node *first); void link_neighbour(st_select_lex_node *neighbour) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c5d54afa29e..8d15e11f90e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7308,7 +7308,6 @@ bool check_fk_parent_table_access(THD *thd, if (key->type == Key::FOREIGN_KEY) { TABLE_LIST parent_table; - bool is_qualified_table_name; Foreign_key *fk_key= (Foreign_key *)key; LEX_CSTRING db_name; LEX_CSTRING table_name= { fk_key->ref_table.str, @@ -7325,7 +7324,6 @@ bool check_fk_parent_table_access(THD *thd, if (fk_key->ref_db.str) { - is_qualified_table_name= true; if (!(db_name.str= (char *) thd->memdup(fk_key->ref_db.str, fk_key->ref_db.length+1))) return true; @@ -7347,7 +7345,6 @@ bool check_fk_parent_table_access(THD *thd, if (!(db_name.str= (char *) thd->memdup(create_db, db_name.length+1))) return true; - is_qualified_table_name= true; if (check_db_name((LEX_STRING*) &db_name)) { @@ -7359,8 +7356,6 @@ bool check_fk_parent_table_access(THD *thd, { if (thd->lex->copy_db_to(&db_name)) return true; - else - is_qualified_table_name= false; } } @@ -7386,22 +7381,11 @@ bool check_fk_parent_table_access(THD *thd, if (check_some_access(thd, privileges, &parent_table) || parent_table.grant.want_privilege) { - if (is_qualified_table_name) - { - const size_t qualified_table_name_len= NAME_LEN + 1 + NAME_LEN + 1; - char *qualified_table_name= (char *) thd->alloc(qualified_table_name_len); - - my_snprintf(qualified_table_name, qualified_table_name_len, "%s.%s", - db_name.str, table_name.str); - table_name.str= qualified_table_name; - } - my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), - "REFERENCES", - thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, - table_name.str); - + "REFERENCES", + thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, + db_name.str, table_name.str); return true; } } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5fca48f403f..ab6734dffb5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4492,6 +4492,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (thd->spcont == NULL) general_log_write(thd, COM_STMT_PREPARE, query(), query_length()); } + // The same format as for triggers to compare + hr_prepare_time= my_hrtime(); DBUG_RETURN(error); } @@ -4585,8 +4587,8 @@ Prepared_statement::execute_loop(String *expanded_query, uchar *packet_end) { Reprepare_observer reprepare_observer; - bool error; int reprepare_attempt= 0; + bool error; iterations= FALSE; /* diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index e688fbcdad3..e990b94b43c 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -4123,7 +4123,7 @@ bool mysql_show_binlog_events(THD* thd) binlog_size= s.st_size; if (lex_mi->pos > binlog_size) { - sprintf(errmsg_buf, "Invalid pos specified. Requested from pos:%llu is " + snprintf(errmsg_buf, sizeof(errmsg_buf), "Invalid pos specified. Requested from pos:%llu is " "greater than actual file size:%lu\n", lex_mi->pos, (ulong)s.st_size); errmsg= errmsg_buf; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5c578ff8755..f49bab0dcaa 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1069,7 +1069,8 @@ public: my_snprintf(m_view_access_denied_message, MYSQL_ERRMSG_SIZE, ER_THD(thd, ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW", m_sctx->priv_user, - m_sctx->host_or_ip, m_top_view->get_table_name()); + m_sctx->host_or_ip, + m_top_view->get_db_name(), m_top_view->get_table_name()); } return m_view_access_denied_message_ptr; } @@ -1161,7 +1162,8 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, DBUG_PRINT("debug", ("check_table_access failed")); my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "SHOW", thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, table_list->alias.str); + thd->security_ctx->host_or_ip, + table_list->db.str, table_list->alias.str); goto exit; } DBUG_PRINT("debug", ("check_table_access succeeded")); @@ -1190,7 +1192,8 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, { my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "SHOW", thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, table_list->alias.str); + thd->security_ctx->host_or_ip, + table_list->db.str, table_list->alias.str); goto exit; } } @@ -7152,13 +7155,14 @@ static bool store_trigger(THD *thd, Trigger *trigger, table->field[14]->store(STRING_WITH_LEN("OLD"), cs); table->field[15]->store(STRING_WITH_LEN("NEW"), cs); - if (trigger->create_time) + if (trigger->hr_create_time.val) { + /* timestamp is in microseconds */ table->field[16]->set_notnull(); - thd->variables.time_zone->gmt_sec_to_TIME(×tamp, - (my_time_t)(trigger->create_time/100)); - /* timestamp is with 6 digits */ - timestamp.second_part= (trigger->create_time % 100) * 10000; + thd->variables.time_zone-> + gmt_sec_to_TIME(×tamp, + (my_time_t) hrtime_to_time(trigger->hr_create_time)); + timestamp.second_part= hrtime_sec_part(trigger->hr_create_time); table->field[16]->store_time_dec(×tamp, 2); } @@ -9978,12 +9982,14 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger) p->store(&trigger->db_cl_name, system_charset_info); - if (trigger->create_time) + if (trigger->hr_create_time.val) { MYSQL_TIME timestamp; - thd->variables.time_zone->gmt_sec_to_TIME(×tamp, - (my_time_t)(trigger->create_time/100)); - timestamp.second_part= (trigger->create_time % 100) * 10000; + thd->variables.time_zone-> + gmt_sec_to_TIME(×tamp, + (my_time_t) + hrtime_to_time(trigger->hr_create_time)); + timestamp.second_part= hrtime_sec_part(trigger->hr_create_time); p->store_datetime(×tamp, 2); } else diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 90693f407fb..fbc97ab54fb 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -173,6 +173,17 @@ void Binary_string::qs_append_hex(const char *str, uint32 len) } +void Binary_string::qs_append_hex_uint32(uint32 num) +{ + char *to= Ptr + str_length; + APPEND_HEX(to, (uchar) (num >> 24)); + APPEND_HEX(to, (uchar) (num >> 16)); + APPEND_HEX(to, (uchar) (num >> 8)); + APPEND_HEX(to, (uchar) num); + str_length+= 8; +} + + // Convert a string to its HEX representation bool Binary_string::set_hex(const char *str, uint32 len) { diff --git a/sql/sql_string.h b/sql/sql_string.h index f9fe895b40b..b1f02bdb43b 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -399,6 +399,7 @@ public: } void qs_append(const char *str, size_t len); void qs_append_hex(const char *str, uint32 len); + void qs_append_hex_uint32(uint32 num); void qs_append(double d); void qs_append(const double *d); inline void qs_append(const char c) @@ -614,7 +615,13 @@ public: } return false; } - + bool append_hex_uint32(uint32 num) + { + if (reserve(8)) + return true; + qs_append_hex_uint32(num); + return false; + } bool append_with_step(const char *s, uint32 arg_length, uint32 step_alloc) { uint32 new_length= arg_length + str_length; @@ -987,6 +994,17 @@ public: { return append(&ls); } + bool append_name_value(const LEX_CSTRING &name, + const LEX_CSTRING &value, + uchar quot= '\0') + { + return + append(name) || + append('=') || + (quot && append(quot)) || + append(value) || + (quot && append(quot)); + } bool append(const char *s, size_t size); bool append_with_prefill(const char *s, uint32 arg_length, uint32 full_length, char fill_char); @@ -999,6 +1017,37 @@ public: return append(s.str, s.length, cs); } + /* + Append a bitmask in an uint32 with a translation into a + C-style human readable representation, e.g.: + 0x05 -> "(flag04|flag01)" + + @param flags - the flags to translate + @param names - an array of flag names + @param count - the number of available elements in "names" + */ + bool append_flag32_names(uint32 flags, LEX_CSTRING names[], size_t count) + { + bool added= false; + if (flags && append('(')) + return true; + for (ulong i= 0; i <= 31; i++) + { + ulong bit= 31 - i; + if (flags & (1 << bit)) + { + if (added && append('|')) + return true; + if (bit < count ? append(names[bit]) : append('?')) + return true; + added= true; + } + } + if (flags && append(')')) + return true; + return false; + } + void strip_sp(); friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); friend class Field; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f26b2e23b25..cbdfb04c8f6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -59,6 +59,7 @@ #include "debug.h" // debug_crash_here() #include <algorithm> #include "wsrep_mysqld.h" +#include "sql_debug.h" #ifdef _WIN32 #include <io.h> @@ -3659,6 +3660,13 @@ without_overlaps_err: thd->mem_root)) DBUG_RETURN(TRUE); +#ifndef DBUG_OFF + DBUG_EXECUTE_IF("key", + Debug_key::print_keys(thd, "prep_create_table: ", + *key_info_buffer, *key_count); + ); +#endif + DBUG_RETURN(FALSE); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 896afa6f59e..d29ef532382 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -38,6 +38,8 @@ #include "debug.h" // debug_crash_here #include "mysql/psi/mysql_sp.h" #include "wsrep_mysqld.h" +#include <my_time.h> +#include <mysql_time.h> /*************************************************************************/ @@ -222,7 +224,7 @@ static File_option triggers_file_parameters[]= }, { { STRING_WITH_LEN("created") }, - my_offsetof(class Table_triggers_list, create_times), + my_offsetof(class Table_triggers_list, hr_create_times), FILE_OPTIONS_ULLLIST }, { { 0, 0 }, 0, FILE_OPTIONS_STRING } @@ -1057,6 +1059,10 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, if (!(trigger= new (&table->mem_root) Trigger(this, 0))) goto err; + /* Time with in microseconds */ + trigger->hr_create_time= make_hr_time(thd->query_start(), + thd->query_start_sec_part()); + /* Create trigger_name.TRN file to ensure trigger name is unique */ if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type, (uchar*)&trigname, trigname_file_parameters)) @@ -1069,8 +1075,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, /* Populate the trigger object */ trigger->sql_mode= thd->variables.sql_mode; - /* Time with 2 decimals, like in MySQL 5.7 */ - trigger->create_time= ((ulonglong) thd->query_start())*100 + thd->query_start_sec_part()/10000; build_trig_stmt_query(thd, tables, stmt_query, &trigger_definition, &trigger->definer, trg_definer_holder); @@ -1138,7 +1142,7 @@ void Table_triggers_list::empty_lists() client_cs_names.empty(); connection_cl_names.empty(); db_cl_names.empty(); - create_times.empty(); + hr_create_times.empty(); } @@ -1174,7 +1178,7 @@ bool Trigger::add_to_file_list(void* param_arg) base->client_cs_names.push_back(&client_cs_name, mem_root) || base->connection_cl_names.push_back(&connection_cl_name, mem_root) || base->db_cl_names.push_back(&db_cl_name, mem_root) || - base->create_times.push_back(&create_time, mem_root)) + base->hr_create_times.push_back(&hr_create_time.val, mem_root)) return 1; return 0; } @@ -1584,7 +1588,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, List_iterator_fast<LEX_CSTRING> it_client_cs_name(trigger_list->client_cs_names); List_iterator_fast<LEX_CSTRING> it_connection_cl_name(trigger_list->connection_cl_names); List_iterator_fast<LEX_CSTRING> it_db_cl_name(trigger_list->db_cl_names); - List_iterator_fast<ulonglong> it_create_times(trigger_list->create_times); + List_iterator_fast<ulonglong> + it_create_times(trigger_list->hr_create_times); LEX *old_lex= thd->lex; LEX lex; sp_rcontext *save_spcont= thd->spcont; @@ -1670,7 +1675,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, trigger->sql_mode= sql_mode; trigger->definition= *trg_create_str; - trigger->create_time= trg_create_time ? *trg_create_time : 0; + trigger->hr_create_time.val= trg_create_time ? *trg_create_time : 0; + /* + Fix time if in 100th of second (comparison with max uint * 100 + (max possible timestamp in the old format)) + */ + if (trigger->hr_create_time.val < 429496729400ULL) + trigger->hr_create_time.val*= 10000; trigger->name= sp ? sp->m_name : empty_clex_str; trigger->on_table_name.str= (char*) lex.raw_trg_on_table_name_begin; trigger->on_table_name.length= (lex.raw_trg_on_table_name_end - diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 739669c86a5..774dca7cba1 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -140,7 +140,7 @@ public: GRANT_INFO subject_table_grants; sql_mode_t sql_mode; /* Store create time. Can't be mysql_time_t as this holds also sub seconds */ - ulonglong create_time; + my_hrtime_t hr_create_time; // Create time timestamp in microseconds trg_event_type event; trg_action_time_type action_time; uint action_order; @@ -223,7 +223,7 @@ public: */ List<ulonglong> definition_modes_list; /** Create times for triggers */ - List<ulonglong> create_times; + List<ulonglong> hr_create_times; List<LEX_CSTRING> definers_list; diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index 702b096231b..497f37f492b 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -743,7 +743,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, Attach the select used of TVC as the only slave to the unit for the derived table tvc_x of the transformation */ - derived_unit->add_slave(tvc_sl); + derived_unit->attach_single(tvc_sl); tvc_sl->set_linkage(DERIVED_TABLE_TYPE); /* diff --git a/sql/sql_union.cc b/sql/sql_union.cc index e8bdbcba2f2..758edbdcbaa 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1075,15 +1075,6 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, order= order->next) order->item= &order->item_ptr; } - for (ORDER *order= global_parameters()->order_list.first; - order; - order=order->next) - { - (*order->item)->walk(&Item::change_context_processor, 0, - &fake_select_lex->context); - (*order->item)->walk(&Item::set_fake_select_as_master_processor, 0, - fake_select_lex); - } } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 6dedd5e85be..7a52b822b9d 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -306,7 +306,8 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, { my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, - thd->security_ctx->priv_host, tbl->table_name.str); + thd->security_ctx->priv_host, + tbl->db.str, tbl->table_name.str); goto err; } /* @@ -834,7 +835,7 @@ static File_option view_parameters[]= my_offsetof(TABLE_LIST, with_check), FILE_OPTIONS_ULONGLONG}, {{ STRING_WITH_LEN("timestamp")}, - my_offsetof(TABLE_LIST, timestamp), + my_offsetof(TABLE_LIST, hr_timestamp), FILE_OPTIONS_TIMESTAMP}, {{ STRING_WITH_LEN("create-version")}, my_offsetof(TABLE_LIST, file_version), @@ -858,6 +859,15 @@ static File_option view_parameters[]= FILE_OPTIONS_STRING} }; + +static File_option view_timestamp_parameters[]= +{ + + {{ C_STRING_WITH_LEN("timestamp")}, 0, FILE_OPTIONS_TIMESTAMP}, + {{NullS, 0}, 0, FILE_OPTIONS_STRING} +}; + + static LEX_CSTRING view_file_type[]= {{STRING_WITH_LEN("VIEW") }}; @@ -875,8 +885,8 @@ int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum, &path, path_buff, sizeof(path_buff), &file, view); /* init timestamp */ - if (!view->timestamp.str) - view->timestamp.str= view->timestamp_buffer; + if (!view->hr_timestamp.str) + view->hr_timestamp.str= view->timestamp_buffer; if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED) { @@ -891,13 +901,13 @@ int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum, swap_alg= 0; if (wrong_checksum) { - if (view->md5.length != 32) + if (view->md5.length != VIEW_MD5_LEN) { - if ((view->md5.str= (char *)thd->alloc(32 + 1)) == NULL) + if ((view->md5.str= (char *)thd->alloc(VIEW_MD5_LEN + 1)) == NULL) DBUG_RETURN(HA_ADMIN_FAILED); } view->calc_md5(const_cast<char*>(view->md5.str)); - view->md5.length= 32; + view->md5.length= VIEW_MD5_LEN; } view->mariadb_version= MYSQL_VERSION_ID; @@ -1021,13 +1031,13 @@ static int mysql_register_view(THD *thd, DDL_LOG_STATE *ddl_log_state, view->file_version= 2; view->mariadb_version= MYSQL_VERSION_ID; view->calc_md5(md5); - if (!(view->md5.str= (char*) thd->memdup(md5, 32))) + if (!(view->md5.str= (char*) thd->memdup(md5, VIEW_MD5_LEN))) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); error= -1; goto err; } - view->md5.length= 32; + view->md5.length= VIEW_MD5_LEN; can_be_merged= lex->can_be_merged(); if (lex->create_view->algorithm == VIEW_ALGORITHM_MERGE && !lex->can_be_merged()) @@ -1078,8 +1088,8 @@ loop_out: &path, path_buff, sizeof(path_buff), &file, view); /* init timestamp */ - if (!view->timestamp.str) - view->timestamp.str= view->timestamp_buffer; + if (!view->hr_timestamp.str) + view->hr_timestamp.str= view->timestamp_buffer; /* check old .frm */ { @@ -1224,7 +1234,32 @@ err: DBUG_RETURN(error); } +/** + Reads view definition "version" + @param[in] share Share object of view + + @return true on error, otherwise false +*/ + +bool mariadb_view_version_get(TABLE_SHARE *share) +{ + DBUG_ASSERT(share->is_view); + + if (!(share->tabledef_version.str= + (uchar*) alloc_root(&share->mem_root, + MICROSECOND_TIMESTAMP_BUFFER_SIZE))) + return TRUE; + share->tabledef_version.length= 0; // safety if the drfinition file is brocken + + DBUG_ASSERT(share->view_def != NULL); + if (share->view_def->parse((uchar *) &share->tabledef_version, NULL, + view_timestamp_parameters, 1, + &file_parser_dummy_hook)) + return TRUE; + DBUG_ASSERT(share->tabledef_version.length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1); + return FALSE; +} /** read VIEW .frm and create structures @@ -1287,6 +1322,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, mysql_handle_single_derived(thd->lex, table, DT_REINIT); DEBUG_SYNC(thd, "after_cached_view_opened"); + if (!share->tabledef_version.length) + { + mariadb_view_version_get(share); + } DBUG_RETURN(0); } @@ -1323,8 +1362,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, arena= thd->activate_stmt_arena_if_needed(&backup); /* init timestamp */ - if (!table->timestamp.str) - table->timestamp.str= table->timestamp_buffer; + if (!table->hr_timestamp.str) + table->hr_timestamp.str= table->timestamp_buffer; /* prepare default values for old format */ table->view_suid= TRUE; table->definer.user.str= table->definer.host.str= 0; @@ -1340,6 +1379,19 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, required_view_parameters, &file_parser_dummy_hook))) goto end; + if (!share->tabledef_version.length) + { + share->tabledef_version.str= (const uchar *) + memdup_root(&share->mem_root, + (const void *) + table->hr_timestamp.str, + (share->tabledef_version.length= + table->hr_timestamp.length)); + } + if (!table->tabledef_version.length) + { + table->set_view_def_version(&table->hr_timestamp); + } /* check old format view .frm @@ -2196,10 +2248,10 @@ bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view) int view_checksum(THD *thd, TABLE_LIST *view) { char md5[MD5_BUFF_LENGTH]; - if (!view->view || view->md5.length != 32) + if (!view->view || view->md5.length != VIEW_MD5_LEN) return HA_ADMIN_NOT_IMPLEMENTED; view->calc_md5(md5); - return (strncmp(md5, view->md5.str, 32) ? + return (strncmp(md5, view->md5.str, VIEW_MD5_LEN) ? HA_ADMIN_WRONG_CHECKSUM : HA_ADMIN_OK); } @@ -2304,7 +2356,7 @@ mysql_rename_view(THD *thd, object for it. */ view_def.reset(); - view_def.timestamp.str= view_def.timestamp_buffer; + view_def.hr_timestamp.str= view_def.timestamp_buffer; view_def.view_suid= TRUE; /* get view definition and source */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7eb574f645e..2a2d8a6a4e7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13704,7 +13704,7 @@ opt_returning: { SELECT_LEX *sl= Lex->returning(); sl->set_master_unit(0); - Select->add_slave(Lex->create_unit(sl)); + Select->attach_single(Lex->create_unit(sl)); sl->include_global((st_select_lex_node**)&Lex->all_selects_list); Lex->push_select(sl); } @@ -15231,7 +15231,8 @@ with_clause: lex->derived_tables|= DERIVED_WITH; lex->with_cte_resolution= true; lex->curr_with_clause= with_clause; - with_clause->add_to_list(Lex->with_clauses_list_last_next); + with_clause->add_to_list(&lex->with_clauses_list, + lex->with_clauses_list_last_next); if (lex->current_select && lex->current_select->parsing_place == BEFORE_OPT_LIST) lex->current_select->parsing_place= NO_MATTER; diff --git a/sql/table.cc b/sql/table.cc index 5f6d88183ef..4ea64985910 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9697,6 +9697,73 @@ bool TABLE_LIST::is_with_table() return derived && derived->with_element; } + +/** + Check if the definition are the same. + + If versions do not match it check definitions (with checking and setting + trigger definition versions (times) + + @param[in] view TABLE_LIST of the view + @param[in] share Share object of view + + @return false on error or different definitions. + + @sa check_and_update_table_version() +*/ + +bool TABLE_LIST::is_the_same_definition(THD* thd, TABLE_SHARE *s) +{ + enum enum_table_ref_type tp= s->get_table_ref_type(); + if (m_table_ref_type == tp) + { + /* + Cache have not changed which means that definition was not changed + including triggers + */ + if (m_table_ref_version == s->get_table_ref_version()) + return TRUE; + + /* + If cache changed then check content version + */ + if ((tabledef_version.length && + tabledef_version.length == s->tabledef_version.length && + memcmp(tabledef_version.str, s->tabledef_version.str, + tabledef_version.length) == 0)) + { + // Definition have not changed, let's check if triggers changed. + if (table && table->triggers) + { + + my_hrtime_t hr_stmt_prepare= thd->hr_prepare_time; + if (hr_stmt_prepare.val) + for(uint i= 0; i < TRG_EVENT_MAX; i++) + for (uint j= 0; j < TRG_ACTION_MAX; j++) + { + Trigger *tr= + table->triggers->get_trigger((trg_event_type)i, + (trg_action_time_type)j); + if (tr) + if (hr_stmt_prepare.val <= tr->hr_create_time.val) + { + set_tabledef_version(s); + return FALSE; + } + } + } + set_table_id(s); + return TRUE; + } + else + tabledef_version.length= 0; + } + else + set_tabledef_version(s); + return FALSE; +} + + uint TABLE_SHARE::actual_n_key_parts(THD *thd) { return use_ext_keys && diff --git a/sql/table.h b/sql/table.h index 5bf21a4ad3c..6579e196368 100644 --- a/sql/table.h +++ b/sql/table.h @@ -36,6 +36,19 @@ #include "sql_type.h" /* vers_kind_t */ #include "privilege.h" /* privilege_t */ +/* + Buffer for unix timestamp in microseconds: + 9,223,372,036,854,775,807 (signed int64 maximal value) + 1 234 567 890 123 456 789 + + Note: we can use unsigned for calculation, but practically they + are the same by probability to overflow them (signed int64 in + microseconds is enough for almost 3e5 years) and signed allow to + avoid increasing the buffer (the old buffer for human readable + date was 19+1). +*/ +#define MICROSECOND_TIMESTAMP_BUFFER_SIZE (19 + 1) + /* Structs that defines the TABLE */ class Item; /* Needed by ORDER */ @@ -72,6 +85,8 @@ class Table_function_json_table; */ typedef ulonglong nested_join_map; +#define VIEW_MD5_LEN 32 + #define tmp_file_prefix "#sql" /**< Prefix for tmp tables */ #define tmp_file_prefix_length 4 @@ -1091,7 +1106,7 @@ struct TABLE_SHARE with a base table, a base table is replaced with a temporary table and so on. - @sa TABLE_LIST::is_table_ref_id_equal() + @sa TABLE_LIST::is_the_same_definition() */ ulong get_table_ref_version() const { @@ -2437,6 +2452,12 @@ struct TABLE_LIST to view with SQL SECURITY DEFINER) */ Security_context *security_ctx; + uchar tabledef_version_buf[MY_UUID_SIZE > + MICROSECOND_TIMESTAMP_BUFFER_SIZE-1 ? + MY_UUID_SIZE + 1 : + MICROSECOND_TIMESTAMP_BUFFER_SIZE]; + LEX_CUSTRING tabledef_version; + /* This view security context (non-zero only for views with SQL SECURITY DEFINER) @@ -2450,7 +2471,7 @@ struct TABLE_LIST LEX_CSTRING source; /* source of CREATE VIEW */ LEX_CSTRING view_db; /* saved view database */ LEX_CSTRING view_name; /* saved view name */ - LEX_STRING timestamp; /* GMT time stamp of last operation */ + LEX_STRING hr_timestamp; /* time stamp of last operation */ LEX_USER definer; /* definer of view */ ulonglong file_version; /* version of file's field set */ ulonglong mariadb_version; /* version of server on creation */ @@ -2534,7 +2555,7 @@ struct TABLE_LIST /* TABLE_TYPE_UNKNOWN if any type is acceptable */ Table_type required_type; handlerton *db_type; /* table_type for handler */ - char timestamp_buffer[MAX_DATETIME_WIDTH + 1]; + char timestamp_buffer[MICROSECOND_TIMESTAMP_BUFFER_SIZE]; /* This TABLE_LIST object is just placeholder for prelocking, it will be used for implicit LOCK TABLES only and won't be used in real statement. @@ -2732,19 +2753,7 @@ struct TABLE_LIST */ bool process_index_hints(TABLE *table); - /** - Compare the version of metadata from the previous execution - (if any) with values obtained from the current table - definition cache element. - - @sa check_and_update_table_version() - */ - inline bool is_table_ref_id_equal(TABLE_SHARE *s) const - { - return (m_table_ref_type == s->get_table_ref_type() && - m_table_ref_version == s->get_table_ref_version()); - } - + bool is_the_same_definition(THD *thd, TABLE_SHARE *s); /** Record the value of metadata version of the corresponding table definition cache element in this parse tree node. @@ -2761,6 +2770,26 @@ struct TABLE_LIST m_table_ref_version= table_ref_version_arg; } + void set_table_id(TABLE_SHARE *s) + { + set_table_ref_id(s); + set_tabledef_version(s); + } + + void set_tabledef_version(TABLE_SHARE *s) + { + if (!tabledef_version.length && s->tabledef_version.length) + { + DBUG_ASSERT(s->tabledef_version.length < + sizeof(tabledef_version_buf)); + tabledef_version.str= tabledef_version_buf; + memcpy(tabledef_version_buf, s->tabledef_version.str, + (tabledef_version.length= s->tabledef_version.length)); + // safety + tabledef_version_buf[tabledef_version.length]= 0; + } + } + /* Set of functions returning/setting state of a derived table/view. */ bool is_non_derived() const { return (!derived_type); } bool is_view_or_derived() const { return derived_type; } @@ -2874,6 +2903,12 @@ struct TABLE_LIST } } + inline void set_view_def_version(LEX_STRING *version) + { + m_table_ref_type= TABLE_REF_VIEW; + tabledef_version.str= (const uchar *) version->str; + tabledef_version.length= version->length; + } private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); |