1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.expression; |
7 | |
8 | import java.util.HashSet; |
9 | import org.h2.engine.DbObject; |
10 | import org.h2.table.Column; |
11 | import org.h2.table.ColumnResolver; |
12 | import org.h2.table.Table; |
13 | |
14 | /** |
15 | * The visitor pattern is used to iterate through all expressions of a query |
16 | * to optimize a statement. |
17 | */ |
18 | public class ExpressionVisitor { |
19 | |
20 | /** |
21 | * Is the value independent on unset parameters or on columns of a higher |
22 | * level query, or sequence values (that means can it be evaluated right |
23 | * now)? |
24 | */ |
25 | public static final int INDEPENDENT = 0; |
26 | |
27 | /** |
28 | * The visitor singleton for the type INDEPENDENT. |
29 | */ |
30 | public static final ExpressionVisitor INDEPENDENT_VISITOR = |
31 | new ExpressionVisitor(INDEPENDENT); |
32 | |
33 | /** |
34 | * Are all aggregates MIN(column), MAX(column), or COUNT(*) for the given |
35 | * table (getTable)? |
36 | */ |
37 | public static final int OPTIMIZABLE_MIN_MAX_COUNT_ALL = 1; |
38 | |
39 | /** |
40 | * Does the expression return the same results for the same parameters? |
41 | */ |
42 | public static final int DETERMINISTIC = 2; |
43 | |
44 | /** |
45 | * The visitor singleton for the type DETERMINISTIC. |
46 | */ |
47 | public static final ExpressionVisitor DETERMINISTIC_VISITOR = |
48 | new ExpressionVisitor(DETERMINISTIC); |
49 | |
50 | /** |
51 | * Can the expression be evaluated, that means are all columns set to |
52 | * 'evaluatable'? |
53 | */ |
54 | public static final int EVALUATABLE = 3; |
55 | |
56 | /** |
57 | * The visitor singleton for the type EVALUATABLE. |
58 | */ |
59 | public static final ExpressionVisitor EVALUATABLE_VISITOR = |
60 | new ExpressionVisitor(EVALUATABLE); |
61 | |
62 | /** |
63 | * Request to set the latest modification id (addDataModificationId). |
64 | */ |
65 | public static final int SET_MAX_DATA_MODIFICATION_ID = 4; |
66 | |
67 | /** |
68 | * Does the expression have no side effects (change the data)? |
69 | */ |
70 | public static final int READONLY = 5; |
71 | |
72 | /** |
73 | * The visitor singleton for the type EVALUATABLE. |
74 | */ |
75 | public static final ExpressionVisitor READONLY_VISITOR = |
76 | new ExpressionVisitor(READONLY); |
77 | |
78 | /** |
79 | * Does an expression have no relation to the given table filter |
80 | * (getResolver)? |
81 | */ |
82 | public static final int NOT_FROM_RESOLVER = 6; |
83 | |
84 | /** |
85 | * Request to get the set of dependencies (addDependency). |
86 | */ |
87 | public static final int GET_DEPENDENCIES = 7; |
88 | |
89 | /** |
90 | * Can the expression be added to a condition of an outer query. Example: |
91 | * ROWNUM() can't be added as a condition to the inner query of select id |
92 | * from (select t.*, rownum as r from test t) where r between 2 and 3; Also |
93 | * a sequence expression must not be used. |
94 | */ |
95 | public static final int QUERY_COMPARABLE = 8; |
96 | |
97 | /** |
98 | * Get all referenced columns. |
99 | */ |
100 | public static final int GET_COLUMNS = 9; |
101 | |
102 | /** |
103 | * The visitor singleton for the type QUERY_COMPARABLE. |
104 | */ |
105 | public static final ExpressionVisitor QUERY_COMPARABLE_VISITOR = |
106 | new ExpressionVisitor(QUERY_COMPARABLE); |
107 | |
108 | private final int type; |
109 | private final int queryLevel; |
110 | private final HashSet<DbObject> dependencies; |
111 | private final HashSet<Column> columns; |
112 | private final Table table; |
113 | private final long[] maxDataModificationId; |
114 | private final ColumnResolver resolver; |
115 | |
116 | private ExpressionVisitor(int type, |
117 | int queryLevel, |
118 | HashSet<DbObject> dependencies, |
119 | HashSet<Column> columns, |
120 | Table table, ColumnResolver resolver, |
121 | long[] maxDataModificationId) { |
122 | this.type = type; |
123 | this.queryLevel = queryLevel; |
124 | this.dependencies = dependencies; |
125 | this.columns = columns; |
126 | this.table = table; |
127 | this.resolver = resolver; |
128 | this.maxDataModificationId = maxDataModificationId; |
129 | } |
130 | |
131 | private ExpressionVisitor(int type) { |
132 | this.type = type; |
133 | this.queryLevel = 0; |
134 | this.dependencies = null; |
135 | this.columns = null; |
136 | this.table = null; |
137 | this.resolver = null; |
138 | this.maxDataModificationId = null; |
139 | } |
140 | |
141 | /** |
142 | * Create a new visitor object to collect dependencies. |
143 | * |
144 | * @param dependencies the dependencies set |
145 | * @return the new visitor |
146 | */ |
147 | public static ExpressionVisitor getDependenciesVisitor( |
148 | HashSet<DbObject> dependencies) { |
149 | return new ExpressionVisitor(GET_DEPENDENCIES, 0, dependencies, null, |
150 | null, null, null); |
151 | } |
152 | |
153 | /** |
154 | * Create a new visitor to check if all aggregates are for the given table. |
155 | * |
156 | * @param table the table |
157 | * @return the new visitor |
158 | */ |
159 | public static ExpressionVisitor getOptimizableVisitor(Table table) { |
160 | return new ExpressionVisitor(OPTIMIZABLE_MIN_MAX_COUNT_ALL, 0, null, |
161 | null, table, null, null); |
162 | } |
163 | |
164 | /** |
165 | * Create a new visitor to check if no expression depends on the given |
166 | * resolver. |
167 | * |
168 | * @param resolver the resolver |
169 | * @return the new visitor |
170 | */ |
171 | static ExpressionVisitor getNotFromResolverVisitor(ColumnResolver resolver) { |
172 | return new ExpressionVisitor(NOT_FROM_RESOLVER, 0, null, null, null, |
173 | resolver, null); |
174 | } |
175 | |
176 | /** |
177 | * Create a new visitor to get all referenced columns. |
178 | * |
179 | * @param columns the columns map |
180 | * @return the new visitor |
181 | */ |
182 | public static ExpressionVisitor getColumnsVisitor(HashSet<Column> columns) { |
183 | return new ExpressionVisitor(GET_COLUMNS, 0, null, columns, null, null, null); |
184 | } |
185 | |
186 | public static ExpressionVisitor getMaxModificationIdVisitor() { |
187 | return new ExpressionVisitor(SET_MAX_DATA_MODIFICATION_ID, 0, null, |
188 | null, null, null, new long[1]); |
189 | } |
190 | |
191 | /** |
192 | * Add a new dependency to the set of dependencies. |
193 | * This is used for GET_DEPENDENCIES visitors. |
194 | * |
195 | * @param obj the additional dependency. |
196 | */ |
197 | public void addDependency(DbObject obj) { |
198 | dependencies.add(obj); |
199 | } |
200 | |
201 | /** |
202 | * Add a new column to the set of columns. |
203 | * This is used for GET_COLUMNS visitors. |
204 | * |
205 | * @param column the additional column. |
206 | */ |
207 | void addColumn(Column column) { |
208 | columns.add(column); |
209 | } |
210 | |
211 | /** |
212 | * Get the dependency set. |
213 | * This is used for GET_DEPENDENCIES visitors. |
214 | * |
215 | * @return the set |
216 | */ |
217 | public HashSet<DbObject> getDependencies() { |
218 | return dependencies; |
219 | } |
220 | |
221 | /** |
222 | * Increment or decrement the query level. |
223 | * |
224 | * @param offset 1 to increment, -1 to decrement |
225 | * @return a clone of this expression visitor, with the changed query level |
226 | */ |
227 | public ExpressionVisitor incrementQueryLevel(int offset) { |
228 | return new ExpressionVisitor(type, queryLevel + offset, dependencies, |
229 | columns, table, resolver, maxDataModificationId); |
230 | } |
231 | |
232 | /** |
233 | * Get the column resolver. |
234 | * This is used for NOT_FROM_RESOLVER visitors. |
235 | * |
236 | * @return the column resolver |
237 | */ |
238 | public ColumnResolver getResolver() { |
239 | return resolver; |
240 | } |
241 | |
242 | /** |
243 | * Update the field maxDataModificationId if this value is higher |
244 | * than the current value. |
245 | * This is used for SET_MAX_DATA_MODIFICATION_ID visitors. |
246 | * |
247 | * @param value the data modification id |
248 | */ |
249 | public void addDataModificationId(long value) { |
250 | long m = maxDataModificationId[0]; |
251 | if (value > m) { |
252 | maxDataModificationId[0] = value; |
253 | } |
254 | } |
255 | |
256 | /** |
257 | * Get the last data modification. |
258 | * This is used for SET_MAX_DATA_MODIFICATION_ID visitors. |
259 | * |
260 | * @return the maximum modification id |
261 | */ |
262 | public long getMaxDataModificationId() { |
263 | return maxDataModificationId[0]; |
264 | } |
265 | |
266 | int getQueryLevel() { |
267 | return queryLevel; |
268 | } |
269 | |
270 | /** |
271 | * Get the table. |
272 | * This is used for OPTIMIZABLE_MIN_MAX_COUNT_ALL visitors. |
273 | * |
274 | * @return the table |
275 | */ |
276 | public Table getTable() { |
277 | return table; |
278 | } |
279 | |
280 | /** |
281 | * Get the visitor type. |
282 | * |
283 | * @return the type |
284 | */ |
285 | public int getType() { |
286 | return type; |
287 | } |
288 | |
289 | } |