diff options
author | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-03-24 18:03:44 +0300 |
---|---|---|
committer | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-03-24 18:03:44 +0300 |
commit | d95c1e3b470506c7df6dfce3fe6dc7e5b46930ee (patch) | |
tree | 9f13d4fcc3ac732dc94fe2cae446f6f8c2b4e02b /sql/sql_view.cc | |
parent | abc6846d5b1df4846c4ffc03f4c93c82f874dd96 (diff) | |
parent | ae715642f46d4ed9ea8b5dd9b5cc9f3cace7f437 (diff) | |
download | mariadb-git-d95c1e3b470506c7df6dfce3fe6dc7e5b46930ee.tar.gz |
Manual merge of mysql-trunk into mysql-trunk-merge.
Conflicts:
Text conflict in client/mysqlbinlog.cc
Text conflict in mysql-test/Makefile.am
Text conflict in mysql-test/collections/default.daily
Text conflict in mysql-test/r/mysqlbinlog_row_innodb.result
Text conflict in mysql-test/suite/rpl/r/rpl_typeconv_innodb.result
Text conflict in mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test
Text conflict in mysql-test/suite/rpl/t/rpl_row_create_table.test
Text conflict in mysql-test/suite/rpl/t/rpl_slave_skip.test
Text conflict in mysql-test/suite/rpl/t/rpl_typeconv_innodb.test
Text conflict in mysys/charset.c
Text conflict in sql/field.cc
Text conflict in sql/field.h
Text conflict in sql/item.h
Text conflict in sql/item_func.cc
Text conflict in sql/log.cc
Text conflict in sql/log_event.cc
Text conflict in sql/log_event_old.cc
Text conflict in sql/mysqld.cc
Text conflict in sql/rpl_utility.cc
Text conflict in sql/rpl_utility.h
Text conflict in sql/set_var.cc
Text conflict in sql/share/Makefile.am
Text conflict in sql/sql_delete.cc
Text conflict in sql/sql_plugin.cc
Text conflict in sql/sql_select.cc
Text conflict in sql/sql_table.cc
Text conflict in storage/example/ha_example.h
Text conflict in storage/federated/ha_federated.cc
Text conflict in storage/myisammrg/ha_myisammrg.cc
Text conflict in storage/myisammrg/myrg_open.c
Diffstat (limited to 'sql/sql_view.cc')
-rw-r--r-- | sql/sql_view.cc | 189 |
1 files changed, 111 insertions, 78 deletions
diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3e81796ede7..2f40720c7ae 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,15 +29,6 @@ const LEX_STRING view_type= { C_STRING_WITH_LEN("VIEW") }; static int mysql_register_view(THD *thd, TABLE_LIST *view, enum_view_create_mode mode); -const char *updatable_views_with_limit_names[]= { "NO", "YES", NullS }; -TYPELIB updatable_views_with_limit_typelib= -{ - array_elements(updatable_views_with_limit_names)-1, "", - updatable_views_with_limit_names, - 0 -}; - - /* Make a unique name for an anonymous view column SYNOPSIS @@ -207,40 +198,17 @@ static void make_valid_column_names(List<Item> &item_list) static bool fill_defined_view_parts (THD *thd, TABLE_LIST *view) { + char key[MAX_DBKEY_LENGTH]; + uint key_length; LEX *lex= thd->lex; - bool not_used; TABLE_LIST decoy; memcpy (&decoy, view, sizeof (TABLE_LIST)); + key_length= create_table_def_key(thd, key, view, 0); - /* - 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. */ - my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW"); + if (tdc_open_view(thd, &decoy, decoy.alias, key, key_length, + thd->mem_root, OPEN_VIEW_NO_PARSE)) return TRUE; - } if (!lex->definer) { @@ -296,12 +264,16 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, 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, view->db_length)) || + if ((check_access(thd, CREATE_VIEW_ACL, view->db, + &view->grant.privilege, + &view->grant.m_internal, + 0, 0) || check_grant(thd, CREATE_VIEW_ACL, view, FALSE, 1, FALSE)) || (mode != VIEW_CREATE_NEW && - (check_access(thd, DROP_ACL, view->db, &view->grant.privilege, - 0, 0, is_schema_db(view->db, view->db_length)) || + (check_access(thd, DROP_ACL, view->db, + &view->grant.privilege, + &view->grant.m_internal, + 0, 0) || check_grant(thd, DROP_ACL, view, FALSE, 1, FALSE)))) goto err; @@ -351,7 +323,9 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, if (!tbl->table_in_first_from_clause) { if (check_access(thd, SELECT_ACL, tbl->db, - &tbl->grant.privilege, 0, 0, test(tbl->schema_table)) || + &tbl->grant.privilege, + &tbl->grant.m_internal, + 0, 0) || check_grant(thd, SELECT_ACL, tbl, FALSE, 1, FALSE)) goto err; } @@ -429,6 +403,37 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_ASSERT(!lex->proc_list.first && !lex->result && !lex->param_list.elements); + /* + We can't allow taking exclusive meta-data locks of unlocked view under + LOCK TABLES since this might lead to deadlock. Since at the moment we + can't really lock view with LOCK TABLES we simply prohibit creation/ + alteration of views under LOCK TABLES. + */ + + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + res= TRUE; + goto err; + } + + if ((res= create_view_precheck(thd, tables, view, mode))) + goto err; + + lex->link_first_table_back(view, link_to_local); + view->open_strategy= TABLE_LIST::OPEN_STUB; + view->lock_strategy= TABLE_LIST::EXCLUSIVE_MDL; + view->open_type= OT_BASE_ONLY; + + if (open_and_lock_tables(thd, lex->query_tables, TRUE, 0)) + { + view= lex->unlink_first_table(&link_to_local); + res= TRUE; + goto err; + } + + view= lex->unlink_first_table(&link_to_local); + if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view)) { res= TRUE; @@ -490,16 +495,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } } #endif - - if ((res= create_view_precheck(thd, tables, view, mode))) - goto err; - - if (open_and_lock_tables(thd, tables)) - { - res= TRUE; - goto err; - } - /* check that tables are not temporary and this VIEW do not used in query (it is possible with ALTERing VIEW). @@ -644,12 +639,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } #endif - if (wait_if_global_read_lock(thd, 0, 0)) + + if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE)) { res= TRUE; goto err; } - VOID(pthread_mutex_lock(&LOCK_open)); + + mysql_mutex_lock(&LOCK_open); res= mysql_register_view(thd, view, mode); if (mysql_bin_log.is_open()) @@ -692,14 +689,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, int errcode= query_error_code(thd, TRUE); if (thd->binlog_query(THD::STMT_QUERY_TYPE, - buff.ptr(), buff.length(), FALSE, FALSE, errcode)) + buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcode)) res= TRUE; } - VOID(pthread_mutex_unlock(&LOCK_open)); + mysql_mutex_unlock(&LOCK_open); if (mode != VIEW_CREATE_NEW) query_cache_invalidate3(thd, view, 0); - start_waiting_global_read_lock(thd); + thd->global_read_lock.start_waiting_global_read_lock(thd); if (res) goto err; @@ -848,7 +845,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, thd->variables.sql_mode|= sql_mode; } - DBUG_PRINT("info", ("View: %s", view_query.ptr())); + DBUG_PRINT("info", + ("View: %*.s", (int) view_query.length(), view_query.ptr())); /* fill structure */ view->source= thd->lex->create_view_select; @@ -1154,8 +1152,18 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, table->db, table->table_name); get_default_definer(thd, &table->definer); } + + /* + Initialize view definition context by character set names loaded from + the view definition file. Use UTF8 character set if view definition + file is of old version and does not contain the character set names. + */ + table->view_creation_ctx= View_creation_ctx::create(thd, table); + if (flags & OPEN_VIEW_NO_PARSE) { + if (arena) + thd->restore_active_arena(arena, &backup); DBUG_RETURN(FALSE); } @@ -1167,16 +1175,23 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, table->view_db.length= table->db_length; table->view_name.str= table->table_name; table->view_name.length= table->table_name_length; - - /*TODO: md5 test here and warning if it is differ */ - /* - Initialize view definition context by character set names loaded from - the view definition file. Use UTF8 character set if view definition - file is of old version and does not contain the character set names. + We don't invalidate a prepared statement when a view changes, + or when someone creates a temporary table. + Instead, the view is inlined into the body of the statement + upon the first execution. Below, make sure that on + re-execution of a prepared statement we don't prefer + a temporary table to the view, if the view name was shadowed + with a temporary table with the same name. + This assignment ensures that on re-execution open_table() will + not try to call find_temporary_table() for this TABLE_LIST, + but will invoke open_table_from_share(), which will + eventually call this function. */ + table->open_type= OT_BASE_ONLY; + + /*TODO: md5 test here and warning if it is differ */ - table->view_creation_ctx= View_creation_ctx::create(thd, table); /* TODO: TABLE mem root should be used here when VIEW will be stored in @@ -1290,7 +1305,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, tbl; tbl= (view_tables_tail= tbl)->next_global) { - tbl->skip_temporary= 1; + tbl->open_type= OT_BASE_ONLY; tbl->belong_to_view= top_view; tbl->referencing_view= table; tbl->prelocking_placeholder= table->prelocking_placeholder; @@ -1337,8 +1352,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, If the view's body needs row-based binlogging (e.g. the VIEW is created from SELECT UUID()), the top statement also needs it. */ - if (lex->is_stmt_unsafe()) - old_lex->set_stmt_unsafe(); + old_lex->set_stmt_unsafe_flags(lex->get_stmt_unsafe_flags()); + view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE && lex->can_be_merged()); @@ -1361,7 +1376,11 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, anyway. */ for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local) + { tbl->lock_type= table->lock_type; + tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ? + MDL_SHARED_WRITE : MDL_SHARED_READ); + } /* If the view is mergeable, we might want to INSERT/UPDATE/DELETE into tables of this view. Preserve the @@ -1609,7 +1628,22 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) bool something_wrong= FALSE; DBUG_ENTER("mysql_drop_view"); - VOID(pthread_mutex_lock(&LOCK_open)); + /* + We can't allow dropping of unlocked view under LOCK TABLES since this + might lead to deadlock. But since we can't really lock view with LOCK + TABLES we have to simply prohibit dropping of views. + */ + + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + DBUG_RETURN(TRUE); + } + + if (lock_table_names(thd, views)) + DBUG_RETURN(TRUE); + + mysql_mutex_lock(&LOCK_open); for (view= views; view; view= view->next_local) { TABLE_SHARE *share; @@ -1645,7 +1679,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) } continue; } - if (my_delete(path, MYF(MY_WME))) + if (mysql_file_delete(key_file_frm, path, MYF(MY_WME))) error= TRUE; some_views_deleted= TRUE; @@ -1657,11 +1691,9 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) if ((share= get_cached_table_share(view->db, view->table_name))) { DBUG_ASSERT(share->ref_count == 0); - pthread_mutex_lock(&share->mutex); share->ref_count++; share->version= 0; - pthread_mutex_unlock(&share->mutex); - release_table_share(share, RELEASE_WAIT_FOR_DROP); + release_table_share(share); } query_cache_invalidate3(thd, view, 0); sp_cache_invalidate(); @@ -1687,7 +1719,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) something_wrong= 1; } - VOID(pthread_mutex_unlock(&LOCK_open)); + mysql_mutex_unlock(&LOCK_open); if (something_wrong) { @@ -1720,10 +1752,11 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt) *dbt= DB_TYPE_UNKNOWN; - if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) + if ((file= mysql_file_open(key_file_frm, + path, O_RDONLY | O_SHARE, MYF(0))) < 0) DBUG_RETURN(FRMTYPE_ERROR); - error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP)); - my_close(file, MYF(MY_WME)); + error= mysql_file_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP)); + mysql_file_close(file, MYF(MY_WME)); if (error) DBUG_RETURN(FRMTYPE_ERROR); |