diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-10-30 19:04:54 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-11-12 09:27:41 +0100 |
commit | 68889c8dfa4a1f580a611c174d0ef807cb87bbad (patch) | |
tree | 39d12de3916d77fbb8878c04e15a4e5c3f18ea21 /sql | |
parent | 89ac4b3bf82aee9cd6bde87e0fe2c5f7ad87154b (diff) | |
download | mariadb-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.cc | 81 | ||||
-rw-r--r-- | sql/sql_acl.h | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 14 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 62 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 23 | ||||
-rw-r--r-- | sql/sql_show.cc | 52 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 10 | ||||
-rw-r--r-- | sql/sql_view.cc | 9 |
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; + } } } } |