diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 227 |
1 files changed, 157 insertions, 70 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 23fef77c98f..35089bbb251 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -147,7 +147,8 @@ static bool end_active_trans(THD *thd) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_commit(thd)) error=1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(ulong) OPTION_BEGIN; + thd->no_trans_update.all= FALSE; } DBUG_RETURN(error); } @@ -171,8 +172,8 @@ static bool begin_trans(THD *thd) else { LEX *lex= thd->lex; - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | - OPTION_BEGIN); + thd->no_trans_update.all= FALSE; + thd->options|= (ulong) OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) error= ha_start_consistent_snapshot(thd); @@ -289,7 +290,8 @@ int check_user(THD *thd, enum enum_server_command command, bool check_count) { DBUG_ENTER("check_user"); - + LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 }; + #ifdef NO_EMBEDDED_ACCESS_CHECKS thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ @@ -300,7 +302,7 @@ int check_user(THD *thd, enum enum_server_command command, function returns 0 */ thd->reset_db(NULL, 0); - if (mysql_change_db(thd, db, FALSE)) + if (mysql_change_db(thd, &db_str, FALSE)) { /* Send the error to the client */ net_send_error(thd); @@ -442,7 +444,7 @@ int check_user(THD *thd, enum enum_server_command command, /* Change database if necessary */ if (db && db[0]) { - if (mysql_change_db(thd, db, FALSE)) + if (mysql_change_db(thd, &db_str, FALSE)) { /* Send error to the client */ net_send_error(thd); @@ -1463,7 +1465,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) */ thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(ulong) OPTION_BEGIN; + thd->no_trans_update.all= FALSE; break; case COMMIT_RELEASE: do_release= 1; /* fall through */ @@ -1480,7 +1483,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_rollback(thd)) res= -1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(ulong) OPTION_BEGIN; + thd->no_trans_update.all= FALSE; if (!res && (completion == ROLLBACK_AND_CHAIN)) res= begin_trans(thd); break; @@ -1635,7 +1639,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, &LOCK_status); thd->convert_string(&tmp, system_charset_info, packet, strlen(packet), thd->charset()); - if (!mysql_change_db(thd, tmp.str, FALSE)) + if (!mysql_change_db(thd, &tmp, FALSE)) { mysql_log.write(thd,command,"%s",thd->db); send_ok(thd); @@ -1859,7 +1863,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, packet= pend+1; if (!my_strcasecmp(system_charset_info, table_list.db, - information_schema_name.str)) + INFORMATION_SCHEMA_NAME.str)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias); if (schema_table) @@ -2233,7 +2237,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, enum enum_schema_tables schema_table_idx) { DBUG_ENTER("prepare_schema_table"); - SELECT_LEX *sel= 0; + SELECT_LEX *schema_select_lex= NULL; + switch (schema_table_idx) { case SCH_SCHEMATA: #if defined(DONT_ALLOW_SHOW_COMMANDS) @@ -2241,11 +2246,9 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ DBUG_RETURN(1); #else - if ((specialflag & SPECIAL_SKIP_SHOW_DB) && - check_global_access(thd, SHOW_DB_ACL)) - DBUG_RETURN(1); break; #endif + case SCH_TABLE_NAMES: case SCH_TABLES: case SCH_VIEWS: @@ -2255,32 +2258,25 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ DBUG_RETURN(1); #else + if (lex->select_lex.db == NULL && + thd->copy_db_to(&lex->select_lex.db, NULL)) { - char *db; - if (lex->select_lex.db == NULL && - thd->copy_db_to(&lex->select_lex.db, 0)) - { - DBUG_RETURN(1); - } - db= lex->select_lex.db; - remove_escape(db); // Fix escaped '_' - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); - DBUG_RETURN(1); - } - if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0, - is_schema_db(db))) - DBUG_RETURN(1); /* purecov: inspected */ - if (!thd->col_access && check_grant_db(thd,db)) - { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->security_ctx->priv_user, thd->security_ctx->priv_host, - db); - DBUG_RETURN(1); - } - break; + DBUG_RETURN(1); } + + schema_select_lex= new SELECT_LEX(); + schema_select_lex->db= lex->select_lex.db; + schema_select_lex->table_list.first= NULL; + remove_escape(schema_select_lex->db); // Fix escaped '_' + + if (check_db_name(schema_select_lex->db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db); + DBUG_RETURN(1); + } + + + break; #endif case SCH_COLUMNS: case SCH_STATISTICS: @@ -2289,28 +2285,23 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ DBUG_RETURN(1); #else - if (table_ident) { + DBUG_ASSERT(table_ident); + TABLE_LIST **query_tables_last= lex->query_tables_last; - sel= new SELECT_LEX(); + schema_select_lex= new SELECT_LEX(); /* 'parent_lex' is used in init_query() so it must be before it. */ - sel->parent_lex= lex; - sel->init_query(); - if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, - (List<String> *) 0, (List<String> *) 0)) + schema_select_lex->parent_lex= lex; + schema_select_lex->init_query(); + if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ, + (List<String> *) 0, (List<String> *) 0)) DBUG_RETURN(1); lex->query_tables_last= query_tables_last; - TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first; - char *db= table_list->db; - remove_escape(db); // Fix escaped '_' - remove_escape(table_list->table_name); - if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, - &table_list->grant.privilege, 0, 0, - test(table_list->schema_table))) - DBUG_RETURN(1); /* purecov: inspected */ - if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2, - UINT_MAX, 0)) - DBUG_RETURN(1); + + TABLE_LIST *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first; + remove_escape(dst_table->db); // Fix escaped '_' + remove_escape(dst_table->table_name); + break; } #endif @@ -2337,7 +2328,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); } TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; - table_list->schema_select_lex= sel; + table_list->schema_select_lex= schema_select_lex; table_list->schema_table_reformed= 1; statistic_increment(thd->status_var.com_stat[lex->orig_sql_command], &LOCK_status); @@ -2933,7 +2924,7 @@ mysql_execute_command(THD *thd) else { /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ - thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } DBUG_ASSERT(first_table == all_tables && first_table != 0); bool link_to_local; @@ -3707,10 +3698,10 @@ end_with_restore_list: we silently add IF EXISTS if TEMPORARY was used. */ if (thd->slave_thread) - lex->drop_if_exists= 1; + lex->drop_if_exists= 1; /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ - thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } /* DDL and binlog write order protected by LOCK_open */ res= mysql_rm_table(thd, first_table, lex->drop_if_exists, @@ -3750,9 +3741,14 @@ end_with_restore_list: } #endif case SQLCOM_CHANGE_DB: - if (!mysql_change_db(thd,select_lex->db,FALSE)) + { + LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; + + if (!mysql_change_db(thd, &db_str, FALSE)) send_ok(thd); + break; + } case SQLCOM_LOAD: { @@ -4296,7 +4292,7 @@ end_with_restore_list: res= TRUE; // cannot happen else { - if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && + if (thd->no_trans_update.all && !thd->slave_thread) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, @@ -4939,8 +4935,8 @@ create_sp_error: thd->transaction.xid_state.xa_state=XA_ACTIVE; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | - OPTION_BEGIN); + thd->no_trans_update.all= FALSE; + thd->options|= (ulong) OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd); break; @@ -5033,7 +5029,8 @@ create_sp_error: xa_state_names[thd->transaction.xid_state.xa_state]); break; } - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(ulong) OPTION_BEGIN; + thd->no_trans_update.all= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -5063,7 +5060,8 @@ create_sp_error: my_error(ER_XAER_RMERR, MYF(0)); else send_ok(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(ulong) OPTION_BEGIN; + thd->no_trans_update.all= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -5159,7 +5157,10 @@ bool check_single_table_access(THD *thd, ulong privilege, goto deny; /* Show only 1 table for check_grant */ - if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0)) + if (grant_option && + !(all_tables->belong_to_view && + (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && + check_grant(thd, privilege, all_tables, 0, 1, 0)) goto deny; thd->security_ctx= backup_ctx; @@ -5376,6 +5377,83 @@ bool check_global_access(THD *thd, ulong want_access) } +static bool check_show_access(THD *thd, TABLE_LIST *table) +{ + switch (get_schema_table_idx(table->schema_table)) + { + case SCH_SCHEMATA: + return (specialflag & SPECIAL_SKIP_SHOW_DB) && + check_global_access(thd, SHOW_DB_ACL); + + case SCH_TABLE_NAMES: + case SCH_TABLES: + case SCH_VIEWS: + case SCH_TRIGGERS: + { + const char *dst_db_name= table->schema_select_lex->db; + + DBUG_ASSERT(dst_db_name); + + if (check_access(thd, SELECT_ACL, dst_db_name, + &thd->col_access, FALSE, FALSE, + is_schema_db(dst_db_name))) + { + return TRUE; + } + + if (!thd->col_access && check_grant_db(thd, dst_db_name)) + { + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->security_ctx->priv_user, + thd->security_ctx->priv_host, + dst_db_name); + return TRUE; + } + + return FALSE; + } + + case SCH_COLUMNS: + case SCH_STATISTICS: + { + TABLE_LIST *dst_table= + (TABLE_LIST *) table->schema_select_lex->table_list.first; + + DBUG_ASSERT(dst_table); + + if (check_access(thd, SELECT_ACL | EXTRA_ACL, + dst_table->db, + &dst_table->grant.privilege, + FALSE, FALSE, + test(dst_table->schema_table))) + { + return FALSE; + } + + return grant_option && + check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE); + } + + case SCH_OPEN_TABLES: + case SCH_VARIABLES: + case SCH_STATUS: + case SCH_PROCEDURES: + case SCH_CHARSETS: + case SCH_COLLATIONS: + case SCH_COLLATION_CHARACTER_SET_APPLICABILITY: + case SCH_USER_PRIVILEGES: + case SCH_SCHEMA_PRIVILEGES: + case SCH_TABLE_PRIVILEGES: + case SCH_COLUMN_PRIVILEGES: + case SCH_TABLE_CONSTRAINTS: + case SCH_KEY_COLUMN_USAGE: + break; + } + + return FALSE; +} + + /* Check the privilege for all used tables. @@ -5428,7 +5506,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, - information_schema_name.str); + INFORMATION_SCHEMA_NAME.str); return TRUE; } /* @@ -5436,7 +5514,16 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, Remove SHOW_VIEW_ACL, because it will be checked during making view */ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); - if (tables->derived || tables->schema_table || + + if (tables->schema_table_reformed) + { + if (check_show_access(thd, tables)) + goto deny; + + continue; + } + + if (tables->derived || (tables->table && (int)tables->table->s->tmp_table) || my_tz_check_n_skip_implicit_tables(&tables, thd->lex->time_zone_tables_used)) @@ -6248,7 +6335,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db, - information_schema_name.str)) + INFORMATION_SCHEMA_NAME.str)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name); if (!schema_table || @@ -6256,7 +6343,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, lex->orig_sql_command == SQLCOM_END)) // not a 'show' command { my_error(ER_UNKNOWN_TABLE, MYF(0), - ptr->table_name, information_schema_name.str); + ptr->table_name, INFORMATION_SCHEMA_NAME.str); DBUG_RETURN(0); } ptr->schema_table_name= ptr->table_name; |