KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > table > TableFilter


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.table;
6
7 import java.sql.SQLException JavaDoc;
8
9 import org.h2.engine.Constants;
10 import org.h2.engine.Right;
11 import org.h2.engine.Session;
12 import org.h2.expression.ConditionAndOr;
13 import org.h2.expression.Expression;
14 import org.h2.index.Cursor;
15 import org.h2.index.Index;
16 import org.h2.index.IndexCondition;
17 import org.h2.message.Message;
18 import org.h2.result.Row;
19 import org.h2.result.SearchRow;
20 import org.h2.util.ObjectArray;
21 import org.h2.util.StringUtils;
22 import org.h2.value.Value;
23
24 /**
25  * @author Thomas
26  */

27 public class TableFilter implements ColumnResolver {
28     private Session session;
29     private Table table;
30     private String JavaDoc alias;
31     private static final int BEFORE_FIRST = 0, FOUND = 1, AFTER_LAST = 2, NULL_ROW = 3;
32     private Index index;
33     private Cursor cursor;
34     private int scanCount;
35     private boolean used; // used in the plan
36

37     // conditions that can be used for direct index lookup (start or end)
38
private ObjectArray indexConditions = new ObjectArray();
39
40     // conditions that can't be used for index lookup, but for row filter for this table (ID=ID, NAME LIKE '%X%')
41
private Expression filterCondition;
42
43     // the complete join condition
44
private Expression joinCondition;
45     private Row current;
46     private int state;
47     private TableFilter join;
48     private boolean outerJoin;
49     private boolean foundOne;
50     private Expression fullCondition;
51     private boolean rightsChecked;
52
53     public TableFilter(Session session, Table table, String JavaDoc alias, boolean rightsChecked) {
54         this.session = session;
55         this.table = table;
56         this.alias = alias;
57         this.rightsChecked = rightsChecked;
58     }
59
60     public Session getSession() {
61         return session;
62     }
63
64     public Table getTable() {
65         return table;
66     }
67
68     public void lock(Session session, boolean exclusive) throws SQLException JavaDoc {
69         if(!rightsChecked) {
70             session.getUser().checkRight(table, Right.SELECT);
71         }
72         table.lock(session, exclusive);
73         if (join != null) {
74             join.lock(session, exclusive);
75         }
76     }
77
78     public PlanItem getBestPlanItem(Session session) throws SQLException JavaDoc {
79         PlanItem item;
80         if (indexConditions.size() == 0) {
81             item = new PlanItem();
82             item.index = table.getScanIndex(session);
83             item.cost = item.index.getCost(null);
84         } else {
85             int len = table.getColumns().length;
86             int[] masks = new int[len];
87             for (int i = 0; i < indexConditions.size(); i++) {
88                 IndexCondition condition = (IndexCondition) indexConditions.get(i);
89                 if (condition.isEvaluatable()) {
90                     if(condition.isAlwaysFalse()) {
91                         masks = null;
92                         break;
93                     } else {
94                         int id = condition.getColumn().getColumnId();
95                         masks[id] |= condition.getMask();
96                     }
97                 }
98             }
99             item = table.getBestPlanItem(session, masks);
100         }
101         if(join != null) {
102             TableFilter j = join;
103             // this table filter is now evaluatable - in all sub-joins
104
do {
105                 Expression e = j.getJoinCondition();
106                 if(e != null) {
107                     e.setEvaluatable(this, true);
108                 }
109                 j = j.getJoin();
110             } while(j != null);
111             item.joinPlan = join.getBestPlanItem(session);
112             // TODO optimizer: calculate cost of a join: should use separate expected row number and lookup cost
113
item.cost += item.cost * item.joinPlan.cost;
114         }
115         return item;
116     }
117
118     public void setPlanItem(PlanItem item) {
119         this.index = item.index;
120         if(join != null && item.joinPlan!=null) {
121             join.setPlanItem(item.joinPlan);
122         }
123     }
124
125     public void prepare() {
126         // forget all unused index conditions
127
for (int i = 0; i < indexConditions.size(); i++) {
128             IndexCondition condition = (IndexCondition) indexConditions.get(i);
129             if(!condition.isAlwaysFalse()) {
130                 Column col = condition.getColumn();
131                 if(index.getColumnIndex(col) < 0) {
132                     indexConditions.remove(i);
133                     i--;
134                 }
135             }
136         }
137         if(join != null) {
138             if(Constants.CHECK && join==this) {
139                 throw Message.getInternalError("self join");
140             }
141             join.prepare();
142         }
143     }
144
145     public void startQuery() {
146         scanCount = 0;
147         if(join != null) {
148             join.startQuery();
149         }
150     }
151
152     public void reset() throws SQLException JavaDoc {
153         if (join != null) {
154             join.reset();
155         }
156         state = BEFORE_FIRST;
157         foundOne = false;
158     }
159
160     public boolean next() throws SQLException JavaDoc {
161         boolean alwaysFalse = false;
162         if (state == AFTER_LAST) {
163             return false;
164         } else if (state == BEFORE_FIRST) {
165             SearchRow start = null, end = null;
166             for (int i = 0; i < indexConditions.size(); i++) {
167                 IndexCondition condition = (IndexCondition) indexConditions.get(i);
168                 if (condition.isAlwaysFalse()) {
169                     alwaysFalse = true;
170                     break;
171                 }
172                 Column column = condition.getColumn();
173                 int type = column.getType();
174                 int id = column.getColumnId();
175                 Value v = condition.getCurrentValue(session).convertTo(type);
176                 if (condition.isStart()) {
177                     // TODO index: start.setExpression(id, bigger(start.getValue(id), e));
178
if(start == null) {
179                         start = table.getTemplateRow();
180                     }
181                     start.setValue(id, v);
182                 }
183                 if (condition.isEnd()) {
184                     // TODO index: end.setExpression(id, smaller(end.getExpression(id), e));
185
if(end == null) {
186                         end = table.getTemplateRow();
187                     }
188                     end.setValue(id, v);
189                 }
190             }
191             if(!alwaysFalse) {
192                 cursor = index.find(session, start, end);
193                 if(join != null) {
194                     join.reset();
195                 }
196             }
197         } else {
198             // state == FOUND || LAST_ROW
199
// the last row was ok - try next row of the join
200
if(join != null && join.next()) {
201                 return true;
202             }
203         }
204         while(true) {
205             // go to the next row
206
if(state == NULL_ROW) {
207                 break;
208             }
209             if(alwaysFalse) {
210                 state = AFTER_LAST;
211             } else {
212                 scanCount++;
213                 if(cursor.next()) {
214                     current = cursor.get();
215                     state = FOUND;
216                 } else {
217                     state = AFTER_LAST;
218                 }
219             }
220             // if no more rows found, try the null row (for outer joins only)
221
if(state == AFTER_LAST) {
222                 if(outerJoin && !foundOne) {
223                     state = NULL_ROW;
224                     current = table.getNullRow();
225                 } else {
226                     break;
227                 }
228             }
229             if(!isOk(filterCondition)) {
230                 continue;
231             }
232             boolean joinConditionOk = isOk(joinCondition);
233             if(state==FOUND && joinConditionOk) {
234                 foundOne = true;
235             }
236             if(join != null) {
237                 join.reset();
238                 if(!join.next()) {
239                     continue;
240                 }
241             }
242             // check if it's ok
243
if(state==NULL_ROW || joinConditionOk) {
244                 return true;
245             }
246         }
247         state = AFTER_LAST;
248         return false;
249     }
250
251     private boolean isOk(Expression condition) throws SQLException JavaDoc {
252         if(condition == null) {
253             return true;
254         }
255         return Boolean.TRUE.equals(condition.getBooleanValue(session));
256     }
257
258     public Row get() {
259         return current;
260     }
261
262     public void set(Row current) {
263         // this is currently only used so that check constraints work - to set the current (new) row
264
this.current = current;
265     }
266
267     public String JavaDoc getTableAlias() {
268         if (alias != null) {
269             return alias;
270         }
271         return table.getName();
272     }
273
274     public void addIndexCondition(IndexCondition condition) {
275         indexConditions.add(condition);
276     }
277
278     public void addFilterCondition(Expression condition, boolean join) {
279         if(join) {
280             if(joinCondition == null) {
281                 joinCondition = condition;
282             } else {
283                 joinCondition = new ConditionAndOr(ConditionAndOr.AND, joinCondition, condition);
284             }
285         } else {
286             if (filterCondition == null) {
287                 filterCondition = condition;
288             } else {
289                 filterCondition = new ConditionAndOr(ConditionAndOr.AND, filterCondition, condition);
290             }
291         }
292     }
293
294     public void addJoin(TableFilter filter, boolean outer, Expression on) throws SQLException JavaDoc {
295         if(on != null) {
296             on.mapColumns(this, 0);
297         }
298         if(join == null) {
299             this.join = filter;
300             filter.outerJoin = outer;
301             if(on != null) {
302                 TableFilter f = filter;
303                 do {
304                     on.mapColumns(f, 0);
305                     f.addFilterCondition(on, true);
306                     on.createIndexConditions(f);
307                     f = f.join;
308                 } while(f != null);
309             }
310         } else {
311             join.addJoin(filter, outer, on);
312         }
313         if(on != null) {
314             on.optimize(session);
315         }
316     }
317
318     public TableFilter getJoin() {
319         return join;
320     }
321
322     public boolean isJoinOuter() {
323         return outerJoin;
324     }
325
326     public String JavaDoc getPlanSQL(boolean join) {
327         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
328         if(join) {
329             if(outerJoin) {
330                 buff.append("LEFT OUTER JOIN ");
331             } else {
332                 buff.append("INNER JOIN ");
333             }
334         }
335         buff.append(table.getSQL());
336         if(alias != null && !table.getName().equals(alias)) {
337             buff.append(' ');
338             buff.append(alias);
339         }
340         buff.append(" /* ");
341         buff.append(index.getPlanSQL());
342         if(indexConditions.size() > 0) {
343             buff.append(": ");
344             for (int i = 0; i < indexConditions.size(); i++) {
345                 IndexCondition condition = (IndexCondition) indexConditions.get(i);
346                 if(i>0) {
347                     buff.append(" AND ");
348                 }
349                 buff.append(condition.getSQL());
350             }
351         }
352         buff.append(" */");
353         if(joinCondition != null) {
354             buff.append(" ON ");
355             buff.append(StringUtils.unEnclose(joinCondition.getSQL()));
356         }
357         if(filterCondition != null) {
358             buff.append(" /* WHERE ");
359             buff.append(StringUtils.unEnclose(filterCondition.getSQL()));
360             buff.append("*/");
361         }
362         return buff.toString();
363     }
364
365     public void removeUnusableIndexConditions() {
366         for(int i=0; i<indexConditions.size(); i++) {
367             IndexCondition cond = (IndexCondition) indexConditions.get(i);
368             if(!cond.isEvaluatable()) {
369                 indexConditions.remove(i--);
370             }
371         }
372     }
373
374     public Index getIndex() {
375         return index;
376     }
377
378     public void setIndex(Index index) {
379         this.index = index;
380     }
381
382     public void setUsed(boolean used) {
383         this.used = used;
384     }
385
386     public boolean getUsed() {
387         return used;
388     }
389
390     public void setSession(Session session) {
391         this.session = session;
392     }
393
394     public void removeJoin() {
395         this.join = null;
396     }
397
398     public Expression getJoinCondition() {
399         return joinCondition;
400     }
401
402     public void removeJoinCondition() {
403         this.joinCondition = null;
404     }
405
406     public Expression getFilterCondition() {
407         return filterCondition;
408     }
409
410     public void removeFilterCondition() {
411         this.filterCondition = null;
412     }
413
414     public void setFullCondition(Expression condition) {
415         this.fullCondition = condition;
416         if(join != null) {
417             join.setFullCondition(condition);
418         }
419     }
420
421     public void optimizeFullCondition(boolean fromOuterJoin) {
422         if(fullCondition != null) {
423             fullCondition.addFilterConditions(this, fromOuterJoin || outerJoin);
424             if(join != null) {
425                 join.optimizeFullCondition(fromOuterJoin || outerJoin);
426             }
427         }
428     }
429
430     public void setEvaluatable(TableFilter filter, boolean b) {
431         if(filterCondition != null) {
432             filterCondition.setEvaluatable(filter, b);
433         }
434         if(joinCondition != null) {
435             joinCondition.setEvaluatable(filter, b);
436         }
437         if(join != null) {
438             join.setEvaluatable(filter, b);
439         }
440     }
441
442     public String JavaDoc getSchemaName() {
443         return table.getSchema().getName();
444     }
445
446     public Column[] getColumns() {
447         return table.getColumns();
448     }
449
450     public Value getValue(Column column) {
451         return current == null ? null : current.getValue(column.getColumnId());
452     }
453
454     public TableFilter getTableFilter() {
455         return this;
456     }
457
458 }
459
Popular Tags