summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-10-30 19:04:54 +0100
committerSergei Golubchik <serg@mariadb.org>2018-11-12 09:27:41 +0100
commit68889c8dfa4a1f580a611c174d0ef807cb87bbad (patch)
tree39d12de3916d77fbb8878c04e15a4e5c3f18ea21 /sql
parent89ac4b3bf82aee9cd6bde87e0fe2c5f7ad87154b (diff)
downloadmariadb-git-bb-10.4-ps.tar.gz
Make mysqltest to use --ps-protocol morebb-10.4-ps
use prepared statements for everything that server supports with the exception of CALL (for now). Fix discovered test failures and bugs. tests: * PROCESSLIST shows Execute state, not Query * SHOW STATUS increments status variables more than in text protocol * multi-statements should be avoided (see tests with a wrong delimiter) * performance_schema events have different names in --ps-protocol mysqltest.cc: * make sure run_query_stmt() doesn't crash if there's no active connection (in wait_until_connected_again.inc) sql_acl.cc: * extract the functionality of getting the user for SHOW GRANTS from check_show_access(), so that mysql_test_show_grants() could generate the correct column names in the prepare step sql_class.cc: * result->prepare() can fail, don't ignore its return value * use the correct metadata when creating a column for ANALYZE SELECT. The actual value is always FLOAT(4,2), but the column was created as FLOAT(4,10), so --ps and text protocols were using different number of decimals. sql_parse.cc: * discard profiling for SHOW PROFILE. In text protocol it's done in prepare_schema_table(), but in --ps it is called on prepare only, so nothing was discarding profiling during execute. * move the permission checking code for SHOW CREATE VIEW to mysqld_show_create_get_fields(), so that it would be called during prepare step too. * only set sel_result when it was created here and needs to be destroyed in the same block. Avoid destroying lex->result. * use the correct number of tables in check_show_access(). Saying "as many as possible" doesn't work when first_not_own_table isn't set yet. sql_prepare.cc: * use correct user name for SHOW GRANTS columns * don't ignore verbose flag for SHOW SLAVE STATUS * support preparing REVOKE ALL and ROLLBACK TO SAVEPOINT * don't ignore errors from thd->prepare_explain_fields() sql_show.cc: * check grants for SHOW CREATE VIEW here, not in mysql_execute_command sql_tvc.cc: * allocate Type_holder and items in the correct arena sql_view.cc: * use the correct function to check privileges. Old code was doing check_access() for thd->security_ctx, which is invoker's sctx, not definer's sctx. Hide various view related errors from the invoker.
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_acl.cc81
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_class.cc14
-rw-r--r--sql/sql_class.h4
-rw-r--r--sql/sql_parse.cc62
-rw-r--r--sql/sql_prepare.cc23
-rw-r--r--sql/sql_show.cc52
-rw-r--r--sql/sql_tvc.cc10
-rw-r--r--sql/sql_view.cc9
9 files changed, 142 insertions, 115 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 19d742691e1..0e0349edb28 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8262,59 +8262,70 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role)
}
-/** checks privileges for SHOW GRANTS and SHOW CREATE USER
+/** get the user/host/role name for SHOW GRANTS and SHOW CREATE USER
@note that in case of SHOW CREATE USER the parser guarantees
that a role can never happen here, so *rolename will never
be assigned to
*/
-static bool check_show_access(THD *thd, LEX_USER *lex_user,
- const char **username,
- const char **hostname, const char **rolename)
+bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username,
+ const char **hostname, const char **rolename)
{
- DBUG_ENTER("check_show_access");
+ DBUG_ENTER("get_show_user");
+ Security_context *sctx= thd->security_ctx;
if (lex_user->user.str == current_user.str)
{
- *username= thd->security_ctx->priv_user;
- *hostname= thd->security_ctx->priv_host;
+ *username= sctx->priv_user;
+ *hostname= sctx->priv_host;
+ DBUG_RETURN(false);
}
- else if (lex_user->user.str == current_role.str)
+ if (lex_user->user.str == current_role.str)
{
- *rolename= thd->security_ctx->priv_role;
+ *rolename= sctx->priv_role;
+ DBUG_RETURN(false);
}
- else if (lex_user->user.str == current_user_and_current_role.str)
+ if (lex_user->user.str == current_user_and_current_role.str)
{
- *username= thd->security_ctx->priv_user;
- *hostname= thd->security_ctx->priv_host;
- *rolename= thd->security_ctx->priv_role;
+ *username= sctx->priv_user;
+ *hostname= sctx->priv_host;
+ *rolename= sctx->priv_role;
+ DBUG_RETURN(false);
}
- else
+
+ if (!(lex_user= get_current_user(thd, lex_user)))
{
- Security_context *sctx= thd->security_ctx;
- bool do_check_access;
+ *username= *rolename= NULL;
+ DBUG_RETURN(false);
+ }
- lex_user= get_current_user(thd, lex_user);
- if (!lex_user)
- DBUG_RETURN(TRUE);
+ if (lex_user->is_role())
+ {
+ *rolename= lex_user->user.str;
+ DBUG_RETURN(strcmp(*rolename, sctx->priv_role));
+ }
- if (lex_user->is_role())
- {
- *rolename= lex_user->user.str;
- do_check_access= strcmp(*rolename, sctx->priv_role);
- }
- else
- {
- *username= lex_user->user.str;
- *hostname= lex_user->host.str;
- do_check_access= strcmp(*username, sctx->priv_user) ||
- strcmp(*hostname, sctx->priv_host);
- }
+ *username= lex_user->user.str;
+ *hostname= lex_user->host.str;
+ DBUG_RETURN(strcmp(*username, sctx->priv_user) ||
+ strcmp(*hostname, sctx->priv_host));
+}
- if (do_check_access && check_access(thd, SELECT_ACL, "mysql", 0, 0, 1, 0))
- DBUG_RETURN(TRUE);
- }
- DBUG_RETURN(FALSE);
+/** checks privileges for SHOW GRANTS and SHOW CREATE USER
+*/
+static bool check_show_access(THD *thd, LEX_USER *lex_user,
+ const char **username, const char **hostname,
+ const char **rolename)
+{
+ DBUG_ENTER("check_show_access");
+ bool do_check_access=
+ get_show_user(thd, lex_user, username, hostname, rolename);
+
+ if (!*username && !*rolename)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(do_check_access &&
+ check_access(thd, SELECT_ACL, "mysql", 0, 0, 1, 0));
}
bool mysql_show_create_user(THD *thd, LEX_USER *lex_user)
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 6da7d4d5db4..5c4a4d09e6d 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -258,6 +258,8 @@ void mysql_show_grants_get_fields(THD *thd, List<Item> *fields,
const char *name, size_t length);
bool mysql_show_grants(THD *thd, LEX_USER *user);
bool mysql_show_create_user(THD *thd, LEX_USER *user);
+bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username,
+ const char **hostname, const char **rolename);
int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond);
void get_privilege_desc(char *to, uint max_length, ulong access);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a4ecdfb1297..1bc0bac99c8 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2584,17 +2584,15 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, size_t key_length)
}
-void THD::prepare_explain_fields(select_result *result,
- List<Item> *field_list,
- uint8 explain_flags,
- bool is_analyze)
+int THD::prepare_explain_fields(select_result *result, List<Item> *field_list,
+ uint8 explain_flags, bool is_analyze)
{
if (lex->explain_json)
make_explain_json_field_list(*field_list, is_analyze);
else
make_explain_field_list(*field_list, explain_flags, is_analyze);
- result->prepare(*field_list, NULL);
+ return result->prepare(*field_list, NULL);
}
@@ -2604,8 +2602,8 @@ int THD::send_explain_fields(select_result *result,
{
List<Item> field_list;
int rc;
- prepare_explain_fields(result, &field_list, explain_flags, is_analyze);
- rc= result->send_result_set_metadata(field_list,
+ rc= prepare_explain_fields(result, &field_list, explain_flags, is_analyze)
+ || result->send_result_set_metadata(field_list,
Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF);
return(rc);
@@ -2683,7 +2681,7 @@ void THD::make_explain_field_list(List<Item> &field_list, uint8 explain_flags,
if (is_analyze)
{
field_list.push_back(item= new (mem_root)
- Item_float(this, "r_rows", 0.1234, 10, 4),
+ Item_float(this, "r_rows", 0.1234, 2, 4),
mem_root);
item->maybe_null=1;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 70781296d1b..c8818424853 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3792,8 +3792,8 @@ public:
void add_changed_table(TABLE *table);
void add_changed_table(const char *key, size_t key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, size_t key_length);
- void prepare_explain_fields(select_result *result, List<Item> *field_list,
- uint8 explain_flags, bool is_analyze);
+ int prepare_explain_fields(select_result *result, List<Item> *field_list,
+ uint8 explain_flags, bool is_analyze);
int send_explain_fields(select_result *result, uint8 explain_flags,
bool is_analyze);
void make_explain_field_list(List<Item> &field_list, uint8 explain_flags,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 8d93233783f..ef45ef7943c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3745,12 +3745,14 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SELECT:
{
-#ifdef WITH_WSREP
if (lex->sql_command == SQLCOM_SELECT)
- WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ)
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ);
else
- WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW)
-#endif /* WITH_WSREP */
+ {
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+ if (lex->sql_command == SQLCOM_SHOW_PROFILE)
+ thd->profiling.discard_current_query();
+ }
thd->status_var.last_query_cost= 0.0;
@@ -4491,48 +4493,7 @@ end_with_restore_list:
DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s",
lex->table_type == TABLE_TYPE_VIEW,
first_table->db.str, first_table->table_name.str));
- if (lex->table_type == TABLE_TYPE_VIEW)
- {
- if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE))
- {
- 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, first_table->alias.str);
- goto error;
- }
- DBUG_PRINT("debug", ("check_table_access succeeded"));
- /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
- first_table->open_type= OT_BASE_ONLY;
- }
- else
- {
- /*
- Temporary tables should be opened for SHOW CREATE TABLE, but not
- for SHOW CREATE VIEW.
- */
- if (thd->open_temporary_tables(all_tables))
- goto error;
-
- /*
- The fact that check_some_access() returned FALSE does not mean that
- access is granted. We need to check if first_table->grant.privilege
- contains any table-specific privilege.
- */
- DBUG_PRINT("debug", ("first_table->grant.privilege: %lx",
- first_table->grant.privilege));
- if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, first_table) ||
- (first_table->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0)
- {
- my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
- "SHOW", thd->security_ctx->priv_user,
- thd->security_ctx->host_or_ip, first_table->alias.str);
- goto error;
- }
- }
-
- /* Access is granted. Execute the command. */
res= mysqld_show_create(thd, first_table);
break;
#endif
@@ -4885,7 +4846,7 @@ end_with_restore_list:
case SQLCOM_DELETE:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
- select_result *sel_result=lex->result;
+ select_result *sel_result= NULL;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (WSREP_CLIENT(thd) &&
wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
@@ -4916,16 +4877,15 @@ end_with_restore_list:
}
else
{
- if (!(sel_result= lex->result) &&
- !(sel_result= new (thd->mem_root) select_send(thd)))
- return 1;
+ if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd)))
+ goto error;
}
}
res = mysql_delete(thd, all_tables,
select_lex->where, &select_lex->order_list,
unit->select_limit_cnt, select_lex->options,
- sel_result);
+ lex->result ? lex->result : sel_result);
if (replaced_protocol)
{
@@ -7089,7 +7049,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
Check_grant will grant access if there is any column privileges on
all of the tables thanks to the fourth parameter (bool show_table).
*/
- if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
+ if (check_grant(thd, SELECT_ACL, dst_table, TRUE, 1, FALSE))
return TRUE; /* Access denied */
close_thread_tables(thd);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 8a627662206..4b27c502d88 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1901,8 +1901,19 @@ static int mysql_test_show_grants(Prepared_statement *stmt)
DBUG_ENTER("mysql_test_show_grants");
THD *thd= stmt->thd;
List<Item> fields;
+ char buff[1024];
+ const char *username= NULL, *hostname= NULL, *rolename= NULL, *end;
- mysql_show_grants_get_fields(thd, &fields, STRING_WITH_LEN("Grants for"));
+ get_show_user(thd, thd->lex->grant_user, &username, &hostname, &rolename);
+
+ if (username)
+ end= strxmov(buff,"Grants for ",username,"@",hostname, NullS);
+ else if (rolename)
+ end= strxmov(buff,"Grants for ",rolename, NullS);
+ else
+ DBUG_RETURN(1);
+
+ mysql_show_grants_get_fields(thd, &fields, buff, end - buff);
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
@@ -1926,7 +1937,7 @@ static int mysql_test_show_slave_status(Prepared_statement *stmt)
THD *thd= stmt->thd;
List<Item> fields;
- show_master_info_get_fields(thd, &fields, 0, 0);
+ show_master_info_get_fields(thd, &fields, thd->lex->verbose, 0);
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
@@ -2466,6 +2477,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
case SQLCOM_ROLLBACK:
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
case SQLCOM_TRUNCATE:
case SQLCOM_DROP_VIEW:
case SQLCOM_REPAIR:
@@ -2495,6 +2507,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
case SQLCOM_GRANT:
case SQLCOM_GRANT_ROLE:
case SQLCOM_REVOKE:
+ case SQLCOM_REVOKE_ALL:
case SQLCOM_REVOKE_ROLE:
case SQLCOM_KILL:
case SQLCOM_COMPOUND:
@@ -2527,9 +2540,9 @@ static bool check_prepared_statement(Prepared_statement *stmt)
!(lex->result= new (stmt->mem_root) select_send(thd)))
DBUG_RETURN(TRUE);
List<Item> field_list;
- thd->prepare_explain_fields(lex->result, &field_list,
- lex->describe, lex->analyze_stmt);
- res= send_prep_stmt(stmt, lex->result->field_count(field_list)) ||
+ res= thd->prepare_explain_fields(lex->result, &field_list,
+ lex->describe, lex->analyze_stmt) ||
+ send_prep_stmt(stmt, lex->result->field_count(field_list)) ||
lex->result->send_result_set_metadata(field_list,
Protocol::SEND_EOF);
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index b98f8aabdc1..8d3ae958b0f 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1238,13 +1238,55 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
List<Item> *field_list, String *buffer)
{
bool error= TRUE;
+ LEX *lex= thd->lex;
MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("mysqld_show_create_get_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db.str,
table_list->table_name.str));
+ if (lex->table_type == TABLE_TYPE_VIEW)
+ {
+ if (check_table_access(thd, SELECT_ACL, table_list, FALSE, 1, FALSE))
+ {
+ 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);
+ goto exit;
+ }
+ DBUG_PRINT("debug", ("check_table_access succeeded"));
+
+ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
+ table_list->open_type= OT_BASE_ONLY;
+ }
+ else
+ {
+ /*
+ Temporary tables should be opened for SHOW CREATE TABLE, but not
+ for SHOW CREATE VIEW.
+ */
+ if (thd->open_temporary_tables(table_list))
+ goto exit;
+
+ /*
+ The fact that check_some_access() returned FALSE does not mean that
+ access is granted. We need to check if table_list->grant.privilege
+ contains any table-specific privilege.
+ */
+ DBUG_PRINT("debug", ("table_list->grant.privilege: %lx",
+ table_list->grant.privilege));
+ if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, table_list) ||
+ (table_list->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0)
+ {
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
+ "SHOW", thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip, table_list->alias.str);
+ goto exit;
+ }
+ }
+
/* We want to preserve the tree for views. */
- thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
+ lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
{
/*
@@ -1259,20 +1301,20 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
bool open_error=
open_tables(thd, &table_list, &counter,
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
- mysql_handle_derived(thd->lex, DT_INIT | DT_PREPARE);
+ mysql_handle_derived(lex, DT_INIT | DT_PREPARE);
thd->pop_internal_handler();
if (unlikely(open_error && (thd->killed || thd->is_error())))
goto exit;
}
/* TODO: add environment variables show when it become possible */
- if (thd->lex->table_type == TABLE_TYPE_VIEW && !table_list->view)
+ if (lex->table_type == TABLE_TYPE_VIEW && !table_list->view)
{
my_error(ER_WRONG_OBJECT, MYF(0),
table_list->db.str, table_list->table_name.str, "VIEW");
goto exit;
}
- else if (thd->lex->table_type == TABLE_TYPE_SEQUENCE &&
+ else if (lex->table_type == TABLE_TYPE_SEQUENCE &&
table_list->table->s->table_type != TABLE_TYPE_SEQUENCE)
{
my_error(ER_NOT_SEQUENCE, MYF(0),
@@ -1287,7 +1329,7 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
if ((table_list->view ?
show_create_view(thd, table_list, buffer) :
- thd->lex->table_type == TABLE_TYPE_SEQUENCE ?
+ lex->table_type == TABLE_TYPE_SEQUENCE ?
show_create_sequence(thd, table_list, buffer) :
show_create_table(thd, table_list, buffer, NULL, WITHOUT_DB_NAME)))
goto exit;
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 0e4caae7a2f..71a749dd4a8 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -230,16 +230,16 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
if (fix_fields_for_tvc(thd, li))
DBUG_RETURN(true);
- if (!(holders= new (thd->mem_root)
- Type_holder[cnt]) ||
- join_type_handlers_for_tvc(thd, li, holders,
- cnt) ||
+ if (!(holders= new (thd->stmt_arena->mem_root) Type_holder[cnt]) ||
+ join_type_handlers_for_tvc(thd, li, holders, cnt) ||
get_type_attributes_for_tvc(thd, li, holders,
lists_of_values.elements, cnt))
DBUG_RETURN(true);
List_iterator_fast<Item> it(*first_elem);
Item *item;
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
sl->item_list.empty();
for (uint pos= 0; (item= it++); pos++)
@@ -253,6 +253,8 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
holders[pos].get_maybe_null());
sl->item_list.push_back(new_holder);
}
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
if (unlikely(thd->is_fatal_error))
DBUG_RETURN(true); // out of memory
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f2fc4b6bf75..31d53111e0a 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -329,12 +329,11 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
{
if (!tbl->table_in_first_from_clause)
{
- if (check_access(thd, SELECT_ACL, tbl->db.str,
- &tbl->grant.privilege,
- &tbl->grant.m_internal,
- 0, 0) ||
- check_grant(thd, SELECT_ACL, tbl, FALSE, 1, FALSE))
+ if (check_single_table_access(thd, SELECT_ACL, tbl, FALSE))
+ {
+ tbl->hide_view_error(thd);
goto err;
+ }
}
}
}