diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.h | 43 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 40 | ||||
-rw-r--r-- | sql/sql_view.cc | 213 | ||||
-rw-r--r-- | sql/sql_view.h | 3 |
4 files changed, 192 insertions, 107 deletions
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,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) return FALSE; } +#ifndef NO_EMBEDDED_ACCESS_CHECKS /** - @brief Creating/altering VIEW procedure + @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 - @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) +bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, + 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(); - } + bool res= TRUE; + DBUG_ENTER("create_view_precheck"); - 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: - user has CREATE VIEW privilege on view table @@ -346,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, (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) @@ -363,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, 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; } /* @@ -399,10 +323,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, 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; - } } } } @@ -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 + 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); |