diff options
-rw-r--r-- | mysql-test/include/grant_cache.inc | 2 | ||||
-rw-r--r-- | mysql-test/r/grant2.result | 2 | ||||
-rw-r--r-- | mysql-test/r/grant_cache_no_prot.result | 2 | ||||
-rw-r--r-- | mysql-test/r/grant_cache_ps_prot.result | 2 | ||||
-rw-r--r-- | mysql-test/r/view_grant.result | 32 | ||||
-rw-r--r-- | mysql-test/t/grant2.test | 2 | ||||
-rw-r--r-- | mysql-test/t/view_grant.test | 68 | ||||
-rw-r--r-- | sql/item.cc | 12 | ||||
-rw-r--r-- | sql/sql_acl.cc | 54 | ||||
-rw-r--r-- | sql/sql_base.cc | 39 | ||||
-rw-r--r-- | sql/sql_cache.cc | 2 | ||||
-rw-r--r-- | sql/sql_derived.cc | 76 | ||||
-rw-r--r-- | sql/sql_parse.cc | 4 | ||||
-rw-r--r-- | sql/table.cc | 31 | ||||
-rw-r--r-- | sql/table.h | 117 |
15 files changed, 362 insertions, 83 deletions
diff --git a/mysql-test/include/grant_cache.inc b/mysql-test/include/grant_cache.inc index dd65d1ed726..501e115f0ee 100644 --- a/mysql-test/include/grant_cache.inc +++ b/mysql-test/include/grant_cache.inc @@ -136,7 +136,7 @@ connect (user3,localhost,mysqltest_3,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); connection user3; select "user3"; --replace_result 127.0.0.1 localhost ---error ER_COLUMNACCESS_DENIED_ERROR +--error ER_TABLEACCESS_DENIED_ERROR select * from t1; select a from t1; --replace_result 127.0.0.1 localhost diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index b94de265d0c..03c4ea042f6 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -434,7 +434,7 @@ USE db1; SELECT c FROM t2; ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' SELECT * FROM t2; -ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' +ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for table 't2' SELECT * FROM t1 JOIN t2 USING (b); ERROR 42000: SELECT command denied to user 'mysqltest1'@'localhost' for column 'c' in table 't2' DROP TABLE db1.t1, db1.t2; diff --git a/mysql-test/r/grant_cache_no_prot.result b/mysql-test/r/grant_cache_no_prot.result index 02360c4c325..cb9acaf540d 100644 --- a/mysql-test/r/grant_cache_no_prot.result +++ b/mysql-test/r/grant_cache_no_prot.result @@ -155,7 +155,7 @@ select "user3"; user3 user3 select * from t1; -ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'b' in table 't1' +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1' select a from t1; a 1 diff --git a/mysql-test/r/grant_cache_ps_prot.result b/mysql-test/r/grant_cache_ps_prot.result index 1e2cd1baa3a..cf1450f3b75 100644 --- a/mysql-test/r/grant_cache_ps_prot.result +++ b/mysql-test/r/grant_cache_ps_prot.result @@ -155,7 +155,7 @@ select "user3"; user3 user3 select * from t1; -ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'b' in table 't1' +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1' select a from t1; a 1 diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 3585635d0f9..9a4fa95912d 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -957,3 +957,35 @@ Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function DROP VIEW v1; DROP TABLE t1; End of 5.1 tests. +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +USE mysqltest1; +CREATE TABLE t1 ( a INT, b INT ); +CREATE TABLE t2 ( a INT, b INT ); +CREATE VIEW v1 AS SELECT a, b FROM t1; +GRANT SELECT( a ) ON v1 TO mysqluser1@localhost; +GRANT UPDATE( b ) ON t2 TO mysqluser1@localhost; +SELECT * FROM mysqltest1.v1; +ERROR 42000: SELECT command denied to user 'mysqluser1'@'localhost' for table 'v1' +CREATE VIEW v1 AS SELECT * FROM mysqltest1.t2; +ERROR 42000: ANY command denied to user 'mysqluser1'@'localhost' for table 't2' +DROP TABLE t1, t2; +DROP VIEW v1; +DROP DATABASE mysqltest1; +DROP USER mysqluser1@localhost; +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +USE mysqltest1; +CREATE VIEW v1 AS SELECT * FROM information_schema.tables LIMIT 1; +CREATE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT 1 AS A; +GRANT SELECT ON mysqltest1.* to mysqluser1@localhost; +PREPARE stmt_v1 FROM "SELECT * FROM mysqltest1.v1"; +PREPARE stmt_v2 FROM "SELECT * FROM mysqltest1.v2"; +REVOKE SELECT ON mysqltest1.* FROM mysqluser1@localhost; +EXECUTE stmt_v1; +ERROR 42000: SELECT command denied to user 'mysqluser1'@'localhost' for table 'v1' +EXECUTE stmt_v2; +ERROR 42000: SELECT command denied to user 'mysqluser1'@'localhost' for table 'v2' +DROP VIEW v1, v2; +DROP DATABASE mysqltest1; +DROP USER mysqluser1@localhost; diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 0f0c92e82eb..d91592f6bb6 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -605,7 +605,7 @@ connection conn1; USE db1; --error ER_COLUMNACCESS_DENIED_ERROR SELECT c FROM t2; ---error ER_COLUMNACCESS_DENIED_ERROR +--error ER_TABLEACCESS_DENIED_ERROR SELECT * FROM t2; --error ER_COLUMNACCESS_DENIED_ERROR SELECT * FROM t1 JOIN t2 USING (b); diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index cbc66300173..afef5c5bc7b 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1219,3 +1219,71 @@ DROP VIEW v1; DROP TABLE t1; --echo End of 5.1 tests. + +# +# Bug#36086: SELECT * from views don't check column grants +# +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; + +USE mysqltest1; + +CREATE TABLE t1 ( a INT, b INT ); +CREATE TABLE t2 ( a INT, b INT ); + +CREATE VIEW v1 AS SELECT a, b FROM t1; + +GRANT SELECT( a ) ON v1 TO mysqluser1@localhost; +GRANT UPDATE( b ) ON t2 TO mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1, , test) + +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM mysqltest1.v1; + +--error ER_TABLEACCESS_DENIED_ERROR +CREATE VIEW v1 AS SELECT * FROM mysqltest1.t2; + +--disconnect connection1 + +--connection default + +DROP TABLE t1, t2; +DROP VIEW v1; +DROP DATABASE mysqltest1; +DROP USER mysqluser1@localhost; + +# +# Bug#35600: Security breach via view, I_S table and prepared +# statement/stored procedure +# +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; + +USE mysqltest1; + +CREATE VIEW v1 AS SELECT * FROM information_schema.tables LIMIT 1; +CREATE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT 1 AS A; + +--connection default +GRANT SELECT ON mysqltest1.* to mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1, , test) +PREPARE stmt_v1 FROM "SELECT * FROM mysqltest1.v1"; +PREPARE stmt_v2 FROM "SELECT * FROM mysqltest1.v2"; + +--connection default +REVOKE SELECT ON mysqltest1.* FROM mysqluser1@localhost; + +--connection connection1 + +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt_v1; +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt_v2; + +--disconnect connection1 +--connection default +DROP VIEW v1, v2; +DROP DATABASE mysqltest1; +DROP USER mysqluser1@localhost; diff --git a/sql/item.cc b/sql/item.cc index 3f41c7211c8..8e278d04064 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4120,16 +4120,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (any_privileges) { char *db, *tab; - if (cached_table->view) - { - db= cached_table->view_db.str; - tab= cached_table->view_name.str; - } - else - { - db= cached_table->db; - tab= cached_table->table_name; - } + db= cached_table->get_db_name(); + tab= cached_table->get_table_name(); if (!(have_privileges= (get_column_grant(thd, &field->table->grant, db, tab, field_name) & VIEW_ANY_ACL))) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 226d41e0fb5..0043ef09229 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3092,12 +3092,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, continue; // Add next user } - db_name= (table_list->view_db.length ? - table_list->view_db.str : - table_list->db); - table_name= (table_list->view_name.length ? - table_list->view_name.str : - table_list->table_name); + db_name= table_list->get_db_name(); + table_name= table_list->get_table_name(); /* Find/create cached table grant */ grant_table= table_hash_search(Str->host.str, NullS, db_name, @@ -3907,8 +3903,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, if (!want_access) continue; // ok - if (!(~table->grant.privilege & want_access) || - table->derived || table->schema_table) + if (!(~table->grant.privilege & want_access) || + table->is_anonymous_derived_table() || table->schema_table) { /* It is subquery in the FROM clause. VIEW set table->derived after @@ -3926,8 +3922,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, continue; } if (!(grant_table= table_hash_search(sctx->host, sctx->ip, - table->db, sctx->priv_user, - table->table_name,0))) + table->get_db_name(), sctx->priv_user, + table->get_table_name(), FALSE))) { want_access &= ~table->grant.privilege; goto err; // No grants @@ -3963,7 +3959,7 @@ err: command, sctx->priv_user, sctx->host_or_ip, - table ? table->table_name : "unknown"); + table ? table->get_table_name() : "unknown"); } DBUG_RETURN(1); } @@ -4118,7 +4114,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, @retval 1 Falure @details This function walks over the columns of a table reference The columns may originate from different tables, depending on the kind of - table reference, e.g. join. + table reference, e.g. join, view. For each table it will retrieve the grant information and will use it to check the required access privileges for the fields requested from it. */ @@ -4133,6 +4129,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_INFO *grant; /* Initialized only to make gcc happy */ GRANT_TABLE *grant_table= NULL; + /* + Flag that gets set if privilege checking has to be performed on column + level. + */ + bool using_column_privileges= FALSE; rw_rdlock(&LOCK_grant); @@ -4140,10 +4141,10 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, { const char *field_name= fields->name(); - if (table_name != fields->table_name()) + if (table_name != fields->get_table_name()) { - table_name= fields->table_name(); - db_name= fields->db_name(); + table_name= fields->get_table_name(); + db_name= fields->get_db_name(); grant= fields->grant(); /* get a fresh one for each table */ want_access= want_access_arg & ~grant->privilege; @@ -4169,6 +4170,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_COLUMN *grant_column= column_hash_search(grant_table, field_name, (uint) strlen(field_name)); + if (grant_column) + using_column_privileges= TRUE; if (!grant_column || (~grant_column->rights & want_access)) goto err; } @@ -4181,12 +4184,21 @@ err: char command[128]; get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - command, - sctx->priv_user, - sctx->host_or_ip, - fields->name(), - table_name); + /* + Do not give an error message listing a column name unless the user has + privilege to see all columns. + */ + if (using_column_privileges) + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, sctx->priv_user, + sctx->host_or_ip, table_name); + else + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), + command, + sctx->priv_user, + sctx->host_or_ip, + fields->name(), + table_name); return 1; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 36b9d53ce85..39030462f0b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7620,9 +7620,34 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, continue; #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* Ensure that we have access rights to all fields to be inserted. */ - if (!((table && (table->grant.privilege & SELECT_ACL) || - tables->view && (tables->grant.privilege & SELECT_ACL))) && + /* + Ensure that we have access rights to all fields to be inserted. Under + some circumstances, this check may be skipped. + + - If any_privileges is true, skip the check. + + - If the SELECT privilege has been found as fulfilled already for both + the TABLE and TABLE_LIST objects (and both of these exist, of + course), the check is skipped. + + - If the SELECT privilege has been found fulfilled for the TABLE object + and the TABLE_LIST represents a derived table other than a view (see + below), the check is skipped. + + - If the TABLE_LIST object represents a view, we may skip checking if + the SELECT privilege has been found fulfilled for it, regardless of + the TABLE object. + + - If there is no TABLE object, the test is skipped if either + * the TABLE_LIST does not represent a view, or + * the SELECT privilege has been found fulfilled. + + A TABLE_LIST that is not a view may be a subquery, an + information_schema table, or a nested table reference. See the comment + for TABLE_LIST. + */ + if (!(table && !tables->view && (table->grant.privilege & SELECT_ACL) || + tables->view && (tables->grant.privilege & SELECT_ACL)) && !any_privileges) { field_iterator.set(tables); @@ -7676,19 +7701,19 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tables->is_natural_join); DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *fld= (Item_field*) item; - const char *field_table_name= field_iterator.table_name(); + const char *field_table_name= field_iterator.get_table_name(); if (!tables->schema_table && !(fld->have_privileges= (get_column_grant(thd, field_iterator.grant(), - field_iterator.db_name(), + field_iterator.get_db_name(), field_table_name, fld->field_name) & VIEW_ANY_ACL))) { - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - fld->field_name, field_table_name); + field_table_name); DBUG_RETURN(TRUE); } } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 375ffc882b4..f5566acbc6f 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2633,7 +2633,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, tables_used; tables_used= tables_used->next_global, n++, block_table++) { - if (tables_used->derived && !tables_used->view) + if (tables_used->is_anonymous_derived_table()) { DBUG_PRINT("qcache", ("derived table skipped")); n--; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 10b42e11b26..41be98621a6 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -73,29 +73,59 @@ out: } -/* - Create temporary table structure (but do not fill it) - - SYNOPSIS - mysql_derived_prepare() - thd Thread handle - lex LEX for this thread - orig_table_list TABLE_LIST for the upper SELECT - - IMPLEMENTATION - Derived table is resolved with temporary table. - - After table creation, the above TABLE_LIST is updated with a new table. - - This function is called before any command containing derived table - is executed. - - Derived tables is stored in thd->derived_tables and freed in - close_thread_tables() - - RETURN - FALSE OK - TRUE Error +/** + @brief Create temporary table structure (but do not fill it). + + @param thd Thread handle + @param lex LEX for this thread + @param orig_table_list TABLE_LIST for the upper SELECT + + @details + + This function is called before any command containing derived tables is + executed. Currently the function is used for derived tables, i.e. + + - Anonymous derived tables, or + - Named derived tables (aka views) with the @c TEMPTABLE algorithm. + + The table reference, contained in @c orig_table_list, is updated with the + fields of a new temporary table. + + Derived tables are stored in @c thd->derived_tables and closed by + close_thread_tables(). + + This function is part of the procedure that starts in + open_and_lock_tables(), a procedure that - among other things - introduces + new table and table reference objects (to represent derived tables) that + don't exist in the privilege database. This means that normal privilege + checking cannot handle them. Hence this function does some extra tricks in + order to bypass normal privilege checking, by exploiting the fact that the + current state of privilege verification is attached as GRANT_INFO structures + on the relevant TABLE and TABLE_REF objects. + + For table references, the current state of accrued access is stored inside + TABLE_LIST::grant. Hence this function must update the state of fulfilled + privileges for the new TABLE_LIST, an operation which is normally performed + exclusively by the table and database access checking functions, + check_access() and check_grant(), respectively. This modification is done + for both views and anonymous derived tables: The @c SELECT privilege is set + as fulfilled by the user. However, if a view is referenced and the table + reference is queried against directly (see TABLE_LIST::referencing_view), + the state of privilege checking (GRANT_INFO struct) is copied as-is to the + temporary table. + + This function implements a signature called "derived table processor", and + is passed as a function pointer to mysql_handle_derived(). + + @note This function sets @c SELECT_ACL for @c TEMPTABLE views as well as + anonymous derived tables, but this is ok since later access checking will + distinguish between them. + + @see mysql_handle_derived(), mysql_derived_filling(), GRANT_INFO + + @return + false OK + true Error */ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index eb643184e1f..9bfa21b5e4b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4872,6 +4872,8 @@ bool check_single_table_access(THD *thd, ulong privilege, /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && + !(all_tables->view && + all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) && check_grant(thd, privilege, all_tables, 0, 1, no_errors)) goto deny; @@ -5184,7 +5186,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, continue; } - if (tables->derived || + if (tables->is_anonymous_derived_table() || (tables->table && (int)tables->table->s->tmp_table)) continue; thd->security_ctx= sctx; diff --git a/sql/table.cc b/sql/table.cc index 58cbde74822..40264a7cbb3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2993,16 +2993,27 @@ void TABLE_LIST::calc_md5(char *buffer) } -/* - set underlying TABLE for table place holder of VIEW +/** + @brief Set underlying table for table place holder of view. - DESCRIPTION - Replace all views that only uses one table with the table itself. - This allows us to treat the view as a simple table and even update - it (it is a kind of optimisation) + @details - SYNOPSIS - TABLE_LIST::set_underlying_merge() + Replace all views that only use one table with the table itself. This + allows us to treat the view as a simple table and even update it (it is a + kind of optimization). + + @note + + This optimization is potentially dangerous as it makes views + masquerade as base tables: Views don't have the pointer TABLE_LIST::table + set to non-@c NULL. + + We may have the case where a view accesses tables not normally accessible + in the current Security_context (only in the definer's + Security_context). According to the table's GRANT_INFO (TABLE::grant), + access is fulfilled, but this is implicitly meant in the definer's security + context. Hence we must never look at only a TABLE's GRANT_INFO without + looking at the one of the referring TABLE_LIST. */ void TABLE_LIST::set_underlying_merge() @@ -4082,7 +4093,7 @@ void Field_iterator_table_ref::next() } -const char *Field_iterator_table_ref::table_name() +const char *Field_iterator_table_ref::get_table_name() { if (table_ref->view) return table_ref->view_name.str; @@ -4095,7 +4106,7 @@ const char *Field_iterator_table_ref::table_name() } -const char *Field_iterator_table_ref::db_name() +const char *Field_iterator_table_ref::get_db_name() { if (table_ref->view) return table_ref->view_db.str; diff --git a/sql/table.h b/sql/table.h index da0e089794f..d21a9eefae8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -66,13 +66,63 @@ typedef struct st_order { table_map used, depend_map; } ORDER; +/** + @brief The current state of the privilege checking process for the current + user, SQL statement and SQL object. + + @details The privilege checking process is divided into phases depending on + the level of the privilege to be checked and the type of object to be + accessed. Due to the mentioned scattering of privilege checking + functionality, it is necessary to keep track of the state of the + process. This information is stored in privilege, want_privilege, and + orig_want_privilege. + + A GRANT_INFO also serves as a cache of the privilege hash tables. Relevant + members are grant_table and version. + */ typedef struct st_grant_info { + /** + @brief A copy of the privilege information regarding the current host, + database, object and user. + + @details The version of this copy is found in GRANT_INFO::version. + */ GRANT_TABLE *grant_table; + /** + @brief Used for cache invalidation when caching privilege information. + + @details The privilege information is stored on disk, with dedicated + caches residing in memory: table-level and column-level privileges, + respectively, have their own dedicated caches. + + The GRANT_INFO works as a level 1 cache with this member updated to the + current value of the global variable @c grant_version (@c static variable + in sql_acl.cc). It is updated Whenever the GRANT_INFO is refreshed from + the level 2 cache. The level 2 cache is the @c column_priv_hash structure + (@c static variable in sql_acl.cc) + + @see grant_version + */ uint version; + /** + @brief The set of privileges that the current user has fulfilled for a + certain host, database, and object. + + @details This field is continually updated throughout the access checking + process. In each step the "wanted privilege" is checked against the + fulfilled privileges. When/if the intersection of these sets is empty, + access is granted. + + The set is implemented as a bitmap, with the bits defined in sql_acl.h. + */ ulong privilege; + /** + @brief the set of privileges that the current user needs to fulfil in + order to carry out the requested operation. + */ ulong want_privilege; - /* + /** Stores the requested access acl of top level tables list. Is used to check access rights to the underlying tables of a view. */ @@ -1104,6 +1154,27 @@ struct TABLE_LIST can see this lists can't be merged) */ TABLE_LIST *correspondent_table; + /** + @brief Normally, this field is non-null for anonymous derived tables only. + + @details This field is set to non-null for + + - Anonymous derived tables, In this case it points to the SELECT_LEX_UNIT + representing the derived table. E.g. for a query + + @verbatim SELECT * FROM (SELECT a FROM t1) b @endverbatim + + For the @c TABLE_LIST representing the derived table @c b, @c derived + points to the SELECT_LEX_UNIT representing the result of the query within + parenteses. + + - Views. This is set for views with @verbatim ALGORITHM = TEMPTABLE + @endverbatim by mysql_make_view(). + + @note Inside views, a subquery in the @c FROM clause is not allowed. + @note Do not use this field to separate views/base tables/anonymous + derived tables. Use TABLE_LIST::is_anonymous_derived_table(). + */ st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; @@ -1169,7 +1240,15 @@ struct TABLE_LIST ulonglong file_version; /* version of file's field set */ ulonglong updatable_view; /* VIEW can be updated */ ulonglong revision; /* revision control number */ - ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ + /** + @brief The declared algorithm, if this is a view. + @details One of + - VIEW_ALGORITHM_UNDEFINED + - VIEW_ALGORITHM_TMPTABLE + - VIEW_ALGORITHM_MERGE + @to do Replace with an enum + */ + ulonglong algorithm; ulonglong view_suid; /* view is suid (TRUE dy default) */ ulonglong with_check; /* WITH CHECK OPTION */ /* @@ -1177,7 +1256,15 @@ struct TABLE_LIST algorithm) */ uint8 effective_with_check; - uint8 effective_algorithm; /* which algorithm was really used */ + /** + @brief The view algorithm that is actually used, if this is a view. + @details One of + - VIEW_ALGORITHM_UNDEFINED + - VIEW_ALGORITHM_TMPTABLE + - VIEW_ALGORITHM_MERGE + @to do Replace with an enum + */ + uint8 effective_algorithm; GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; @@ -1362,6 +1449,26 @@ struct TABLE_LIST m_table_ref_version= s->get_table_ref_version(); } + /** + @brief True if this TABLE_LIST represents an anonymous derived table, + i.e. the result of a subquery. + */ + bool is_anonymous_derived_table() const { return derived && !view; } + + /** + @brief Returns the name of the database that the referenced table belongs + to. + */ + char *get_db_name() { return view != NULL ? view_db.str : db; } + + /** + @brief Returns the name of the table that this TABLE_LIST represents. + + @details The unqualified table name or view name for a table or view, + respectively. + */ + char *get_table_name() { return view != NULL ? view_name.str : table_name; } + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); @@ -1491,8 +1598,8 @@ public: bool end_of_fields() { return (table_ref == last_leaf && field_it->end_of_fields()); } const char *name() { return field_it->name(); } - const char *table_name(); - const char *db_name(); + const char *get_table_name(); + const char *get_db_name(); GRANT_INFO *grant(); Item *create_item(THD *thd) { return field_it->create_item(thd); } Field *field() { return field_it->field(); } |