|
Query_term * | pushdown_limit_order_by (Query_term_set_op *parent=nullptr) |
| Called after contextualization to simplify query, c.f. More...
|
|
bool | validate_structure (const Query_term *parent, int depth=0) const |
| Return true if structure is too deep, i.e. More...
|
|
std::pair< bool, bool > | redundant_order_by (Query_block *block, int level) |
| Determine if we have a redundant ORDER BY in block. More...
|
|
virtual Query_term_type | term_type () const =0 |
| Get the node tree type. More...
|
|
virtual const char * | operator_string () const =0 |
| Get the node type description. More...
|
|
virtual | ~Query_term ()=default |
| Node destructor. More...
|
|
virtual size_t | child_count () const |
| Get the number of children this node has. More...
|
|
virtual void | label_children ()=0 |
| Set the correct value of Query_term::m_sibling_idx recursively for set operations. More...
|
|
Query_term_set_op * | parent () const |
| Getter for m_parent, q.v. More...
|
|
void | set_sibling_idx (uint idx) |
| Setter for m_sibling_idx , q.v. More...
|
|
uint | sibling_idx () |
| Getter for m_sibling_idx , q.v. More...
|
|
virtual void | cleanup (bool full) |
| Reset resources used. More...
|
|
virtual void | destroy_tree ()=0 |
| Destroy the query term tree structure. More...
|
|
virtual bool | open_result_tables (THD *thd, int level) |
| Open tmp tables for the tree of set operation query results, by recursing. More...
|
|
virtual void | debugPrint (int level, std::ostringstream &buf) const =0 |
| Print the tree rooted at this node to buf. More...
|
|
void | printPointers (std::ostringstream &buf) const |
| Print the pointer of this node and its parent to buf. More...
|
|
virtual Query_block * | query_block () const =0 |
| The query_block which holds the ORDER BY and LIMIT information for this set operation. More...
|
|
void | set_setop_query_result (Query_result *rs) |
| Setter for m_setop_query_result, q.v. More...
|
|
Query_result * | setop_query_result () |
| Getter for m_setop_query_result, q.v. More...
|
|
Query_result_union * | setop_query_result_union () |
| Getter for m_setop_query_result, q.v. Use only if we can down cast. More...
|
|
void | cleanup_query_result (bool full) |
| Cleanup m_setop_query_result, q.v. More...
|
|
void | set_owning_operand () |
| Setter for m_owning_operand, q.v. More...
|
|
bool | owning_operand () |
| Getter for m_owning_operand, q.v. More...
|
|
void | set_result_table (Table_ref *tl) |
| Setter for m_result_table, q.v. More...
|
|
Table_ref & | result_table () |
| Getter for m_result_table, q.v. More...
|
|
void | set_fields (mem_root_deque< Item * > *fields) |
|
mem_root_deque< Item * > * | fields () |
|
Query term tree structure.
There are five node types, cf. Query_term_type. Leaf nodes are Query_block objects. We have three kinds of n-ary set operation nodes corresponding to INTERSECT, UNION and EXCEPT. Finally, we have a "unary" node which essentially adds a ORDER BY/LIMIT over another node.
Query blocks serve a dual purpose: they represent the query specification and table constructors of the query. As such they are the leaf nodes of the query tree. But they also serve as a way to realize ORDER BY and LIMIT for non-leaf nodes, accessed via the function Query_term::query_block(). Therefore, every non-leaf node in the tree has a companion Query_block to hold ORDER BY and LIMIT information. For the leaf nodes, which are themselves query blocks, the query_block() function just returns a pointer to self, i.e. the leaf nodes handle ORDER BY and LIMIT themselves.
Example: ((SELECT * FROM t1 UNION SELECT * FROM t2 UNION ALL SELECT * FROM t3
ORDER BY a LIMIT 5) INTERSECT
(((SELECT * FROM t3 ORDER BY a LIMIT 4) ) EXCEPT SELECT * FROM t4)
ORDER BY a LIMIT 4) ORDER BY -a LIMIT 3;
->
m_query_term +------------------+ slave(s)
+--------------|-Query_expression |------------------+
| +------------------+ |
V post_ |
+-------------------+processing_ +----------------------+ |
| Query_term_unary |block() |Query_block | |
| |----------->|order by -(`a) limit 3| |
+-------------------+ +----------------------+ |
|m_children |
| +-----------------------+ +----------------------+ |
| |Query_term_intersect | |Query_block | |
+>|last distinct index: 1 |-->|order by `a` limit 4 | |
+-----------------------+ +----------------------+ |
|m_children |
| +-----------------------+ +----------------------+ |
| |Query_term_union | |Query_block | |
+->|last distinct index: 1 |-->|order by `a` limit 5 | |
| +-----------------------+ +----------------------+ |
| |m_children |
| | +------------+ SELECT * FROM t1 /
| +-->|Query_block | <---------------------------------+
| | +------------+ ----------------------------------+ next
| | \
| | +------------+ SELECT * FROM t2 /
| +-->|Query_block | <---------------------------------+
| | +------------+ ----------------------------------+ next
| | \
| | +------------+ SELECT * FROM t3 /
| +-->|Query_block | <---------------------------------+
| +------------+ ----------------------------------+ next
| \
| +-----------------------+ +------------+ |
| |Query_term_except |->|Query_block | |
+->|last distinct index: 1 | +------------+ |
+-----------------------+ |
|m_children |
| +----------------------+ |
| |Query_block | SELECT * FROM t3 /
+-->|order by `a` limit 4 | <------------------------+
| +----------------------+ -------------------------+ next
| \
| +------------+ SELECT * FROM t4 |
+-->|Query_block | <------------------------------------+
+------------+
Note that all leaf query blocks representing the query specifications are linked under Query_expression via their next pointers. The nesting is achieved by the arrows on the left side of the figure, via the nodes' m_children members. The four classes Query_term_unary and Query_term_{union, intersect, except} are modelled via the base class Query_term_set_op which contains a m_children member. Each of these also contain a Query_block which will handle its order by and/or limit clauses. These are similar to the old so-called "fake_query_block" (which is now gone), and are not linked in with "next" pointers.
The is also a back pointer from the children nodes to the parent Query_term object (not shown).
In the simple case of a single query specification (or table value constructor or explicit table), there is no super-structure over the Query_block linked from the Query_expression, i.e. Query_expression's m_query_term member is just a Query_block.
The query blocks (QT_QUERY_BLOCK nodes) corresponding to the query specification (or table value constructors) are prepared and optimized by running over them from the Query_expression via the slave/next pointers as before. There are separate methods which handle prepare and optimization for non-leaves, i.e. nodes of types QT_UNARY, QT_INTERSECT, QT_EXCEPT and QT_UNION.
We also define an iterator class (Query_terms) for iterating over all the nodes in the tree, see also Query_expression::query_terms() for its use. When possible, we access all nodes using iterators.
The built structure can be traced with the debug trace keyword "ast", e.g. as SET SESSION debug = 'd,ast:O,/tmp/mysqld.trace';