Commit 315665cf authored by unknown's avatar unknown

Bug#32890 Crash after repeated create and drop of tables and views

The problem is that CREATE VIEW statements inside prepared statements
weren't being expanded during the prepare phase, which leads to objects
not being allocated in the appropriate memory arenas.

The solution is to perform the validation of CREATE VIEW statements
during the prepare phase of a prepared statement. The validation
during the prepare phase assures that transformations of the parsed
tree will use the permanent arena of the prepared statement.


mysql-test/r/ps.result:
  Add test case result for Bug#32890
mysql-test/t/ps.test:
  Add test case for Bug#32890
sql/item.h:
  Restore original field name if name is auto generated.
sql/sql_prepare.cc:
  Validate and prepare a CREATE VIEW statement for execution.
sql/sql_view.cc:
  Move privileges check to it's own function.
sql/sql_view.h:
  Export function which check privileges of a CREATE VIEW statement.
parent fa08b280
...@@ -1709,4 +1709,156 @@ a b ...@@ -1709,4 +1709,156 @@ a b
9999999999999999 14632475938453979136 9999999999999999 14632475938453979136
deallocate prepare stmt; deallocate prepare stmt;
drop table t1; drop table t1;
drop view if exists v1;
drop table if exists t1;
create table t1 (a int, b int);
insert into t1 values (1,1), (2,2), (3,3);
insert into t1 values (3,1), (1,2), (2,3);
prepare stmt from "create view v1 as select * from t1";
execute stmt;
drop table t1;
create table t1 (a int, b int);
drop view v1;
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1`
drop view v1;
prepare stmt from "create view v1 (c,d) as select a,b from t1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d` from `t1`
select * from v1;
c d
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d` from `t1`
select * from v1;
c d
drop view v1;
prepare stmt from "create view v1 (c) as select b+1 from t1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1`
select * from v1;
c
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`b` + 1) AS `c` from `t1`
select * from v1;
c
drop view v1;
prepare stmt from "create view v1 (c,d,e,f) as select a,b,a in (select a+2 from t1), a = all (select a from t1) from t1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d`,`t1`.`a` in (select (`t1`.`a` + 2) AS `a+2` from `t1`) AS `e`,`t1`.`a` = all (select `t1`.`a` AS `a` from `t1`) AS `f` from `t1`
select * from v1;
c d e f
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `c`,`t1`.`b` AS `d`,`t1`.`a` in (select (`t1`.`a` + 2) AS `a+2` from `t1`) AS `e`,`t1`.`a` = all (select `t1`.`a` AS `a` from `t1`) AS `f` from `t1`
select * from v1;
c d e f
drop view v1;
prepare stmt from "create or replace view v1 as select 1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
select * from v1;
1
1
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`
select * from v1;
1
1
drop view v1;
prepare stmt from "create view v1 as select 1, 1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`,1 AS `My_exp_1`
select * from v1;
1 My_exp_1
1 1
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1`,1 AS `My_exp_1`
select * from v1;
1 My_exp_1
1 1
drop view v1;
prepare stmt from "create view v1 (x) as select a from t1 where a > 1";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `x` from `t1` where (`t1`.`a` > 1)
select * from v1;
x
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `x` from `t1` where (`t1`.`a` > 1)
select * from v1;
x
drop view v1;
prepare stmt from "create view v1 as select * from `t1` `b`";
execute stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `b`.`a` AS `a`,`b`.`b` AS `b` from `t1` `b`
select * from v1;
a b
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `b`.`a` AS `a`,`b`.`b` AS `b` from `t1` `b`
select * from v1;
a b
drop view v1;
prepare stmt from "create view v1 (a,b,c) as select * from t1";
execute stmt;
ERROR HY000: View's SELECT and view's field list have different column counts
execute stmt;
ERROR HY000: View's SELECT and view's field list have different column counts
deallocate prepare stmt;
drop table t1;
create temporary table t1 (a int, b int);
prepare stmt from "create view v1 as select * from t1";
execute stmt;
ERROR HY000: View's SELECT refers to a temporary table 't1'
execute stmt;
ERROR HY000: View's SELECT refers to a temporary table 't1'
deallocate prepare stmt;
drop table t1;
prepare stmt from "create view v1 as select * from t1";
ERROR 42S02: Table 'test.t1' doesn't exist
prepare stmt from "create view v1 as select * from `t1` `b`";
ERROR 42S02: Table 'test.t1' doesn't exist
End of 5.0 tests. End of 5.0 tests.
...@@ -1824,4 +1824,127 @@ select * from t1 where a = @a and b = @b; ...@@ -1824,4 +1824,127 @@ select * from t1 where a = @a and b = @b;
deallocate prepare stmt; deallocate prepare stmt;
drop table t1; drop table t1;
#
# Bug#32890 Crash after repeated create and drop of tables and views
#
--disable_warnings
drop view if exists v1;
drop table if exists t1;
--enable_warnings
create table t1 (a int, b int);
insert into t1 values (1,1), (2,2), (3,3);
insert into t1 values (3,1), (1,2), (2,3);
prepare stmt from "create view v1 as select * from t1";
execute stmt;
drop table t1;
create table t1 (a int, b int);
drop view v1;
execute stmt;
show create view v1;
drop view v1;
prepare stmt from "create view v1 (c,d) as select a,b from t1";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 (c) as select b+1 from t1";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 (c,d,e,f) as select a,b,a in (select a+2 from t1), a = all (select a from t1) from t1";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create or replace view v1 as select 1";
execute stmt;
show create view v1;
select * from v1;
execute stmt;
show create view v1;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 as select 1, 1";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 (x) as select a from t1 where a > 1";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 as select * from `t1` `b`";
execute stmt;
show create view v1;
select * from v1;
drop view v1;
execute stmt;
deallocate prepare stmt;
show create view v1;
select * from v1;
drop view v1;
prepare stmt from "create view v1 (a,b,c) as select * from t1";
--error ER_VIEW_WRONG_LIST
execute stmt;
--error ER_VIEW_WRONG_LIST
execute stmt;
deallocate prepare stmt;
drop table t1;
create temporary table t1 (a int, b int);
prepare stmt from "create view v1 as select * from t1";
--error ER_VIEW_SELECT_TMPTABLE
execute stmt;
--error ER_VIEW_SELECT_TMPTABLE
execute stmt;
deallocate prepare stmt;
drop table t1;
--error ER_NO_SUCH_TABLE
prepare stmt from "create view v1 as select * from t1";
--error ER_NO_SUCH_TABLE
prepare stmt from "create view v1 as select * from `t1` `b`";
--echo End of 5.0 tests. --echo End of 5.0 tests.
...@@ -879,6 +879,23 @@ public: ...@@ -879,6 +879,23 @@ public:
class sp_head; class sp_head;
class Item_basic_constant :public Item
{
public:
/* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup()
{
/*
Restore the original field name as it might not have been allocated
in the statement memory. If the name is auto generated, it must be
done again between subsequent executions of a prepared statement.
*/
if (orig_name)
name= orig_name;
}
};
/***************************************************************************** /*****************************************************************************
The class is a base class for representation of stored routine variables in The class is a base class for representation of stored routine variables in
the Item-hierarchy. There are the following kinds of SP-vars: the Item-hierarchy. There are the following kinds of SP-vars:
...@@ -1161,7 +1178,7 @@ bool agg_item_charsets(DTCollation &c, const char *name, ...@@ -1161,7 +1178,7 @@ bool agg_item_charsets(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep); Item **items, uint nitems, uint flags, int item_sep);
class Item_num: public Item class Item_num: public Item_basic_constant
{ {
public: public:
Item_num() {} /* Remove gcc warning */ Item_num() {} /* Remove gcc warning */
...@@ -1352,7 +1369,7 @@ public: ...@@ -1352,7 +1369,7 @@ public:
friend class st_select_lex_unit; friend class st_select_lex_unit;
}; };
class Item_null :public Item class Item_null :public Item_basic_constant
{ {
public: public:
Item_null(char *name_par=0) Item_null(char *name_par=0)
...@@ -1374,8 +1391,6 @@ public: ...@@ -1374,8 +1391,6 @@ public:
bool send(Protocol *protocol, String *str); bool send(Protocol *protocol, String *str);
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NULL; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
/* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup() {}
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_null(name); } Item *clone_item() { return new Item_null(name); }
bool is_null() { return 1; } bool is_null() { return 1; }
...@@ -1567,8 +1582,6 @@ public: ...@@ -1567,8 +1582,6 @@ public:
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_int(name,value,max_length); } Item *clone_item() { return new Item_int(name,value,max_length); }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str); void print(String *str);
Item_num *neg() { value= -value; return this; } Item_num *neg() { value= -value; return this; }
uint decimal_precision() const uint decimal_precision() const
...@@ -1621,8 +1634,6 @@ public: ...@@ -1621,8 +1634,6 @@ public:
{ {
return new Item_decimal(name, &decimal_value, decimals, max_length); return new Item_decimal(name, &decimal_value, decimals, max_length);
} }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str); void print(String *str);
Item_num *neg() Item_num *neg()
{ {
...@@ -1673,8 +1684,6 @@ public: ...@@ -1673,8 +1684,6 @@ public:
String *val_str(String*); String *val_str(String*);
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
Item *clone_item() Item *clone_item()
{ return new Item_float(name, value, decimals, max_length); } { return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; } Item_num *neg() { value= -value; return this; }
...@@ -1696,7 +1705,7 @@ public: ...@@ -1696,7 +1705,7 @@ public:
}; };
class Item_string :public Item class Item_string :public Item_basic_constant
{ {
public: public:
Item_string(const char *str,uint length, Item_string(const char *str,uint length,
...@@ -1780,8 +1789,6 @@ public: ...@@ -1780,8 +1789,6 @@ public:
max_length= str_value.numchars() * collation.collation->mbmaxlen; max_length= str_value.numchars() * collation.collation->mbmaxlen;
} }
void print(String *str); void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
}; };
...@@ -1839,10 +1846,10 @@ public: ...@@ -1839,10 +1846,10 @@ public:
}; };
class Item_hex_string: public Item class Item_hex_string: public Item_basic_constant
{ {
public: public:
Item_hex_string(): Item() {} Item_hex_string() {}
Item_hex_string(const char *str,uint str_length); Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; } enum Type type() const { return VARBIN_ITEM; }
double val_real() double val_real()
...@@ -1858,8 +1865,6 @@ public: ...@@ -1858,8 +1865,6 @@ public:
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
enum Item_result cast_to_int_type() const { return INT_RESULT; } enum Item_result cast_to_int_type() const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str); void print(String *str);
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs); virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
...@@ -2449,7 +2454,7 @@ private: ...@@ -2449,7 +2454,7 @@ private:
}; };
class Item_cache: public Item class Item_cache: public Item_basic_constant
{ {
protected: protected:
Item *example; Item *example;
...@@ -2486,8 +2491,6 @@ public: ...@@ -2486,8 +2491,6 @@ public:
static Item_cache* get_cache(const Item *item); static Item_cache* get_cache(const Item *item);
table_map used_tables() const { return used_table_map; } table_map used_tables() const { return used_table_map; }
virtual void keep_array() {} virtual void keep_array() {}
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str); void print(String *str);
bool eq_def(Field *field) bool eq_def(Field *field)
{ {
......
...@@ -1512,6 +1512,45 @@ static bool mysql_test_create_table(Prepared_statement *stmt) ...@@ -1512,6 +1512,45 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
} }
/**
@brief Validate and prepare for execution CREATE VIEW statement
@param stmt prepared statement
@note This function handles create view commands.
@retval FALSE Operation was a success.
@retval TRUE An error occured.
*/
static bool mysql_test_create_view(Prepared_statement *stmt)
{
DBUG_ENTER("mysql_test_create_view");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
bool res= TRUE;
/* Skip first table, which is the view we are creating */
bool link_to_local;
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
if (create_view_precheck(thd, tables, view, lex->create_view_mode))
goto err;
if (open_normal_and_derived_tables(thd, tables, 0))
goto err;
lex->view_prepare_mode= 1;
res= select_like_stmt_test(stmt, 0, 0);
err:
/* put view back for PS rexecuting */
lex->link_first_table_back(view, link_to_local);
DBUG_RETURN(res);
}
/* /*
Validate and prepare for execution a multi update statement. Validate and prepare for execution a multi update statement.
...@@ -1730,6 +1769,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, ...@@ -1730,6 +1769,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0)); my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error; goto error;
} }
res= mysql_test_create_view(stmt);
break; break;
case SQLCOM_DO: case SQLCOM_DO:
res= mysql_test_do_fields(stmt, tables, lex->insert_list); res= mysql_test_do_fields(stmt, tables, lex->insert_list);
......
...@@ -227,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) ...@@ -227,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
return FALSE; return FALSE;
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/** /**
@brief Creating/altering VIEW procedure @brief CREATE VIEW privileges pre-check.
@param thd thread handler @param thd thread handler
@param tables tables used in the view
@param views views to create @param views views to create
@param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE @param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
@note This function handles both create and alter view commands.
@retval FALSE Operation was a success. @retval FALSE Operation was a success.
@retval TRUE An error occured. @retval TRUE An error occured.
*/ */
bool mysql_create_view(THD *thd, TABLE_LIST *views, bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
enum_view_create_mode mode) enum_view_create_mode mode)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
bool link_to_local;
/* first table in list is target VIEW name => cut off it */ /* first table in list is target VIEW name => cut off it */
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl; TABLE_LIST *tbl;
SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX *select_lex= &lex->select_lex;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
SELECT_LEX *sl; SELECT_LEX *sl;
#endif bool res= TRUE;
SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("create_view_precheck");
bool res= FALSE;
DBUG_ENTER("mysql_create_view");
/* This is ensured in the parser. */
DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
!lex->param_list.elements && !lex->derived_tables);
if (mode != VIEW_CREATE_NEW)
{
if (mode == VIEW_ALTER &&
fill_defined_view_parts(thd, view))
{
res= TRUE;
goto err;
}
sp_cache_invalidate();
}
if (!lex->definer)
{
/*
DEFINER-clause is missing; we have to create default definer in
persistent arena to be PS/SP friendly.
If this is an ALTER VIEW then the current user should be set as
the definer.
*/
Query_arena original_arena;
Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
if (!(lex->definer= create_default_definer(thd)))
res= TRUE;
if (ps_arena)
thd->restore_active_arena(ps_arena, &original_arena);
if (res)
goto err;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
check definer of view:
- same as current user
- current user has SUPER_ACL
*/
if (lex->definer &&
(strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
my_strcasecmp(system_charset_info,
lex->definer->host.str,
thd->security_ctx->priv_host) != 0))
{
if (!(thd->security_ctx->master_access & SUPER_ACL))
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
res= TRUE;
goto err;
}
else
{
if (!is_acl_user(lex->definer->host.str,
lex->definer->user.str))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,
ER(ER_NO_SUCH_USER),
lex->definer->user.str,
lex->definer->host.str);
}
}
}
/* /*
Privilege check for view creation: Privilege check for view creation:
- user has CREATE VIEW privilege on view table - user has CREATE VIEW privilege on view table
...@@ -346,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -346,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege, (check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
0, 0, is_schema_db(view->db)) || 0, 0, is_schema_db(view->db)) ||
grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0)))) grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
{
res= TRUE;
goto err; goto err;
}
for (sl= select_lex; sl; sl= sl->next_select()) for (sl= select_lex; sl; sl= sl->next_select())
{ {
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local) for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
...@@ -363,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -363,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->security_ctx->priv_user, "ANY", thd->security_ctx->priv_user,
thd->security_ctx->priv_host, tbl->table_name); thd->security_ctx->priv_host, tbl->table_name);
res= TRUE;
goto err; goto err;
} }
/* /*
...@@ -399,13 +323,10 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -399,13 +323,10 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (check_access(thd, SELECT_ACL, tbl->db, if (check_access(thd, SELECT_ACL, tbl->db,
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) || &tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0)) grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
{
res= TRUE;
goto err; goto err;
} }
} }
} }
}
/* /*
Mark fields for special privilege check ("any" privilege) Mark fields for special privilege check ("any" privilege)
*/ */
...@@ -426,8 +347,126 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -426,8 +347,126 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
} }
} }
} }
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
@param thd thread handler
@param views views to create
@param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
@note This function handles both create and alter view commands.
@retval FALSE Operation was a success.
@retval TRUE An error occured.
*/
bool mysql_create_view(THD *thd, TABLE_LIST *views,
enum_view_create_mode mode)
{
LEX *lex= thd->lex;
bool link_to_local;
/* first table in list is target VIEW name => cut off it */
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl;
SELECT_LEX *select_lex= &lex->select_lex;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
SELECT_LEX *sl;
#endif
SELECT_LEX_UNIT *unit= &lex->unit;
bool res= FALSE;
DBUG_ENTER("mysql_create_view");
/* This is ensured in the parser. */
DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
!lex->param_list.elements && !lex->derived_tables);
if (mode != VIEW_CREATE_NEW)
{
if (mode == VIEW_ALTER &&
fill_defined_view_parts(thd, view))
{
res= TRUE;
goto err;
}
sp_cache_invalidate();
}
if (!lex->definer)
{
/*
DEFINER-clause is missing; we have to create default definer in
persistent arena to be PS/SP friendly.
If this is an ALTER VIEW then the current user should be set as
the definer.
*/
Query_arena original_arena;
Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
if (!(lex->definer= create_default_definer(thd)))
res= TRUE;
if (ps_arena)
thd->restore_active_arena(ps_arena, &original_arena);
if (res)
goto err;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
check definer of view:
- same as current user
- current user has SUPER_ACL
*/
if (lex->definer &&
(strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
my_strcasecmp(system_charset_info,
lex->definer->host.str,
thd->security_ctx->priv_host) != 0))
{
if (!(thd->security_ctx->master_access & SUPER_ACL))
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
res= TRUE;
goto err;
}
else
{
if (!is_acl_user(lex->definer->host.str,
lex->definer->user.str))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,
ER(ER_NO_SUCH_USER),
lex->definer->user.str,
lex->definer->host.str);
}
}
}
#endif #endif
if ((res= create_view_precheck(thd, tables, view, mode)))
goto err;
if (open_and_lock_tables(thd, tables)) if (open_and_lock_tables(thd, tables))
{ {
res= TRUE; res= TRUE;
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
enum_view_create_mode mode);
bool mysql_create_view(THD *thd, TABLE_LIST *view, bool mysql_create_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode); enum_view_create_mode mode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment