summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc227
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;