forked from robertzhao2002/database-management-system
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLogicalPlanBuilder.java
113 lines (104 loc) · 5 KB
/
LogicalPlanBuilder.java
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
package com.dbms.queryplan;
import com.dbms.operators.logical.LogicalDuplicateEliminationOperator;
import com.dbms.operators.logical.LogicalJoinOperator;
import com.dbms.operators.logical.LogicalOperator;
import com.dbms.operators.logical.LogicalProjectOperator;
import com.dbms.operators.logical.LogicalScanOperator;
import com.dbms.operators.logical.LogicalSelectOperator;
import com.dbms.operators.logical.LogicalSortOperator;
import com.dbms.utils.Catalog;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.AllColumns;
import net.sf.jsqlparser.statement.select.Distinct;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
/** Builds a query plan from a Statement and stores the root operator. */
public class LogicalPlanBuilder {
public LogicalOperator root;
/** @param tableName (aliased) table name for the scan
* @param exp select expression, null if not filtered
* @return scan operator if expression is null, otherwise a select operator */
private LogicalOperator createScanAndSelect(String tableName, Expression exp) {
LogicalOperator op = new LogicalScanOperator(tableName);
if (exp != null) op = new LogicalSelectOperator(op, exp);
return op;
}
/** Initializes a join operator after selection-pushing has been done
*
* @param tables list of join tables
* @param uv {@code UnionFindVisitor} for selection-pushing
* @return {@code LogicalJoinOperator} that contains all the conditions of each children as
* select operators
* @throws FileNotFoundException */
private LogicalJoinOperator createJoinOperator(List<String> tables, UnionFindVisitor uv)
throws FileNotFoundException {
Map<String, LogicalOperator> children = new HashMap<>();
for (String table : tables) {
children.put(table, createScanAndSelect(table, uv.getExpression(table)));
}
return new LogicalJoinOperator(children, uv, tables);
}
/** Populates Catalog alias map if tables use aliases.
*
* @param from from table
* @param joins join tables, null if not a join
* @return list of (aliased) table names in the order of tables provided */
private List<String> extractNames(FromItem from, List<Join> joins) {
LinkedList<FromItem> tables = joins != null
? joins.stream().map(j -> j.getRightItem()).collect(Collectors.toCollection(LinkedList::new))
: new LinkedList<>();
tables.addFirst(from);
return Catalog.populateAliasMap(tables);
}
/** @param statement Statement for which to build a query plan and create a root operator
* @throws FileNotFoundException */
public LogicalPlanBuilder(Statement statement) throws FileNotFoundException {
// extract relevant items from statement
Select select = (Select) statement;
PlainSelect body = (PlainSelect) select.getSelectBody();
List<SelectItem> selectItems = body.getSelectItems();
boolean isAllColumns = selectItems.get(0) instanceof AllColumns;
Expression exp = body.getWhere();
FromItem mainFromItem = body.getFromItem();
List<Join> joins = body.getJoins();
List<String> tableNames = extractNames(mainFromItem, joins);
List<OrderByElement> orderByElements = body.getOrderByElements();
Distinct distinct = body.getDistinct();
LogicalOperator subRoot;
if (joins != null) {
UnionFindVisitor uv = new UnionFindVisitor();
if (exp != null) exp.accept(uv);
subRoot = createJoinOperator(tableNames, uv);
} else {
// if no joins, create a scan/select operator for the from table
subRoot = createScanAndSelect(tableNames.get(0), exp);
}
// add if necessary: projection, sorting, duplicate elimination
if (!isAllColumns) subRoot = new LogicalProjectOperator(subRoot, selectItems);
subRoot = orderByElements != null || distinct != null
? new LogicalSortOperator(subRoot, orderByElements)
: subRoot;
root = distinct != null ? new LogicalDuplicateEliminationOperator(subRoot) : subRoot;
}
/** Writes this plan. Assumes a statement was already processed.
*
* @param i query number
* @throws FileNotFoundException */
public void writePlan(int i) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(Catalog.pathToOutputLogicalPlan(i));
root.write(pw, 0);
pw.close();
}
}