To implement the final component of the core query processing engine: a Planner. This class bridges the gap between the parser and the execution engine, translating the Abstract Syntax Tree (AST) from ANTLR into a runnable tree of executor objects. This commit marks the completion of the Phase 3 roadmap.
The Planner is the brain of the query processing system. While a production planner is incredibly complex (handling optimization, cost models, and statistics), our simple planner has one clear responsibility: translation. It takes a SQL string as input and produces a ready-to-execute Executor tree as output.
The createPlan method is the entry point. It orchestrates the entire translation pipeline.
The planner first uses the ANTLR-generated classes to transform a raw SQL string into a structured object. This process involves several key components from the ANTLR runtime:
SimpleSQLLexer: The Lexer (or "tokenizer") is the first stage. It consumes the character stream and groups the characters into meaningful tokens (e.g.,SELECT,*,users).CommonTokenStream: The parser needs to be able to look ahead. TheCommonTokenStreamacts as a buffer, pulling all tokens from the lexer and storing them in a list to provide that lookahead capability.SimpleSQLParser: The Parser is the main brain. It consumes the stream of tokens and tries to match them against the structural rules in our grammar, building a tree-like "Context" object (the AST) in memory.
Once the planner has the ANTLR Context Tree, it inspects it to determine the type of statement (SELECT, INSERT, etc.) and delegates to a specific build method (e.g., buildSelectPlan).
The buildSelectPlan method demonstrates the core logic of the planner. It builds the executor tree from the bottom up:
- It always starts with a
SeqScanExecutoras the base of the plan. - It then checks the AST for a
WHEREclause. If one exists, it recursively builds our ownExpressiontree from the AST and wraps theSeqScanExecutorin aFilterExecutor. - Finally, it checks for a specific column list (a projection). If found, it creates an output
Schemaand wraps the current plan in aProjectionExecutor.
This bottom-up construction results in a final, runnable plan like Projection -> Filter -> SeqScan, which can be returned to the client.
With the Planner in place, our database can now accept SQL strings for a variety of single-table queries and execute them correctly. The core query processing engine is complete. We have successfully built:
- An expanded SQL parser.
- Executors for
SELECT(with projection and filtering),INSERT, andDELETE. - A planner to automatically assemble these executors into a query plan.
The database is now functional but not yet performant for large tables. All queries that require finding specific rows must perform a full table scan. Phase 4 will address this by implementing Indexing for Performance. This will involve:
- Implementing a B+-Tree data structure from scratch.
- Building an
IndexScanExecutorthat can use the B+-Tree to find specific tuples without scanning the entire table. - Enhancing the Planner to be able to choose between a
SeqScanand anIndexScanbased on the query.