summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2022-10-01 23:07:26 +0200
committerSergei Golubchik <serg@mariadb.org>2022-10-01 23:07:26 +0200
commitd4f6d2f08f228778fd7744554d8b12be05b6a114 (patch)
tree2ccc39d16d3a5be27c54e03a81d2d3f75cfb9266 /sql
parent3744b8ae3171fd423f89c64a83d3afc7e3722856 (diff)
parentdd8833bff0af1b75e007e3db1d18debfb7c4a096 (diff)
downloadmariadb-git-d4f6d2f08f228778fd7744554d8b12be05b6a114.tar.gz
Merge branch '10.3' into 10.4
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_partition.cc15
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_subselect.cc44
-rw-r--r--sql/item_subselect.h1
-rw-r--r--sql/parse_file.cc21
-rw-r--r--sql/share/errmsg-utf8.txt38
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_acl.cc13
-rw-r--r--sql/sql_analyse.cc60
-rw-r--r--sql/sql_base.cc23
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_cte.cc100
-rw-r--r--sql/sql_cte.h20
-rw-r--r--sql/sql_lex.cc18
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc24
-rw-r--r--sql/sql_prepare.cc4
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_show.cc30
-rw-r--r--sql/sql_trigger.cc25
-rw-r--r--sql/sql_trigger.h4
-rw-r--r--sql/sql_tvc.cc3
-rw-r--r--sql/sql_union.cc9
-rw-r--r--sql/sql_view.cc84
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--sql/sql_yacc_ora.yy3
-rw-r--r--sql/table.cc67
-rw-r--r--sql/table.h67
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(&timestamp,
- (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(&timestamp,
+ (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(&timestamp, 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(&timestamp,
- (my_time_t)(trigger->create_time/100));
- timestamp.second_part= (trigger->create_time % 100) * 10000;
+ thd->variables.time_zone->
+ gmt_sec_to_TIME(&timestamp,
+ (my_time_t)
+ hrtime_to_time(trigger->hr_create_time));
+ timestamp.second_part= hrtime_sec_part(trigger->hr_create_time);
p->store(&timestamp, 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);