MySQL 源码解读 -- 基础结构之Lex

SELECT_LEX & SELECT_LEX_UNIT 关系

select_lex_unit 表示一个expression, 在union的情况下可以包含多个select_lex
但在subquery的情况下, 一个新的subquery 会引入一个新的SELECT_LEX_UNIT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
SELECT * FROM t1;

unit
|
V
select t1



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

lex & select_lex & select_lex_unit 关系

select_lex->parent_lex = lex;
lex->select_lex = select_lex;
lex->unit = select_lex->master;
lex->m_current_select = lex->select_lex;

SELECT_LEX_UNIT->master = outer_SELECT_LEX;
SELECT_LEX_UNIT->slave = select_lex;
SELECT_LEX_UNIT->next = out_SELECT_LEX->slave; // 就是将SELECT_LEX_UNIT 组成一个链表
SELECT_LEX_UNIT->prev = &out_SELECT_LEX->slave;

SELECT_LEX->master = out_SLECT_LEX_UNIT;
out_SLECT_LEX_UNIT->slave = SELECT_LEX;
SELECT_LEX->next = out_SELECT_LEX_UNIT->next;
SELECT_LEX->prev = &out_SELECT_LEX_UNIT->slave;
SELECT_LEX->link_next = LEX->all_selects_list; //在lex 下全部串起来
SELECT_LEX->link_prev = &LEX->all_slects_list;
LEX->all_slects_list = 指向第一个SELECT_LEX

SELECT_LEX->prev_query_block = LEX->all_query_blocks_last; //他们指向第一个SELECT_LEX
LEX->all_query_blocks_last = SELECT_LEX->next_query_block;

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;

SELECT_LEX *next_query_block{nullptr}; // 链表 指向LEX->all_query_blocks_last
SELECT_LEX **prev_query_block{nullptr};

}

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
}

LEX

推荐参考 https://dev.mysql.com/doc/dev/mysql-server/8.0.20/structLEX.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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;
}

SELECT_LEX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ptype select_lex->context                
type = struct Name_resolution_context {
Name_resolution_context *outer_context;
Name_resolution_context *next_context;
TABLE_LIST *table_list;
TABLE_LIST *first_name_resolution_table;
TABLE_LIST *last_name_resolution_table;
SELECT_LEX *select_lex;
bool view_error_handler;
TABLE_LIST *view_error_handler_arg;
bool resolve_in_select_list;
Security_context *security_ctx;
public:
Name_resolution_context(void);
void init(void);
void resolve_in_table_list_only(TABLE_LIST *);
}

SELECT_LEX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class SELECT_LEX  :
{
private:
SELECT_LEX *next;
SELECT_LEX **prev;
SELECT_LEX_UNIT *master;
SELECT_LEX_UNIT *slave;
SELECT_LEX *link_next;
SELECT_LEX **link_prev;
Query_result *m_query_result;
ulonglong m_base_options;
ulonglong m_active_options;
public:
uint8 uncacheable;
bool skip_local_transforms;
sub_select_type linkage;
bool no_table_names_allowed;
Name_resolution_context context;
Name_resolution_context *first_context;
SELECT_LEX::Resolve_place resolve_place;
TABLE_LIST *resolve_nest;
bool semijoin_disallowed;
char *db;
private:
Item *m_where_cond;
Item *m_having_cond;
public:
Item::cond_result cond_value;
Item::cond_result having_value;
LEX *parent_lex;
olap_type olap;
SQL_I_List<TABLE_LIST> table_list;
SQL_I_List<ORDER> group_list;
Group_list_ptrs *group_list_ptrs;
List<Window> m_windows;
List<Item> item_list;
bool is_item_list_lookup;
int hidden_group_field_count;
List<Item> &fields_list;
List<Item> all_fields;
List<Item> all_inner_ref_fields;
List<Item_func_match> *ftfunc_list;
List<Item_func_match> ftfunc_list_alloc;
JOIN *join;
List<TABLE_LIST> top_join_list;
List<TABLE_LIST> *join_list;
TABLE_LIST *embedding;
List<TABLE_LIST> sj_nests;
TABLE_LIST *leaf_tables;
uint leaf_table_count;
uint derived_table_count;
uint table_func_count;
uint materialized_derived_table_count;
bool has_sj_nests;
uint partitioned_table_count;
SQL_I_List<ORDER> order_list;
Group_list_ptrs *order_list_ptrs;
Item *select_limit;
Item *offset_limit;
Ref_item_array base_ref_items;
uint select_n_having_items;
uint cond_count;
uint between_count;
uint max_equal_elems;
uint select_n_where_fields;
enum_parsing_context parsing_place;
uint in_sum_expr;
bool with_sum_func;
uint n_sum_items;
uint n_child_sum_items;
uint select_number;
int nest_level;
Item_sum *inner_sum_func_list;
uint with_wild;
bool braces;
bool having_fix_field;
bool group_fix_field;
List<Item_outer_ref> inner_refs_list;
bool explicit_limit;
bool subquery_in_having;
bool first_execution;
bool sj_pullout_done;
bool exclude_from_table_unique_test;
bool allow_merge_derived;
TABLE_LIST *recursive_reference;
SELECT_LEX_UNIT *recursive_dummy_unit;
table_map select_list_tables;
table_map outer_join;
Opt_hints_qb *opt_hints_qb;

TABLE_LIST *end_lateral_table;
bool is_parallel_unsafe;
StringBuffer<1024> printed_query_before_pqplan;
private:
bool m_agg_func_used;
bool m_json_agg_func_used;
bool m_empty_query;
static const char *type_str[8];
Mem_root_array<Item_exists_subselect*> *sj_candidates;
public:
int hidden_order_field_count;

Item * where_cond(void) const;
void set_where_cond(Item *);
Item * having_cond(void) const;
void set_having_cond(Item *);
void set_query_result(Query_result *);
Query_result * query_result(void) const;
bool change_query_result(Query_result_interceptor *, Query_result_interceptor *);
void set_base_options(ulonglong);
void add_base_options(ulonglong);
void remove_base_options(ulonglong);
}

SELECT_LEX_UNIT