-
Notifications
You must be signed in to change notification settings - Fork 0
/
Planner.py
156 lines (122 loc) · 4.68 KB
/
Planner.py
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from Metadata import *
from Parser import *
import logging
db_logger = logging.getLogger('SimpleDB')
# In the book, all *Plan classes are implementing Plan interface
# Plan interface has the following methods;
# open()
# blocksAccessed()
# recordsOutput()
# distinctValues(field_name)
# schema()
# schema is used to verify type correctness and plan optimization
class TablePlan:
def __init__(self, tx : Transaction, table_name, mm : MetadataMgr):
self.tx = tx
self.table_name = table_name
self.layout = mm.getLayout(self.tx, self.table_name)
self.table_stat = mm.getStatInfo(tx, self.table_name, self.layout)
def open(self):
return TableScan(self.tx, self.table_name, self.layout)
def blocksAccessed(self):
return self.table_stat['blocksAccessed']
def recordsOutput(self):
return self.table_stat['recordsOutput']
# TODO: Update this once we have distinct values for each column name
def distinctValues(self, field_name):
return self.table_stat['distinctValues']
def plan_schema(self):
return self.layout.schema
class SelectPlan:
def __init__(self, plan, pred):
self.plan = plan
self.pred = pred
def open(self):
temp_scan = self.plan.open()
return SelectScan(temp_scan, self.pred)
def blocksAccessed(self):
return self.plan.blocksAccessed()
def recordsOutput(self):
return self.plan.recordsOutput()
# TODO: Update this once we have distinct values for each column name
def distinctValues(self, field_name):
return self.plan.distinctValues()
def plan_schema(self):
return self.plan.plan_schema()
class ProjectPlan:
def __init__(self, plan, *fields):
self.plan = plan
self.fields = fields
self.schema: Schema = Schema()
for field_name in self.fields:
self.schema.addField(
field_name,
self.plan.plan_schema().field_info[field_name]['field_type'],
self.plan.plan_schema().field_info[field_name]['field_byte_length']
)
def open(self):
temp_scan = self.plan.open()
return ProjectScan(temp_scan, *self.fields)
def blocksAccessed(self):
return self.plan.blocksAccessed()
def recordsOutput(self):
return self.plan.recordsOutput()
# TODO: Update this once we have distinct values for each column name
def distinctValues(self, field_name):
return self.plan.distinctValues()
def plan_schema(self):
return self.schema
class ProductPlan:
def __init__(self, plan1, plan2):
self.plan1 = plan1
self.plan2 = plan2
self.schema = Schema()
self.schema.field_info = {
**self.plan1.plan_schema().field_info.copy(),
**self.plan2.plan_schema().field_info.copy()
}
def open(self):
temp_scan1 = self.plan1.open()
temp_scan2 = self.plan2.open()
return ProductScan(temp_scan1, temp_scan2)
def blocksAccessed(self):
pass
def recordsOutput(self):
pass
# TODO: Update this once we have distinct values for each column name
def distinctValues(self, field_name):
pass
def plan_schema(self):
return self.schema
# implements basic query planning algorithme explained in 10.10
# All variants of QueryPlanner implements QueryPlanner interface
class BasicQueryPlanner:
def __init__(self, mm):
self.mm = mm
def createPlan(self, tx, query_data):
all_plans = []
for table_name in query_data['tables']:
all_plans.append(TablePlan(tx, table_name, self.mm))
product_plan = all_plans[0]
del all_plans[0]
for t in all_plans:
product_plan = ProductPlan(t, product_plan)
select_plan = SelectPlan(product_plan, query_data['predicate'])
return ProjectPlan(select_plan, *query_data['fields'])
class BetterQueryPlanner:
pass
# All updates scanners implements UpdatePlanner interface
class BasicUpdatePlanner:
def __init__(self, mm):
self.mm = mm
class Planner:
def __init__(self, query_planner, update_planner):
self.query_planner = query_planner
self.update_planner = update_planner
def createQueryPlan(self, tx, query):
parsed_query = Parser(query)
# TODO: Verify Consistency of ACID; meaning that query is valid to run, such as type checking
# TODO: Verify the user is authorized to run, table access permission
# TODO: Query rewrite during optimization; such as using BetterQueryPlanner.createPlan()
query_plan = self.query_planner.createPlan(tx, parsed_query.query())
return query_plan