SELECT * FROM t1 UNION SELECT * FROM t2; unit | V next select t1 --------> select t2
SELECT * FROM t1 where c1 in (select * from t11 union select * from t12); unit | V select t1 | V unit1.1 | V next select t11 ---------> select t12
SELECT * FROM t1 WHERE c1 in (SELECT * FROM t11) and c2 in (SELECT * FROM t12);
unit1 | V select t1 | V next unit1.1 ------> unit1.2 | | V V select t11 select t12
At last, i give a sample in sql_lex.h.
select * from table1 where table1.field IN (select * from table1_1_1 union select * from table1_1_2) union select * from table2 where table2.field=(select (select f1 from table2_1_1_1_1 where table2_1_1_1_1.f2=table2_1_1.f3) from table2_1_1 where table2_1_1.f1=table2.f2) union select * from table3;
unit | V select table1------------> select table2 ------------>select table3 | | V |__________ unit1 | | | V | select table 1_1_1--->select table 1_1_2 V unit2 | V select table2_1_1 | V unit2.1 | V select table2_1_1_1_1
class SELECT_LEX_UNIT { /** Intrusive double-linked list of all query expressions immediately contained within the same query block. */ SELECT_LEX_UNIT *next; SELECT_LEX_UNIT **prev;
/** The query block wherein this query expression is contained, NULL if the query block is the outer-most one. */ SELECT_LEX *master; /// The first query block in this query expression. SELECT_LEX *slave; /// @return the query block this query expression belongs to as subquery SELECT_LEX *outer_select() const { return master; } /// @return the first query block inside this query expression SELECT_LEX *first_select() const { return slave; }
/** Helper query block for query expression with UNION or multi-level ORDER BY/LIMIT / SELECT_LEX fake_select_lex; / SELECT_LEX that stores LIMIT and OFFSET for UNION ALL when no fake_select_lex is used. / SELECT_LEX saved_fake_select_lex; / Points to last query block which has UNION DISTINCT on its left. In a list of UNIONed blocks, UNION is left-associative; so UNION DISTINCT eliminates duplicates in all blocks up to the first one on its right included. Which is why we only need to remember that query block. */ SELECT_LEX *union_distinct;
/** First query block (in this UNION) which references the CTE. NULL if not the query expression of a recursive CTE. */ SELECT_LEX *first_recursive;
… }
SELECT_LEX{ /** Intrusive double-linked list of all query blocks within the same query expression. */ SELECT_LEX *next; SELECT_LEX **prev;
/// The query expression containing this query block. SELECT_LEX_UNIT *master; /// The first query expression contained within this query block. SELECT_LEX_UNIT *slave;
/// Intrusive double-linked global list of query blocks. SELECT_LEX *link_next; SELECT_LEX link_prev; // 用于link LEX->all_selects_list / For plan clone, link each other between original SELECT_LEX and its clone */ SELECT_LEX *m_clone_source;
LEX { SELECT_LEX_UNIT *unit; ///< Outer-most query expression /// @todo: select_lex can be replaced with unit->first-select() SELECT_LEX *select_lex; ///< First query block SELECT_LEX *all_selects_list; ///< List of all query blocks }
struct LEX : public Query_tables_list, public im::Query_blocks_list {
SELECT_LEX_UNIT *unit; ///< Outer-most query expression /// @todo: select_lex can be replaced with unit->first-select() SELECT_LEX *select_lex; ///< First query block SELECT_LEX *all_selects_list; ///< List of all query blocks private: /* current SELECT_LEX in parsing */ SELECT_LEX *m_current_select;
}
class Query_blocks_list { public: SELECT_LEX *all_query_blocks; SELECT_LEX **all_query_blocks_last; }
class Query_tables_list { /** SQL command for this statement. Part of this class since the process of opening and locking tables for the statement needs this information to determine correct type of lock for some of the tables. */ enum_sql_command sql_command; /* Global list of all tables used by this statement */ TABLE_LIST *query_tables; /* Pointer to next_global member of last element in the previous list. */ TABLE_LIST **query_tables_last; /* If non-0 then indicates that query requires prelocking and points to next_global member of last own element in query table list (i.e. last table which was not added to it as part of preparation to prelocking). 0 - indicates that this query does not need prelocking. */ TABLE_LIST **query_tables_own_last; }