File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\command\dml\SelectUnion.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.command.dml;
8
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import org.h2.command.CommandInterface;
12 import org.h2.constant.ErrorCode;
13 import org.h2.constant.SysProperties;
14 import org.h2.engine.Session;
15 import org.h2.expression.Expression;
16 import org.h2.expression.ExpressionColumn;
17 import org.h2.expression.ExpressionVisitor;
18 import org.h2.expression.Parameter;
19 import org.h2.expression.ValueExpression;
20 import org.h2.message.DbException;
21 import org.h2.result.LocalResult;
22 import org.h2.result.ResultInterface;
23 import org.h2.result.ResultTarget;
24 import org.h2.result.SortOrder;
25 import org.h2.table.Column;
26 import org.h2.table.ColumnResolver;
27 import org.h2.table.Table;
28 import org.h2.table.TableFilter;
29 import org.h2.util.New;
30 import org.h2.util.StringUtils;
31 import org.h2.value.Value;
32 import org.h2.value.ValueInt;
33 import org.h2.value.ValueNull;
34
35 /**
36 * Represents a union SELECT statement.
37 */
38 public class SelectUnion extends Query {
39
40 /**
41 * The type of a UNION statement.
42 */
43 public static final int UNION = 0;
44
45 /**
46 * The type of a UNION ALL statement.
47 */
48 public static final int UNION_ALL = 1;
49
50 /**
51 * The type of an EXCEPT statement.
52 */
53 public static final int EXCEPT = 2;
54
55 /**
56 * The type of an INTERSECT statement.
57 */
58 public static final int INTERSECT = 3;
59
60 private int unionType;
61 private final Query left;
62 private Query right;
63 private ArrayList<Expression> expressions;
64 private Expression[] expressionArray;
65 private ArrayList<SelectOrderBy> orderList;
66 private SortOrder sort;
67 private boolean isPrepared, checkInit;
68 private boolean isForUpdate;
69
70 public SelectUnion(Session session, Query query) {
71 super(session);
72 this.left = query;
73 }
74
75 public void setUnionType(int type) {
76 this.unionType = type;
77 }
78
79 public int getUnionType() {
80 return unionType;
81 }
82
83 public void setRight(Query select) {
84 right = select;
85 }
86
87 public Query getLeft() {
88 return left;
89 }
90
91 public Query getRight() {
92 return right;
93 }
94
95 public void setSQL(String sql) {
96 this.sqlStatement = sql;
97 }
98
99 public void setOrder(ArrayList<SelectOrderBy> order) {
100 orderList = order;
101 }
102
103 private Value[] convert(Value[] values, int columnCount) {
104 for (int i = 0; i < columnCount; i++) {
105 Expression e = expressions.get(i);
106 values[i] = values[i].convertTo(e.getType());
107 }
108 return values;
109 }
110
111 public ResultInterface queryMeta() {
112 int columnCount = left.getColumnCount();
113 LocalResult result = new LocalResult(session, expressionArray, columnCount);
114 result.done();
115 return result;
116 }
117
118 public LocalResult getEmptyResult() {
119 int columnCount = left.getColumnCount();
120 return new LocalResult(session, expressionArray, columnCount);
121 }
122
123 protected LocalResult queryWithoutCache(int maxRows, ResultTarget target) {
124 if (maxRows != 0) {
125 // maxRows is set (maxRows 0 means no limit)
126 int l;
127 if (limitExpr == null) {
128 l = -1;
129 } else {
130 Value v = limitExpr.getValue(session);
131 l = v == ValueNull.INSTANCE ? -1 : v.getInt();
132 }
133 if (l < 0) {
134 // for limitExpr, 0 means no rows, and -1 means no limit
135 l = maxRows;
136 } else {
137 l = Math.min(l, maxRows);
138 }
139 limitExpr = ValueExpression.get(ValueInt.get(l));
140 }
141 if (session.getDatabase().getSettings().optimizeInsertFromSelect) {
142 if (unionType == UNION_ALL && target != null) {
143 if (sort == null && !distinct && maxRows == 0 && offsetExpr == null && limitExpr == null) {
144 left.query(0, target);
145 right.query(0, target);
146 return null;
147 }
148 }
149 }
150 int columnCount = left.getColumnCount();
151 LocalResult result = new LocalResult(session, expressionArray, columnCount);
152 if (sort != null) {
153 result.setSortOrder(sort);
154 }
155 if (distinct) {
156 left.setDistinct(true);
157 right.setDistinct(true);
158 result.setDistinct();
159 }
160 if (randomAccessResult) {
161 result.setRandomAccess();
162 }
163 switch (unionType) {
164 case UNION:
165 case EXCEPT:
166 left.setDistinct(true);
167 right.setDistinct(true);
168 result.setDistinct();
169 break;
170 case UNION_ALL:
171 break;
172 case INTERSECT:
173 left.setDistinct(true);
174 right.setDistinct(true);
175 break;
176 default:
177 DbException.throwInternalError("type=" + unionType);
178 }
179 ResultInterface l = left.query(0);
180 ResultInterface r = right.query(0);
181 l.reset();
182 r.reset();
183 switch (unionType) {
184 case UNION_ALL:
185 case UNION: {
186 while (l.next()) {
187 result.addRow(convert(l.currentRow(), columnCount));
188 }
189 while (r.next()) {
190 result.addRow(convert(r.currentRow(), columnCount));
191 }
192 break;
193 }
194 case EXCEPT: {
195 while (l.next()) {
196 result.addRow(convert(l.currentRow(), columnCount));
197 }
198 while (r.next()) {
199 result.removeDistinct(convert(r.currentRow(), columnCount));
200 }
201 break;
202 }
203 case INTERSECT: {
204 LocalResult temp = new LocalResult(session, expressionArray, columnCount);
205 temp.setDistinct();
206 temp.setRandomAccess();
207 while (l.next()) {
208 temp.addRow(convert(l.currentRow(), columnCount));
209 }
210 while (r.next()) {
211 Value[] values = convert(r.currentRow(), columnCount);
212 if (temp.containsDistinct(values)) {
213 result.addRow(values);
214 }
215 }
216 break;
217 }
218 default:
219 DbException.throwInternalError("type=" + unionType);
220 }
221 if (offsetExpr != null) {
222 result.setOffset(offsetExpr.getValue(session).getInt());
223 }
224 if (limitExpr != null) {
225 Value v = limitExpr.getValue(session);
226 if (v != ValueNull.INSTANCE) {
227 result.setLimit(v.getInt());
228 }
229 }
230 result.done();
231 if (target != null) {
232 while (result.next()) {
233 target.addRow(result.currentRow());
234 }
235 result.close();
236 return null;
237 }
238 return result;
239 }
240
241 public void init() {
242 if (SysProperties.CHECK && checkInit) {
243 DbException.throwInternalError();
244 }
245 checkInit = true;
246 left.init();
247 right.init();
248 int len = left.getColumnCount();
249 if (len != right.getColumnCount()) {
250 throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
251 }
252 ArrayList<Expression> le = left.getExpressions();
253 // set the expressions to get the right column count and names,
254 // but can't validate at this time
255 expressions = New.arrayList();
256 for (int i = 0; i < len; i++) {
257 Expression l = le.get(i);
258 expressions.add(l);
259 }
260 }
261
262 public void prepare() {
263 if (isPrepared) {
264 // sometimes a subquery is prepared twice (CREATE TABLE AS SELECT)
265 return;
266 }
267 if (SysProperties.CHECK && !checkInit) {
268 DbException.throwInternalError("not initialized");
269 }
270 isPrepared = true;
271 left.prepare();
272 right.prepare();
273 int len = left.getColumnCount();
274 // set the correct expressions now
275 expressions = New.arrayList();
276 ArrayList<Expression> le = left.getExpressions();
277 ArrayList<Expression> re = right.getExpressions();
278 for (int i = 0; i < len; i++) {
279 Expression l = le.get(i);
280 Expression r = re.get(i);
281 int type = Value.getHigherOrder(l.getType(), r.getType());
282 long prec = Math.max(l.getPrecision(), r.getPrecision());
283 int scale = Math.max(l.getScale(), r.getScale());
284 int displaySize = Math.max(l.getDisplaySize(), r.getDisplaySize());
285 Column col = new Column(l.getAlias(), type, prec, scale, displaySize);
286 Expression e = new ExpressionColumn(session.getDatabase(), col);
287 expressions.add(e);
288 }
289 if (orderList != null) {
290 initOrder(session, expressions, null, orderList, getColumnCount(), true, null);
291 sort = prepareOrder(orderList, expressions.size());
292 orderList = null;
293 }
294 expressionArray = new Expression[expressions.size()];
295 expressions.toArray(expressionArray);
296 }
297
298 public double getCost() {
299 return left.getCost() + right.getCost();
300 }
301
302 public HashSet<Table> getTables() {
303 HashSet<Table> set = left.getTables();
304 set.addAll(right.getTables());
305 return set;
306 }
307
308 public ArrayList<Expression> getExpressions() {
309 return expressions;
310 }
311
312 public void setForUpdate(boolean forUpdate) {
313 left.setForUpdate(forUpdate);
314 right.setForUpdate(forUpdate);
315 isForUpdate = forUpdate;
316 }
317
318 public int getColumnCount() {
319 return left.getColumnCount();
320 }
321
322 public void mapColumns(ColumnResolver resolver, int level) {
323 left.mapColumns(resolver, level);
324 right.mapColumns(resolver, level);
325 }
326
327 public void setEvaluatable(TableFilter tableFilter, boolean b) {
328 left.setEvaluatable(tableFilter, b);
329 right.setEvaluatable(tableFilter, b);
330 }
331
332 public void addGlobalCondition(Parameter param, int columnId, int comparisonType) {
333 addParameter(param);
334 switch (unionType) {
335 case UNION_ALL:
336 case UNION:
337 case INTERSECT: {
338 left.addGlobalCondition(param, columnId, comparisonType);
339 right.addGlobalCondition(param, columnId, comparisonType);
340 break;
341 }
342 case EXCEPT: {
343 left.addGlobalCondition(param, columnId, comparisonType);
344 break;
345 }
346 default:
347 DbException.throwInternalError("type=" + unionType);
348 }
349 }
350
351 public String getPlanSQL() {
352 StringBuilder buff = new StringBuilder();
353 buff.append('(').append(left.getPlanSQL()).append(')');
354 switch (unionType) {
355 case UNION_ALL:
356 buff.append("\nUNION ALL\n");
357 break;
358 case UNION:
359 buff.append("\nUNION\n");
360 break;
361 case INTERSECT:
362 buff.append("\nINTERSECT\n");
363 break;
364 case EXCEPT:
365 buff.append("\nEXCEPT\n");
366 break;
367 default:
368 DbException.throwInternalError("type=" + unionType);
369 }
370 buff.append('(').append(right.getPlanSQL()).append(')');
371 Expression[] exprList = expressions.toArray(new Expression[expressions.size()]);
372 if (sort != null) {
373 buff.append("\nORDER BY ").append(sort.getSQL(exprList, exprList.length));
374 }
375 if (limitExpr != null) {
376 buff.append("\nLIMIT ").append(StringUtils.unEnclose(limitExpr.getSQL()));
377 if (offsetExpr != null) {
378 buff.append("\nOFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL()));
379 }
380 }
381 if (sampleSize != 0) {
382 buff.append("\nSAMPLE_SIZE ").append(sampleSize);
383 }
384 if (isForUpdate) {
385 buff.append("\nFOR UPDATE");
386 }
387 return buff.toString();
388 }
389
390 public LocalResult query(int limit, ResultTarget target) {
391 // union doesn't always know the parameter list of the left and right queries
392 return queryWithoutCache(limit, target);
393 }
394
395 public boolean isEverything(ExpressionVisitor visitor) {
396 return left.isEverything(visitor) && right.isEverything(visitor);
397 }
398
399 public boolean isReadOnly() {
400 return left.isReadOnly() && right.isReadOnly();
401 }
402
403 public void updateAggregate(Session s) {
404 left.updateAggregate(s);
405 right.updateAggregate(s);
406 }
407
408 public void fireBeforeSelectTriggers() {
409 left.fireBeforeSelectTriggers();
410 right.fireBeforeSelectTriggers();
411 }
412
413 public int getType() {
414 return CommandInterface.SELECT;
415 }
416
417 public boolean allowGlobalConditions() {
418 return left.allowGlobalConditions() && right.allowGlobalConditions();
419 }
420
421 }
422