KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > command > dml > SelectUnion


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.command.dml;
6
7 import java.sql.SQLException JavaDoc;
8 import java.util.HashSet JavaDoc;
9
10 import org.h2.engine.Constants;
11 import org.h2.engine.Session;
12 import org.h2.expression.Expression;
13 import org.h2.expression.ExpressionColumn;
14 import org.h2.expression.ExpressionVisitor;
15 import org.h2.expression.ValueExpression;
16 import org.h2.jdbc.JdbcSQLException;
17 import org.h2.message.Message;
18 import org.h2.result.LocalResult;
19 import org.h2.result.SortOrder;
20 import org.h2.table.Column;
21 import org.h2.table.ColumnResolver;
22 import org.h2.table.TableFilter;
23 import org.h2.util.ObjectArray;
24 import org.h2.util.StringUtils;
25 import org.h2.value.Value;
26 import org.h2.value.ValueInt;
27
28 public class SelectUnion extends Query {
29     public static final int UNION=0, UNION_ALL=1, EXCEPT=2, INTERSECT=3;
30     private int unionType;
31     private Query left, right;
32     private ObjectArray expressions;
33     private ObjectArray orderList;
34     private SortOrder sort;
35     private boolean distinct;
36     private boolean checkPrepared, checkInit;
37     private boolean isForUpdate;
38     
39     public SelectUnion(Session session, Query query) {
40         super(session);
41         this.left = query;
42     }
43     
44     public void setUnionType(int type) {
45         this.unionType = type;
46     }
47     
48     public void setRight(Query select) throws JdbcSQLException {
49         right = select;
50     }
51     
52     
53     
54     public void setSQL(String JavaDoc sql) {
55         this.sql = sql;
56     }
57     
58     public void setOrder(ObjectArray order) {
59         orderList = order;
60     }
61     
62     private Value[] convert(Value[] values) throws SQLException JavaDoc {
63         for(int i=0; i<values.length; i++) {
64             Expression e = (Expression) expressions.get(i);
65             values[i] = values[i].convertTo(e.getType());
66         }
67         return values;
68     }
69
70     public LocalResult queryWithoutCache(int maxrows) throws SQLException JavaDoc {
71         if(maxrows != 0) {
72             if(limit != null) {
73                 maxrows = Math.min(limit.getValue(session).getInt(), maxrows);
74             }
75             limit = ValueExpression.get(ValueInt.get(maxrows));
76         }
77         ObjectArray expressions = left.getExpressions();
78         int columnCount = left.getColumnCount();
79         LocalResult result = new LocalResult(session, expressions, columnCount);
80         result.setSortOrder(sort);
81         if(distinct) {
82             left.setDistinct(true);
83             right.setDistinct(true);
84             result.setDistinct();
85         }
86         switch(unionType) {
87         case UNION:
88             left.setDistinct(true);
89             right.setDistinct(true);
90             result.setDistinct();
91             break;
92         case UNION_ALL:
93             break;
94         case EXCEPT:
95             result.setDistinct();
96             // fall through
97
case INTERSECT: {
98             left.setDistinct(true);
99             right.setDistinct(true);
100             break;
101         }
102         default:
103             throw Message.getInternalError("type="+unionType);
104         }
105         LocalResult l = left.query(0);
106         LocalResult r = right.query(0);
107         l.reset();
108         r.reset();
109         switch(unionType) {
110         case UNION_ALL:
111         case UNION: {
112             while(l.next()) {
113                 result.addRow(convert(l.currentRow()));
114             }
115             while(r.next()) {
116                 result.addRow(convert(r.currentRow()));
117             }
118             break;
119         }
120         case EXCEPT: {
121             while(l.next()) {
122                 result.addRow(convert(l.currentRow()));
123             }
124             while(r.next()) {
125                 result.removeDistinct(convert(r.currentRow()));
126             }
127             break;
128         }
129         case INTERSECT: {
130             LocalResult temp = new LocalResult(session, expressions, columnCount);
131             temp.setDistinct();
132             while(l.next()) {
133                 temp.addRow(convert(l.currentRow()));
134             }
135             while(r.next()) {
136                 Value[] values = convert(r.currentRow());
137                 if(temp.containsDistinct(values)) {
138                     result.addRow(values);
139                 }
140             }
141             break;
142         }
143         default:
144             throw Message.getInternalError("type="+unionType);
145         }
146         if(offset != null) {
147             result.setOffset(offset.getValue(session).getInt());
148         }
149         if(limit != null) {
150             result.setLimit(limit.getValue(session).getInt());
151         }
152         result.done();
153         return result;
154     }
155     
156     public void init() throws SQLException JavaDoc {
157         if(Constants.CHECK && checkInit) {
158             throw Message.getInternalError();
159         }
160         checkInit = true;
161         left.init();
162         right.init();
163         int len = left.getColumnCount();
164         if(len != right.getColumnCount()) {
165             throw Message.getSQLException(Message.COLUMN_COUNT_DOES_NOT_MATCH);
166         }
167     }
168
169     public void prepare() throws SQLException JavaDoc {
170         if(Constants.CHECK && (checkPrepared || !checkInit)) {
171             throw Message.getInternalError("already prepared");
172         }
173         checkPrepared = true;
174         left.prepare();
175         right.prepare();
176         ObjectArray le = left.getExpressions();
177         ObjectArray re = right.getExpressions();
178         expressions = new ObjectArray();
179         int len = left.getColumnCount();
180         for(int i=0; i<len; i++) {
181             Expression l = (Expression)le.get(i);
182             Expression r = (Expression)re.get(i);
183             int type = Value.getHigherOrder(l.getType(), r.getType());
184             long prec = Math.max(l.getPrecision(), r.getPrecision());
185             int scale = Math.max(l.getScale(), r.getScale());
186             Column col = new Column(l.getAlias(), type, prec, scale);
187             Expression e = new ExpressionColumn(session.getDatabase(), null, col);
188             expressions.add(e);
189         }
190         if(orderList != null) {
191             sort = initOrder(expressions, orderList, getColumnCount(), true);
192             orderList = null;
193         }
194     }
195
196     public double getCost() {
197         return left.getCost() + right.getCost();
198     }
199     
200     public HashSet JavaDoc getTables() {
201         HashSet JavaDoc set = left.getTables();
202         set.addAll(right.getTables());
203         return set;
204     }
205     
206     public void setDistinct(boolean b) {
207         distinct = b;
208     }
209
210     public ObjectArray getExpressions() {
211         return expressions;
212     }
213
214     public void setForUpdate(boolean forUpdate) {
215         left.setForUpdate(forUpdate);
216         right.setForUpdate(forUpdate);
217         isForUpdate = forUpdate;
218     }
219
220     public int getColumnCount() {
221         return left.getColumnCount();
222     }
223
224     public void mapColumns(ColumnResolver resolver, int level) throws SQLException JavaDoc {
225         left.mapColumns(resolver, level);
226         right.mapColumns(resolver, level);
227     }
228     
229     public void setEvaluatable(TableFilter tableFilter, boolean b) {
230         left.setEvaluatable(tableFilter, b);
231         right.setEvaluatable(tableFilter, b);
232     }
233
234     public void addGlobalCondition(Expression expr, int columnId, int comparisonType) throws SQLException JavaDoc {
235         switch(unionType) {
236         case UNION_ALL:
237         case UNION:
238         case INTERSECT: {
239             left.addGlobalCondition(expr, columnId, comparisonType);
240             right.addGlobalCondition(expr, columnId, comparisonType);
241             break;
242         }
243         case EXCEPT: {
244             left.addGlobalCondition(expr, columnId, comparisonType);
245             break;
246         }
247         default:
248             throw Message.getInternalError("type="+unionType);
249         }
250     }
251     
252     public String JavaDoc getPlan() {
253         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
254         buff.append('(');
255         buff.append(left.getPlan());
256         buff.append(") ");
257         switch(unionType) {
258         case UNION_ALL:
259             buff.append("UNION ALL ");
260             break;
261         case UNION:
262             buff.append("UNION ");
263             break;
264         case INTERSECT:
265             buff.append("INTERSECT ");
266             break;
267         case EXCEPT:
268             buff.append("EXCEPT ");
269             break;
270         default:
271             throw Message.getInternalError("type="+unionType);
272         }
273         buff.append('(');
274         buff.append(right.getPlan());
275         buff.append(')');
276         Expression[] exprList = new Expression[expressions.size()];
277         expressions.toArray(exprList);
278         if(sort != null) {
279             buff.append(" ORDER BY ");
280             buff.append(sort.getSQL(exprList, exprList.length));
281         }
282         // TODO refactoring: limit and order by could be in Query (now in SelectUnion and in Select)
283
if(limit != null) {
284             buff.append(" LIMIT ");
285             buff.append(StringUtils.unEnclose(limit.getSQL()));
286             if(offset != null) {
287                 buff.append(" OFFSET ");
288                 buff.append(StringUtils.unEnclose(offset.getSQL()));
289             }
290         }
291         if(isForUpdate) {
292             buff.append(" FOR UPDATE");
293         }
294         return buff.toString();
295     }
296
297     public boolean isEverything(ExpressionVisitor visitor) {
298         return left.isEverything(visitor) && right.isEverything(visitor);
299     }
300     
301     public boolean isReadOnly() {
302         return left.isReadOnly() && right.isReadOnly();
303     }
304
305 }
306
Popular Tags