/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: * * Copyright (C) 2008 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once #include #include namespace drizzled { /** * A Table referenced in the FROM clause. * * These table references can be of several types that correspond to * different SQL elements. Below we list all types of TableLists with * the necessary conditions to determine when a TableList instance * belongs to a certain type. * * 1) table (TableList::view == NULL) * - base table * (TableList::derived == NULL) * - subquery - TableList::table is a temp table * (TableList::derived != NULL) * * @note * * for schema tables TableList::field_translation may be != NULL * * 2) Was VIEW * 3) nested table reference (TableList::nested_join != NULL) * - table sequence - e.g. (t1, t2, t3) * @todo how to distinguish from a JOIN? * - general JOIN * @todo how to distinguish from a table sequence? * - NATURAL JOIN * (TableList::natural_join != NULL) * - JOIN ... USING * (TableList::join_using_fields != NULL) * - semi-join */ class TableList { public: TableList(): next_local(NULL), next_global(NULL), prev_global(NULL), schema(NULL), alias(NULL), table_name(NULL), option(NULL), on_expr(NULL), table(NULL), prep_on_expr(NULL), cond_equal(NULL), natural_join(NULL), is_natural_join(false), is_join_columns_complete(false), straight(false), force_index(false), ignore_leaves(false), join_using_fields(NULL), join_columns(NULL), next_name_resolution_table(NULL), index_hints(NULL), derived_result(NULL), derived(NULL), schema_select_lex(NULL), select_lex(NULL), next_leaf(NULL), outer_join(0), dep_tables(0), on_expr_dep_tables(0), nested_join(NULL), embedding(NULL), join_list(NULL), db_type(NULL), internal_tmp_table(false), is_alias(false), is_fqtn(false), create(false) { } /** * List of tables local to a subquery (used by SQL_LIST). Considers * views as leaves (unlike 'next_leaf' below). Created at parse time * in Select_Lex::add_table_to_list() -> table_list.link_in_list(). */ TableList *next_local; /** link in a global list of all queries tables */ TableList *next_global; TableList **prev_global; private: const char* schema; public: const char *getSchemaName() const { return schema; } void setSchemaName(const char* v) { schema= v; } const char *alias; private: const char* table_name; public: const char *getTableName() const { return table_name; } void setTableName(const char* v) { table_name= v; } const char *option; ///< Used by cache index Item *on_expr; ///< Used with outer join Table *table; ///< opened table /** * The structure of ON expression presented in the member above * can be changed during certain optimizations. This member * contains a snapshot of AND-OR structure of the ON expression * made after permanent transformations of the parse tree, and is * used to restore ON clause before every reexecution of a prepared * statement or stored procedure. */ Item *prep_on_expr; COND_EQUAL *cond_equal; ///< Used with outer join /** * During parsing - left operand of NATURAL/USING join where 'this' is * the right operand. After parsing (this->natural_join == this) iff * 'this' represents a NATURAL or USING join operation. Thus after * parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ TableList *natural_join; /** * True if 'this' represents a nested join that is a NATURAL JOIN. * For one of the operands of 'this', the member 'natural_join' points * to the other operand of 'this'. */ bool is_natural_join; /** true if join_columns contains all columns of this table reference. */ bool is_join_columns_complete; bool straight; ///< optimize with prev table bool force_index; ///< prefer index over table scan bool ignore_leaves; ///< preload only non-leaf nodes /* is the table a cartesian join, assumption is yes unless "solved" */ bool isCartesian() const; /** Field names in a USING clause for JOIN ... USING. */ List *join_using_fields; /** * Explicitly store the result columns of either a NATURAL/USING join or * an operand of such a join. */ List *join_columns; /** * List of nodes in a nested join tree, that should be considered as * leaves with respect to name resolution. The leaves are: views, * top-most nodes representing NATURAL/USING joins, subqueries, and * base tables. All of these TableList instances contain a * materialized list of columns. The list is local to a subquery. */ TableList *next_name_resolution_table; /** Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ List *index_hints; /** * select_result for derived table to pass it from table creation to table * filling procedure */ select_union *derived_result; Select_Lex_Unit *derived; ///< Select_Lex_Unit of derived table */ Select_Lex *schema_select_lex; /** link to select_lex where this table was used */ Select_Lex *select_lex; /** * List of all base tables local to a subquery including all view * tables. Unlike 'next_local', this in this list views are *not* * leaves. Created in setup_tables() -> make_leaves_list(). */ TableList *next_leaf; thr_lock_type lock_type; uint32_t outer_join; ///< Which join type void set_underlying_merge(); bool setup_underlying(Session *session); /** * If you change placeholder(), please check the condition in * check_transactional_lock() too. */ bool placeholder(); /** * Print table as it should be in join list. * * @param str string where table should be printed */ void print(Session *session, String *str); /** * Sets insert_values buffer * * @param[in] memory pool for allocating * * @retval * false - OK * @retval * true - out of memory */ void set_insert_values(); /** * Find underlying base tables (TableList) which represent given * table_to_find (Table) * * @param[in] table to find * * @retval * NULL if table is not found * @retval * Pointer to found table reference */ TableList *find_underlying_table(Table *table); /** * Retrieve the first (left-most) leaf in a nested join tree with * respect to name resolution. * * @details * * Given that 'this' is a nested table reference, recursively walk * down the left-most children of 'this' until we reach a leaf * table reference with respect to name resolution. * * @retval * If 'this' is a nested table reference - the left-most child of * the tree rooted in 'this', * else return 'this' */ TableList *first_leaf_for_name_resolution(); /** * Retrieve the last (right-most) leaf in a nested join tree with * respect to name resolution. * * @details * * Given that 'this' is a nested table reference, recursively walk * down the right-most children of 'this' until we reach a leaf * table reference with respect to name resolution. * * @retval * If 'this' is a nested table reference - the right-most child of * the tree rooted in 'this', * else 'this' */ TableList *last_leaf_for_name_resolution(); /** * Test if this is a leaf with respect to name resolution. * * @details * * A table reference is a leaf with respect to name resolution if * it is either a leaf node in a nested join tree (table, view, * schema table, subquery), or an inner node that represents a * NATURAL/USING join, or a nested join with materialized join * columns. * * @retval * true if a leaf, false otherwise. */ bool is_leaf_for_name_resolution() const; inline TableList *top_table() { return this; } /** * Return subselect that contains the FROM list this table is taken from * * @retval * Subselect item for the subquery that contains the FROM list * this table is taken from if there is any * @retval * NULL otherwise */ Item_subselect *containing_subselect(); /** * Compiles the tagged hints list and fills up st_table::keys_in_use_for_query, * st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, * st_table::force_index and st_table::covering_keys. * * @param the Table to operate on. * * @details * * The parser collects the index hints for each table in a "tagged list" * (TableList::index_hints). Using the information in this tagged list * this function sets the members Table::keys_in_use_for_query, * Table::keys_in_use_for_group_by, Table::keys_in_use_for_order_by, * Table::force_index and Table::covering_keys. * * Current implementation of the runtime does not allow mixing FORCE INDEX * and USE INDEX, so this is checked here. Then the FORCE INDEX list * (if non-empty) is appended to the USE INDEX list and a flag is set. * * Multiple hints of the same kind are processed so that each clause * is applied to what is computed in the previous clause. * * For example: * USE INDEX (i1) USE INDEX (i2) * is equivalent to * USE INDEX (i1,i2) * and means "consider only i1 and i2". * * Similarly * USE INDEX () USE INDEX (i1) * is equivalent to * USE INDEX (i1) * and means "consider only the index i1" * * It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is * not an error. * * Different kind of hints (USE/FORCE/IGNORE) are processed in the following * order: * 1. All indexes in USE (or FORCE) INDEX are added to the mask. * 2. All IGNORE INDEX * e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all * as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1". * As an optimization if there is a covering index, and we have * IGNORE INDEX FOR GROUP/order_st, and this index is used for the JOIN part, * then we have to ignore the IGNORE INDEX FROM GROUP/order_st. * * @retval * false no errors found * @retval * true found and reported an error. */ bool process_index_hints(Table *table); friend std::ostream& operator<<(std::ostream& output, const TableList &list) { output << "TableList:("; output << list.getSchemaName(); output << ", "; output << list.getTableName(); output << ", "; output << list.alias; output << ", "; output << "is_natural_join:" << list.is_natural_join; output << ", "; output << "is_join_columns_complete:" << list.is_join_columns_complete; output << ", "; output << "straight:" << list.straight; output << ", "; output << "force_index" << list.force_index; output << ", "; output << "ignore_leaves:" << list.ignore_leaves; output << ", "; output << "create:" << list.create; output << ", "; output << "outer_join:" << list.outer_join; output << ", "; output << "nested_join:" << list.nested_join; output << ")"; return output; // for multiple << operators. } void setIsAlias(bool in_is_alias) { is_alias= in_is_alias; } void setIsFqtn(bool in_is_fqtn) { is_fqtn= in_is_fqtn; } void setCreate(bool in_create) { create= in_create; } void setInternalTmpTable(bool in_internal_tmp_table) { internal_tmp_table= in_internal_tmp_table; } void setDbType(plugin::StorageEngine *in_db_type) { db_type= in_db_type; } void setJoinList(List *in_join_list) { join_list= in_join_list; } void setEmbedding(TableList *in_embedding) { embedding= in_embedding; } void setNestedJoin(NestedJoin *in_nested_join) { nested_join= in_nested_join; } void setDepTables(table_map in_dep_tables) { dep_tables= in_dep_tables; } void setOnExprDepTables(table_map in_on_expr_dep_tables) { on_expr_dep_tables= in_on_expr_dep_tables; } bool getIsAlias() const { return is_alias; } bool getIsFqtn() const { return is_fqtn; } bool isCreate() const { return create; } bool getInternalTmpTable() const { return internal_tmp_table; } plugin::StorageEngine *getDbType() const { return db_type; } TableList *getEmbedding() const { return embedding; } List *getJoinList() const { return join_list; } NestedJoin *getNestedJoin() const { return nested_join; } table_map getDepTables() const { return dep_tables; } table_map getOnExprDepTables() const { return on_expr_dep_tables; } void unlock_table_name(); void unlock_table_names(TableList *last_table= NULL); private: table_map dep_tables; ///< tables the table depends on table_map on_expr_dep_tables; ///< tables on expression depends on NestedJoin *nested_join; ///< if the element is a nested join TableList *embedding; ///< nested join containing the table List *join_list; ///< join list the table belongs to plugin::StorageEngine *db_type; ///< table_type for handler bool internal_tmp_table; /** true if an alias for this table was specified in the SQL. */ bool is_alias; /** * true if the table is referred to in the statement using a fully * qualified name (.). */ bool is_fqtn; /** * This TableList object corresponds to the table to be created * so it is possible that it does not exist (used in CREATE TABLE * ... SELECT implementation). */ bool create; }; void close_thread_tables(Session *session); } /* namespace drizzled */