diff options
author | Sergei Golubchik <serg@mariadb.org> | 2022-10-01 23:07:26 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2022-10-01 23:07:26 +0200 |
commit | d4f6d2f08f228778fd7744554d8b12be05b6a114 (patch) | |
tree | 2ccc39d16d3a5be27c54e03a81d2d3f75cfb9266 /sql | |
parent | 3744b8ae3171fd423f89c64a83d3afc7e3722856 (diff) | |
parent | dd8833bff0af1b75e007e3db1d18debfb7c4a096 (diff) | |
download | mariadb-git-d4f6d2f08f228778fd7744554d8b12be05b6a114.tar.gz |
Merge branch '10.3' into 10.4
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/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_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_trigger.cc | 25 | ||||
-rw-r--r-- | sql/sql_trigger.h | 4 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 3 | ||||
-rw-r--r-- | sql/sql_union.cc | 9 | ||||
-rw-r--r-- | sql/sql_view.cc | 84 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 3 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 3 | ||||
-rw-r--r-- | sql/table.cc | 67 | ||||
-rw-r--r-- | sql/table.h | 67 |
29 files changed, 428 insertions, 262 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 0069bbf66c3..18a8cd5e027 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3639,7 +3639,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 52febaa3031..05bfc47a2b4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1924,7 +1924,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 7a9b874c53b..461bd9fb144 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -393,50 +393,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 4816785fa13..d81991a087e 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -244,7 +244,6 @@ public: bool walk(Item_processor processor, bool walk_subquery, void *arg); bool mark_as_eliminated_processor(void *arg); bool eliminate_subselect_processor(void *arg); - bool set_fake_select_as_master_processor(void *arg); bool enumerate_field_refs_processor(void *arg); bool check_vcol_func_processor(void *arg) { diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 59b4027a352..18fffb2445d 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -173,11 +173,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); @@ -833,16 +834,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/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 42958986745..dde8337f01c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -3384,25 +3384,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 negado para usuario: '%s'@'%s' para 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 negado para usuario: '%s'@'%s' para 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 ddf9df6e3d5..b7e3680f704 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1802,7 +1802,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 3eb89b58289..dc69cb63618 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -6982,7 +6982,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); } } @@ -8031,8 +8032,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). @@ -8241,7 +8242,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); @@ -8424,7 +8425,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, Security_context *sctx= thd->security_ctx; ulong UNINIT_VAR(want_access); 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); @@ -8513,7 +8514,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 edcc8aeeda6..61474433506 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 @@ -805,32 +805,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")); @@ -848,12 +848,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)); } } @@ -892,18 +892,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")); @@ -918,10 +918,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)); } @@ -940,18 +940,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")); @@ -971,15 +971,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 && @@ -1000,7 +1000,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 9942552e80b..77c86972964 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2012,6 +2012,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. @@ -2019,10 +2024,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); @@ -2897,7 +2898,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 @@ -2914,7 +2915,7 @@ static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables, TABLE_SHARE *table_share) { - if (! tables->is_table_ref_id_equal(table_share)) + if (! tables->is_the_same_definition(thd, table_share)) { if (thd->m_reprepare_observer && thd->m_reprepare_observer->report_error(thd)) @@ -3020,7 +3021,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 @@ -3035,7 +3038,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); @@ -8273,19 +8275,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 df3a7e2b704..be96fdda0f0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3977,6 +3977,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; } @@ -3993,6 +3994,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 64f9ba276b3..ab1efd6962b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -117,8 +117,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 @@ -1177,6 +1177,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 8c2630c5106..63907c2c9b5 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -409,9 +409,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; @@ -479,29 +487,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; } @@ -531,22 +560,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); @@ -573,8 +610,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); } } @@ -652,10 +688,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 c0624c5e9e1..39648d731c7 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -390,10 +390,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_lex.cc b/sql/sql_lex.cc index 3d1837fe698..8922c6b541b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2506,23 +2506,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 976d1b79cad..aae994c8721 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -740,7 +740,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 a039090da34..471d93d97f6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7273,7 +7273,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, @@ -7291,7 +7290,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; @@ -7313,7 +7311,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)) { @@ -7325,8 +7322,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; } } @@ -7352,22 +7347,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 a15c3062e16..347cb186da2 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4352,6 +4352,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); } @@ -4445,8 +4447,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 d59bfbdb839..82663c3ca2c 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -4112,7 +4112,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 85889b614c8..d290fde9d22 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1174,7 +1174,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; } @@ -1266,7 +1267,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")); @@ -1295,7 +1297,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; } } @@ -7163,13 +7166,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); } @@ -10343,12 +10347,14 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger) trigger->db_cl_name.length, 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(×tamp, 2); } else diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 77c7b60c233..1398e8f9a55 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -38,6 +38,8 @@ #ifdef WITH_WSREP #include "wsrep_mysqld.h" #endif +#include <my_time.h> +#include <mysql_time.h> /*************************************************************************/ @@ -203,7 +205,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 } @@ -911,6 +913,10 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, if (!(trigger= new (&table->mem_root) Trigger(this, 0))) goto err_without_cleanup; + /* 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)) @@ -919,8 +925,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); @@ -988,7 +992,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(); } @@ -1024,7 +1028,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; } @@ -1406,7 +1410,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; @@ -1492,7 +1497,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 ae3d1738b16..f906fa0d1a8 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -115,7 +115,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; @@ -198,7 +198,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 72d53b2307c..a25f6522bd9 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -709,7 +709,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); /* @@ -1157,4 +1157,3 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd) thd->lex->current_select= save_current_select; DBUG_RETURN(false); } - diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 70a521696d2..b878294bfef 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -633,15 +633,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 093f12f5fb5..248ac3c025e 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -304,7 +304,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; } /* @@ -787,7 +788,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), @@ -811,6 +812,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") }}; @@ -828,8 +838,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) { @@ -844,13 +854,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; @@ -973,13 +983,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, 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()) @@ -1030,8 +1040,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 */ { @@ -1156,7 +1166,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 @@ -1219,6 +1254,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); } @@ -1255,8 +1294,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; @@ -1272,6 +1311,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 @@ -2110,10 +2162,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); } @@ -2217,7 +2269,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 57540f9d3bd..8a096b4808d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15575,7 +15575,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/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index f49efa8c262..c1df628ab86 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -15707,7 +15707,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 ffbc75e6d7c..876d0b143a8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9397,6 +9397,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 3f750e7b221..b888dfe04db 100644 --- a/sql/table.h +++ b/sql/table.h @@ -33,6 +33,19 @@ #include "filesort_utils.h" #include "parse_file.h" +/* + 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 */ @@ -68,6 +81,8 @@ struct Name_resolution_context; */ 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 @@ -1062,7 +1077,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 { @@ -2454,6 +2469,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) @@ -2467,7 +2488,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 */ @@ -2550,7 +2571,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. @@ -2748,19 +2769,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. @@ -2777,6 +2786,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. */ inline bool is_non_derived() { @@ -2906,6 +2935,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); |