diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 8845f011971..32f48a688e2 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1709,4 +1709,156 @@ a b 9999999999999999 14632475938453979136 deallocate prepare stmt; 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. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 3f4b37f13f4..58ba901d82b 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1824,4 +1824,127 @@ select * from t1 where a = @a and b = @b; deallocate prepare stmt; 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. diff --git a/sql/item.h b/sql/item.h index 5f511557f47..ae3e240778a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -879,6 +879,23 @@ public: 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 Item-hierarchy. There are the following kinds of SP-vars: @@ -1161,7 +1178,7 @@ bool agg_item_charsets(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); -class Item_num: public Item +class Item_num: public Item_basic_constant { public: Item_num() {} /* Remove gcc warning */ @@ -1352,7 +1369,7 @@ public: friend class st_select_lex_unit; }; -class Item_null :public Item +class Item_null :public Item_basic_constant { public: Item_null(char *name_par=0) @@ -1374,8 +1391,6 @@ public: bool send(Protocol *protocol, String *str); enum Item_result result_type () const { return STRING_RESULT; } 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; } Item *clone_item() { return new Item_null(name); } bool is_null() { return 1; } @@ -1567,8 +1582,6 @@ public: int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } 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); Item_num *neg() { value= -value; return this; } uint decimal_precision() const @@ -1621,8 +1634,6 @@ public: { 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); Item_num *neg() { @@ -1673,8 +1684,6 @@ public: String *val_str(String*); my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} Item *clone_item() { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } @@ -1696,7 +1705,7 @@ public: }; -class Item_string :public Item +class Item_string :public Item_basic_constant { public: Item_string(const char *str,uint length, @@ -1780,8 +1789,6 @@ public: max_length= str_value.numchars() * collation.collation->mbmaxlen; } void print(String *str); - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} }; @@ -1839,10 +1846,10 @@ public: }; -class Item_hex_string: public Item +class Item_hex_string: public Item_basic_constant { public: - Item_hex_string(): Item() {} + Item_hex_string() {} Item_hex_string(const char *str,uint str_length); enum Type type() const { return VARBIN_ITEM; } double val_real() @@ -1858,8 +1865,6 @@ public: enum Item_result result_type () const { return STRING_RESULT; } enum Item_result cast_to_int_type() const { return INT_RESULT; } 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); bool eq(const Item *item, bool binary_cmp) const; virtual Item *safe_charset_converter(CHARSET_INFO *tocs); @@ -2449,7 +2454,7 @@ private: }; -class Item_cache: public Item +class Item_cache: public Item_basic_constant { protected: Item *example; @@ -2486,8 +2491,6 @@ public: static Item_cache* get_cache(const Item *item); table_map used_tables() const { return used_table_map; } virtual void keep_array() {} - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} void print(String *str); bool eq_def(Field *field) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 74cbd2c5505..4972b259693 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -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. @@ -1730,6 +1769,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0)); goto error; } + res= mysql_test_create_view(stmt); break; case SQLCOM_DO: res= mysql_test_do_fields(stmt, tables, lex->insert_list); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 48ab5b3af9e..4c8e6e80c41 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -227,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 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 @@ -241,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; @@ -325,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 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; diff --git a/sql/sql_view.h b/sql/sql_view.h index ab0920e0bf2..1d45283352b 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -15,6 +15,9 @@ 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, enum_view_create_mode mode);