11# SQL Execution
22
3- Ok, now that the planner and optimizer has done all the hard work of figuring out how to execute a
3+ Now that the planner and optimizer have done all the hard work of figuring out how to execute a
44query, it's time to actually execute it.
55
66## Plan Executor
77
88Plan execution is done by ` sql::execution::Executor ` in the
99[ ` sql::execution ` ] ( https://github.com/erikgrinaker/toydb/tree/9419bcf6aededf0e20b4e7485e2a5fa3e975d79f/src/sql/execution )
10- module, using a ` sql::engine::Transaction ` to perform read/write operations on the SQL engine.
10+ module, using a ` sql::engine::Transaction ` to access the SQL storage engine.
1111
1212https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5/src/sql/execution/executor.rs#L14-L49
1313
1414The executor takes a ` sql::planner::Plan ` as input, and will return an ` ExecutionResult ` depending
1515on the statement type.
1616
17- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L330-L338
17+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L331-L339
1818
1919When executing the plan, the executor will branch off depending on the statement type:
2020
21- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L56-L100
21+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L57-L101
2222
23- We'll focus on ` SELECT ` queries here, which is the most interesting.
23+ We'll focus on ` SELECT ` queries here, which are the most interesting.
2424
25- toyDB uses the iterator model (also known as the volcano model) for query execution. In the case
26- of a ` SELECT ` query, the result is a result row iterator, and pulling from this iterator by calling
27- ` next() ` will drive the entire execution pipeline. This maps very naturally onto Rust's iterators,
28- and we leverage these to construct the execution pipeline as nested iterators.
25+ toyDB uses the iterator model (also known as the volcano model) for query execution. In the case of
26+ a ` SELECT ` query, the result is a row iterator, and pulling from this iterator by calling ` next() `
27+ will drive the entire execution pipeline by recursively calling ` next() ` on the child nodes' row
28+ iterators. This maps very naturally onto Rust's iterators, and we leverage these to construct the
29+ execution pipeline as nested iterators.
2930
3031Execution itself is fairly straightforward, since we're just doing exactly what the planner tells us
3132to do in the plan. We call ` Executor::execute_node ` recursively on each ` sql::planner:Node ` ,
3233starting with the root node. Each node returns a result row iterator that the parent node can pull
3334its input rows from, process them, and output the resulting rows via its own row iterator (with the
3435root node's iterator being returned to the caller):
3536
36- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L102- L103
37+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L103-L104
3738
38- ` Executor::execute_node ` will simply look at the type of ` Node ` , recursively call
39- ` Executor::execute_node ` on any child nodes, and then process the rows accordingly.
39+ ` Executor::execute_node() ` will simply look at the type of ` Node ` , recursively call
40+ ` Executor::execute_node() ` on any child nodes, and then process the rows accordingly.
4041
41- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L102-L211
42+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L103-L212
4243
43- We won't discuss every plan node in details , but let's consider the movie plan we've looked at
44+ We won't discuss every plan node in detail , but let's consider the movie plan we've looked at
4445previously:
4546
4647```
@@ -52,62 +53,62 @@ Select
5253 └─ Scan: genres
5354```
5455
55- We'll recursively call ` execute_node ` until we end up in the two ` Scan ` nodes. These simply
56- call through to the SQL engine (either using Raft or local disk) via ` Transaction::scan ` , passing
56+ We'll recursively call ` execute_node() ` until we end up in the two ` Scan ` nodes. These simply
57+ call through to the SQL engine (either using Raft or local disk) via ` Transaction::scan() ` , passing
5758in the scan predicate if any, and return the resulting row iterator:
5859
59- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L202- L203
60+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L203-L204
6061
6162` HashJoin ` will then join the output rows from the ` movies ` and ` genres ` iterators by using a
6263hash join. This builds an in-memory table for ` genres ` and then iterates over ` movies ` , joining
6364the rows:
6465
65- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L127-L140
66+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L128-L141
6667
6768https://github.com/erikgrinaker/toydb/blob/889aef9f24c0fa4d58e314877fa17559a9f3d5d2/src/sql/execution/join.rs#L103-L183
6869
6970The ` Projection ` node will simply evaluate the (trivial) column expressions using each joined
7071row as input:
7172
72- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L178-L185
73+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L179-L186
7374
7475And finally the ` Order ` node will sort the results (which requires buffering them all in memory):
7576
76- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L172-L176
77+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L173-L177
7778
78- https://github.com/erikgrinaker/toydb/blob/213e5c02b09f1a3cac6a8bbd0a81773462f367f5 /src/sql/execution/executor.rs#L297-L327
79+ https://github.com/erikgrinaker/toydb/blob/686d3971a253bfc9facc2ba1b0e716cff5c109fb /src/sql/execution/executor.rs#L298-L328
7980
80- The output row iterator of ` Order ` is returned to the caller via ` ExecutionResult::Select ` , and
81- it can now go ahead and pull its query result .
81+ The output row iterator of ` Order ` is returned via ` ExecutionResult::Select ` , and the caller can now
82+ go ahead and pull the resulting rows from it .
8283
8384## Session Management
8485
8586The entry point to the SQL engine is the ` sql::execution::Session ` , which represents a single user
86- session. It is obtained via ` sql::engine::Engine::session ` .
87+ session. It is obtained via ` sql::engine::Engine::session() ` .
8788
8889https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L14-L21
8990
90- The session takes a series of raw SQL statement strings as input, then parses, plans, and executes
91- them against the engine.
91+ The session takes a series of raw SQL statement strings as input and parses them:
9292
93- https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L29-L30
93+ https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L29-L33
9494
9595For each statement, it returns a result depending on the kind of statement:
9696
9797https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L132-L148
9898
99- In particular, the session performs transaction control. It handles ` BEGIN ` , ` COMMIT ` , and
100- ` ROLLBACK ` statements itself , and modifies the transaction accordingly.
99+ The session itself performs transaction control. It handles ` BEGIN ` , ` COMMIT ` , and ` ROLLBACK `
100+ statements, and modifies the transaction accordingly.
101101
102102https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L34-L70
103103
104104Any other statements are processed by the SQL planner, optimizer, and executor as we've seen in
105- previous sections. These statements are always executed using the session's current transaction. If
106- there is no active transaction, the session will create a new, implicit transaction for each
107- statement.
105+ previous sections.
108106
109107https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L77-L83
110108
109+ These statements are always executed using the session's current transaction. If there is no active
110+ transaction, the session will create a new, implicit transaction for each statement.
111+
111112https://github.com/erikgrinaker/toydb/blob/0839215770e31f1e693d5cccf20a68210deaaa3f/src/sql/execution/session.rs#L87-L112
112113
113114And with that, we have a fully functional SQL engine!
0 commit comments