mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Merge chunk from trunk.
This commit is contained in:
272
sql/sql_view.cc
272
sql/sql_view.cc
@@ -182,10 +182,33 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
|
||||
TABLE_LIST decoy;
|
||||
|
||||
memcpy (&decoy, view, sizeof (TABLE_LIST));
|
||||
if (!open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE) &&
|
||||
!decoy.view)
|
||||
|
||||
/*
|
||||
Let's reset decoy.view before calling open_table(): when we start
|
||||
supporting ALTER VIEW in PS/SP that may save us from a crash.
|
||||
*/
|
||||
|
||||
decoy.view= NULL;
|
||||
|
||||
/*
|
||||
open_table() will return NULL if 'decoy' is idenitifying a view *and*
|
||||
there is no TABLE object for that view in the table cache. However,
|
||||
decoy.view will be set to 1.
|
||||
|
||||
If there is a TABLE-instance for the oject identified by 'decoy',
|
||||
open_table() will return that instance no matter if it is a table or
|
||||
a view.
|
||||
|
||||
Thus, there is no need to check for the return value of open_table(),
|
||||
since the return value itself does not mean anything.
|
||||
*/
|
||||
|
||||
open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE);
|
||||
|
||||
if (!decoy.view)
|
||||
{
|
||||
/* It's a table */
|
||||
/* It's a table. */
|
||||
my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -204,6 +227,143 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
||||
/**
|
||||
@brief CREATE VIEW privileges pre-check.
|
||||
|
||||
@param thd thread handler
|
||||
@param tables tables used in the view
|
||||
@param views views to create
|
||||
@param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
|
||||
|
||||
@retval FALSE Operation was a success.
|
||||
@retval TRUE An error occured.
|
||||
*/
|
||||
|
||||
bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
|
||||
enum_view_create_mode mode)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
/* first table in list is target VIEW name => cut off it */
|
||||
TABLE_LIST *tbl;
|
||||
SELECT_LEX *select_lex= &lex->select_lex;
|
||||
SELECT_LEX *sl;
|
||||
bool res= TRUE;
|
||||
DBUG_ENTER("create_view_precheck");
|
||||
|
||||
/*
|
||||
Privilege check for view creation:
|
||||
- user has CREATE VIEW privilege on view table
|
||||
- user has DROP privilege in case of ALTER VIEW or CREATE OR REPLACE
|
||||
VIEW
|
||||
- user has some (SELECT/UPDATE/INSERT/DELETE) privileges on columns of
|
||||
underlying tables used on top of SELECT list (because it can be
|
||||
(theoretically) updated, so it is enough to have UPDATE privilege on
|
||||
them, for example)
|
||||
- user has SELECT privilege on columns used in expressions of VIEW select
|
||||
- for columns of underly tables used on top of SELECT list also will be
|
||||
checked that we have not more privileges on correspondent column of view
|
||||
table (i.e. user will not get some privileges by view creation)
|
||||
*/
|
||||
if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
|
||||
0, 0, is_schema_db(view->db)) ||
|
||||
grant_option && check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
|
||||
(mode != VIEW_CREATE_NEW &&
|
||||
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
|
||||
0, 0, is_schema_db(view->db)) ||
|
||||
grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
|
||||
goto err;
|
||||
|
||||
for (sl= select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
|
||||
{
|
||||
/*
|
||||
Ensure that we have some privileges on this table, more strict check
|
||||
will be done on column level after preparation,
|
||||
*/
|
||||
if (check_some_access(thd, VIEW_ANY_ACL, tbl))
|
||||
{
|
||||
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
|
||||
"ANY", thd->security_ctx->priv_user,
|
||||
thd->security_ctx->priv_host, tbl->table_name);
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
Mark this table as a table which will be checked after the prepare
|
||||
phase
|
||||
*/
|
||||
tbl->table_in_first_from_clause= 1;
|
||||
|
||||
/*
|
||||
We need to check only SELECT_ACL for all normal fields, fields for
|
||||
which we need "any" (SELECT/UPDATE/INSERT/DELETE) privilege will be
|
||||
checked later
|
||||
*/
|
||||
tbl->grant.want_privilege= SELECT_ACL;
|
||||
/*
|
||||
Make sure that all rights are loaded to the TABLE::grant field.
|
||||
|
||||
tbl->table_name will be correct name of table because VIEWs are
|
||||
not opened yet.
|
||||
*/
|
||||
fill_effective_table_privileges(thd, &tbl->grant, tbl->db,
|
||||
tbl->table_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (&lex->select_lex != lex->all_selects_list)
|
||||
{
|
||||
/* check tables of subqueries */
|
||||
for (tbl= tables; tbl; tbl= tbl->next_global)
|
||||
{
|
||||
if (!tbl->table_in_first_from_clause)
|
||||
{
|
||||
if (check_access(thd, SELECT_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
|
||||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Mark fields for special privilege check ("any" privilege)
|
||||
*/
|
||||
for (sl= select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
List_iterator_fast<Item> it(sl->item_list);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
Item_field *field;
|
||||
if ((field= item->filed_for_view_update()))
|
||||
{
|
||||
/*
|
||||
any_privileges may be reset later by the Item_field::set_field
|
||||
method in case of a system temporary table.
|
||||
*/
|
||||
field->any_privileges= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res= FALSE;
|
||||
|
||||
err:
|
||||
DBUG_RETURN(res || thd->net.report_error);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
|
||||
enum_view_create_mode mode)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@brief Creating/altering VIEW procedure
|
||||
@@ -218,7 +378,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
|
||||
@retval TRUE An error occured.
|
||||
*/
|
||||
|
||||
bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
||||
bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
||||
enum_view_create_mode mode)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
@@ -302,109 +462,11 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Privilege check for view creation:
|
||||
- user has CREATE VIEW privilege on view table
|
||||
- user has DROP privilege in case of ALTER VIEW or CREATE OR REPLACE
|
||||
VIEW
|
||||
- user has some (SELECT/UPDATE/INSERT/DELETE) privileges on columns of
|
||||
underlying tables used on top of SELECT list (because it can be
|
||||
(theoretically) updated, so it is enough to have UPDATE privilege on
|
||||
them, for example)
|
||||
- user has SELECT privilege on columns used in expressions of VIEW select
|
||||
- for columns of underly tables used on top of SELECT list also will be
|
||||
checked that we have not more privileges on correspondent column of view
|
||||
table (i.e. user will not get some privileges by view creation)
|
||||
*/
|
||||
if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
|
||||
0, 0, is_schema_db(view->db)) ||
|
||||
grant_option && check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
|
||||
(mode != VIEW_CREATE_NEW &&
|
||||
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
|
||||
0, 0, is_schema_db(view->db)) ||
|
||||
grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
|
||||
{
|
||||
res= TRUE;
|
||||
goto err;
|
||||
}
|
||||
for (sl= select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
|
||||
{
|
||||
/*
|
||||
Ensure that we have some privileges on this table, more strict check
|
||||
will be done on column level after preparation,
|
||||
*/
|
||||
if (check_some_access(thd, VIEW_ANY_ACL, tbl))
|
||||
{
|
||||
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
|
||||
"ANY", thd->security_ctx->priv_user,
|
||||
thd->security_ctx->priv_host, tbl->table_name);
|
||||
res= TRUE;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
Mark this table as a table which will be checked after the prepare
|
||||
phase
|
||||
*/
|
||||
tbl->table_in_first_from_clause= 1;
|
||||
|
||||
/*
|
||||
We need to check only SELECT_ACL for all normal fields, fields for
|
||||
which we need "any" (SELECT/UPDATE/INSERT/DELETE) privilege will be
|
||||
checked later
|
||||
*/
|
||||
tbl->grant.want_privilege= SELECT_ACL;
|
||||
/*
|
||||
Make sure that all rights are loaded to the TABLE::grant field.
|
||||
|
||||
tbl->table_name will be correct name of table because VIEWs are
|
||||
not opened yet.
|
||||
*/
|
||||
fill_effective_table_privileges(thd, &tbl->grant, tbl->db,
|
||||
tbl->table_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (&lex->select_lex != lex->all_selects_list)
|
||||
{
|
||||
/* check tables of subqueries */
|
||||
for (tbl= tables; tbl; tbl= tbl->next_global)
|
||||
{
|
||||
if (!tbl->table_in_first_from_clause)
|
||||
{
|
||||
if (check_access(thd, SELECT_ACL, tbl->db,
|
||||
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
|
||||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
|
||||
{
|
||||
res= TRUE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Mark fields for special privilege check ("any" privilege)
|
||||
*/
|
||||
for (sl= select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
List_iterator_fast<Item> it(sl->item_list);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
Item_field *field;
|
||||
if ((field= item->filed_for_view_update()))
|
||||
{
|
||||
/*
|
||||
any_privileges may be reset later by the Item_field::set_field
|
||||
method in case of a system temporary table.
|
||||
*/
|
||||
field->any_privileges= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((res= create_view_precheck(thd, tables, view, mode)))
|
||||
goto err;
|
||||
|
||||
if (open_and_lock_tables(thd, tables))
|
||||
{
|
||||
res= TRUE;
|
||||
|
Reference in New Issue
Block a user