69
import org.hsqldb.HsqlNameManager.HsqlName;
70
import org.hsqldb.lib.HashMap;
71
import org.hsqldb.lib.HashSet;
72
import org.hsqldb.lib.HsqlArrayList;
73
import org.hsqldb.lib.Iterator;
75
// fredt@users 20010701 - patch 1.6.1 by hybris
76
// basic implementation of LIMIT n m
77
// fredt@users 20020130 - patch 471710 by fredt - LIMIT rewritten
78
// for SELECT LIMIT n m DISTINCT
79
// fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
80
// type and logging attributes of sIntotable
81
// fredt@users 20020230 - patch 495938 by johnhobs@users - GROUP BY order
82
// fred@users 20020522 - patch 1.7.0 - aggregate functions with DISTINCT
83
// rougier@users 20020522 - patch 552830 - COUNT(DISTINCT)
84
// fredt@users 20020804 - patch 580347 by dkkopp - view speedup
85
// tony_lai@users 20021020 - patch 1.7.2 - improved aggregates and HAVING
86
// boucherb@users 20030811 - patch 1.7.2 - prepared statement support
87
// fredt@users 20031012 - patch 1.7.2 - better OUTER JOIN implementation
88
// fredt@users 20031012 - patch 1.7.2 - SQL standard ORDER BY with UNION and other set queries
89
// fredt@users 200408xx - patch 1.7.2 - correct evaluation of the precedence of nested UNION and other set query
92
* The compiled representation of an SQL SELECT.
94
* Extended in successive versions of HSQLDB.
96
* @author Thomas Mueller (Hypersonic SQL Group)
98
* @since Hypersonic SQL
102
boolean isDistinctSelect;
103
boolean isAggregated;
104
private boolean isGrouped;
105
private HashSet groupColumnNames;
106
TableFilter[] tFilter;
107
Expression limitCondition;
108
Expression queryCondition; // null means no condition
109
Expression havingCondition; // null means none
110
Expression[] exprColumns; // 'result', 'group' and 'order' columns
111
int iResultLen; // number of columns that are 'result'
112
int iGroupLen; // number of columns that are 'group'
113
int iHavingLen; // number of columns that are 'group'
114
int iOrderLen; // number of columns that are 'order'
117
boolean sortUnion; // if true, sort the result of the full union
118
HsqlName sIntoTable; // null means not select..into
120
Select[] unionArray; // only set in the first Select in a union chain
121
int unionMaxDepth; // max unionDepth in chain
122
Select unionSelect; // null means no union select
125
static final int NOUNION = 0,
130
private boolean simpleLimit; // true if maxrows can be uses as is
131
Result.ResultMetaData resultMetaData;
136
* Map the column aliases to expressions in order to resolve alias names
140
HashMap getColumnAliases() {
142
HashMap aliasMap = new HashMap();
144
for (int i = 0; i < iResultLen; i++) {
145
String alias = exprColumns[i].getAlias();
148
aliasMap.put(alias, exprColumns[i]);
159
* @throws HsqlException
161
void resolve(Session session) throws HsqlException {
164
resolveTypes(session);
165
setFilterConditions(session);
172
* @throws HsqlException
174
private void resolveTables() throws HsqlException {
176
// replace the aliases with expressions
177
for (int i = iResultLen; i < exprColumns.length; i++) {
178
if (exprColumns[i].exprType == Expression.COLUMN) {
179
if (exprColumns[i].joinedTableColumnIndex == -1) {
180
boolean descending = exprColumns[i].isDescending();
183
exprColumns[i].getExpressionForAlias(exprColumns,
187
exprColumns[i].setDescending();
191
exprColumns[i].replaceAliases(exprColumns, iResultLen);
195
if (queryCondition != null) {
196
queryCondition.replaceAliases(exprColumns, iResultLen);
199
int len = tFilter.length;
201
for (int i = 0; i < len; i++) {
202
resolveTables(tFilter[i]);
207
* Sets the types of all the expressions that have so far resolved.
209
* @throws HsqlException
211
void resolveTypes(Session session) throws HsqlException {
213
int len = exprColumns.length;
215
for (int i = 0; i < len; i++) {
216
exprColumns[i].resolveTypes(session);
219
if (queryCondition != null) {
220
queryCondition.resolveTypes(session);
224
void resolveTablesUnion(TableFilter f) throws HsqlException {
226
if (unionArray == null) {
229
for (int i = 0; i < unionArray.length; i++) {
230
unionArray[i].resolveTables(f);
236
* Resolves the tables for all the Expression in the Select object
237
* if it is possible to do so with the given TableFilter.
241
* @throws HsqlException
243
void resolveTables(TableFilter f) throws HsqlException {
245
int len = exprColumns.length;
247
for (int i = 0; i < len; i++) {
248
exprColumns[i].resolveTables(f);
251
if (queryCondition != null) {
252
queryCondition.resolveTables(f);
256
private void setFilterConditions(Session session) throws HsqlException {
258
if (queryCondition == null) {
262
for (int i = 0; i < tFilter.length; i++) {
263
tFilter[i].setConditions(session, queryCondition);
268
* Check all Expression have resolved. Return true or false as a result.
269
* Throw if false and check parameter is true.
271
* @throws HsqlException
273
boolean checkResolved(boolean check) throws HsqlException {
275
boolean result = true;
276
int len = exprColumns.length;
278
for (int i = 0; i < len; i++) {
279
result = result && exprColumns[i].checkResolved(check);
282
if (queryCondition != null) {
283
result = result && queryCondition.checkResolved(check);
286
if (havingCondition != null) {
287
result = result && havingCondition.checkResolved(check);
290
for (int i = 0; i < tFilter.length; i++) {
291
if (tFilter[i].filterIndex == null) {
292
tFilter[i].filterIndex =
293
tFilter[i].filterTable.getPrimaryIndex();
301
* Removes all the TableFilters from the Expressions.
303
* @throws HsqlException
306
void removeFilters() throws HsqlException {
308
int len = eColumn.length;
310
for (int i = 0; i < len; i++) {
311
eColumn[i].removeFilters();
314
if (eCondition != null) {
315
eCondition.removeFilters();
321
* Returns a single value result or throws if the result has more than
322
* one row with one value.
324
* @param type data type
325
* @param session context
326
* @return the single valued result
327
* @throws HsqlException
329
Object getValue(Session session, int type) throws HsqlException {
333
Result r = getResult(session, 2); // 2 records are required for test
334
int size = r.getSize();
335
int len = r.getColumnCount();
340
} else if (size == 1) {
341
Object o = r.rRoot.data[0];
343
return r.metaData.colTypes[0] == type ? o
344
: Column.convertObject(
347
throw Trace.error(Trace.CARDINALITY_VIOLATION_NO_SUBCLASS);
352
Trace.error(Trace.CARDINALITY_VIOLATION_NO_SUBCLASS);
354
throw new HsqlInternalException(e);
358
* Resolves expressions and pepares thre metadata for the result.
360
void prepareResult(Session session) throws HsqlException {
362
resolveAll(session, true);
364
if (iGroupLen > 0) { // has been set in Parser
366
groupColumnNames = new HashSet();
368
for (int i = iResultLen; i < iResultLen + iGroupLen; i++) {
370
// MarcH: this is wrong for a CASE WHEN statement in a SELECT CASE WHEN ...,<something aggregate> statement
371
// collectColumnName collects no columns if exprColumns[i]'s expressiontype is Expression.CASEWHEN
372
// collectAllColumnNames collects all columns used in the CASE WHEN statement
373
// exprColumns[i].collectColumnName(groupColumnNames);
374
exprColumns[i].collectAllColumnNames(groupColumnNames);
378
int len = exprColumns.length;
380
resultMetaData = new Result.ResultMetaData(len);
382
Result.ResultMetaData rmd = resultMetaData;
384
// tony_lai@users having
385
int groupByStart = iResultLen;
386
int groupByEnd = groupByStart + iGroupLen;
387
int orderByStart = groupByEnd + iHavingLen;
388
int orderByEnd = orderByStart + iOrderLen;
390
for (int i = 0; i < len; i++) {
391
Expression e = exprColumns[i];
393
rmd.colTypes[i] = e.getDataType();
394
rmd.colSizes[i] = e.getColumnSize();
395
rmd.colScales[i] = e.getColumnScale();
397
if (e.isAggregate()) {
401
if (i >= groupByStart && i < groupByEnd
402
&&!exprColumns[i].canBeInGroupBy()) {
403
Trace.error(Trace.INVALID_GROUP_BY, exprColumns[i]);
406
if (i >= groupByEnd && i < groupByEnd + iHavingLen
407
&&!exprColumns[i].isConditional()) {
408
Trace.error(Trace.INVALID_HAVING, exprColumns[i]);
411
if (i >= orderByStart && i < orderByEnd
412
&&!exprColumns[i].canBeInOrderBy()) {
413
Trace.error(Trace.INVALID_ORDER_BY, exprColumns[i]);
416
if (i < iResultLen) {
417
rmd.colLabels[i] = e.getAlias();
418
rmd.isLabelQuoted[i] = e.isAliasQuoted();
419
rmd.schemaNames[i] = e.getTableSchemaName();
420
rmd.tableNames[i] = e.getTableName();
421
rmd.colNames[i] = e.getColumnName();
423
if (rmd.isTableColumn(i)) {
424
rmd.colNullable[i] = e.nullability;
425
rmd.isIdentity[i] = e.isIdentity;
426
rmd.isWritable[i] = e.isWritable;
429
rmd.classNames[i] = e.getValueClassName();
433
checkAggregateOrGroupByColumns(0, iResultLen);
434
checkAggregateOrGroupByColumns(groupByEnd, orderByStart);
435
checkAggregateOrGroupByColumns(orderByStart, orderByEnd);
438
simpleLimit = (isDistinctSelect == false && isGrouped == false
439
&& unionSelect == null && iOrderLen == 0);
443
* This is called externally only on the first Select in a UNION chain.
445
void prepareUnions() throws HsqlException {
449
for (Select current = this; current != null;
450
current = current.unionSelect, count++) {}
453
if (unionDepth != 0) {
454
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
460
unionArray = new Select[count];
463
for (Select current = this; current != null;
464
current = current.unionSelect, count++) {
465
unionArray[count] = current;
466
unionMaxDepth = current.unionDepth > unionMaxDepth
471
if (unionArray[unionArray.length - 1].unionDepth != 0) {
472
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
477
* Returns the result of executing this Select.
479
* @param maxrows may be 0 to indicate no limit on the number of rows.
480
* Positive values limit the size of the result set.
481
* @return the result of executing this Select
482
* @throws HsqlException if a database access error occurs
484
Result getResult(Session session, int maxrows) throws HsqlException {
488
if (unionArray == null) {
489
r = getSingleResult(session, maxrows);
491
r = getResultMain(session);
494
sortResult(session, r);
495
r.trimResult(getLimitStart(), getLimitCount(maxrows));
499
// fredt - now there is no need for the sort and group columns
500
r.setColumnCount(iResultLen);
505
private Result getResultMain(Session session) throws HsqlException {
507
Result[] unionResults = new Result[unionArray.length];
509
for (int i = 0; i < unionArray.length; i++) {
510
unionResults[i] = unionArray[i].getSingleResult(session,
514
for (int depth = unionMaxDepth; depth >= 0; depth--) {
515
for (int pass = 0; pass < 2; pass++) {
516
for (int i = 0; i < unionArray.length - 1; i++) {
517
if (unionResults[i] != null
518
&& unionArray[i].unionDepth >= depth) {
520
&& unionArray[i].unionType
521
!= Select.INTERSECT) {
526
&& unionArray[i].unionType
527
== Select.INTERSECT) {
531
int nextIndex = i + 1;
533
for (; nextIndex < unionArray.length; nextIndex++) {
534
if (unionResults[nextIndex] != null) {
539
if (nextIndex == unionArray.length) {
543
unionArray[i].mergeResults(session, unionResults[i],
544
unionResults[nextIndex]);
546
unionResults[nextIndex] = unionResults[i];
547
unionResults[i] = null;
553
return unionResults[unionResults.length - 1];
557
* Merges the second result into the first using the unionMode
560
private void mergeResults(Session session, Result first,
561
Result second) throws HsqlException {
566
first.append(second);
567
first.removeDuplicates(session, iResultLen);
571
first.append(second);
575
first.removeDifferent(session, second, iResultLen);
579
first.removeSecond(session, second, iResultLen);
584
int getLimitStart() throws HsqlException {
586
if (limitCondition != null) {
587
Integer limit = (Integer) limitCondition.getArg().getValue(null);
590
return limit.intValue();
598
* For SELECT LIMIT n m ....
599
* finds cases where the result does not have to be fully built and
600
* returns an adjusted rowCount with LIMIT params.
602
int getLimitCount(int rowCount) throws HsqlException {
606
if (limitCondition != null) {
607
Integer limit = (Integer) limitCondition.getArg2().getValue(null);
610
limitCount = limit.intValue();
614
if (rowCount != 0 && (limitCount == 0 || rowCount < limitCount)) {
615
limitCount = rowCount;
622
* translate the rowCount into total number of rows needed from query,
623
* including any rows skipped at the beginning
625
int getMaxRowCount(int rowCount) throws HsqlException {
627
int limitStart = getLimitStart();
628
int limitCount = getLimitCount(rowCount);
631
rowCount = Integer.MAX_VALUE;
634
rowCount = limitCount;
637
if (rowCount == 0 || rowCount > Integer.MAX_VALUE - limitStart) {
638
rowCount = Integer.MAX_VALUE;
640
rowCount += limitStart;
647
private Result getSingleResult(Session session,
648
int rowCount) throws HsqlException {
650
if (resultMetaData == null) {
651
prepareResult(session);
654
Result r = buildResult(session, getMaxRowCount(rowCount));
656
// the result is perhaps wider (due to group and order by)
657
// so use the visible columns to remove duplicates
658
if (isDistinctSelect) {
659
r.removeDuplicates(session, iResultLen);
663
sortResult(session, r);
664
r.trimResult(getLimitStart(), getLimitCount(rowCount));
670
private void prepareSort() {
672
if (iOrderLen == 0) {
676
sortOrder = new int[iOrderLen];
677
sortDirection = new int[iOrderLen];
679
int startCol = iResultLen + iGroupLen + iHavingLen;
681
for (int i = startCol, j = 0; j < iOrderLen; i++, j++) {
684
// fredt - when a union, use the visible select columns for sort comparison
685
// also whenever a column alias is used
686
if (exprColumns[i].joinedTableColumnIndex != -1) {
687
colindex = exprColumns[i].joinedTableColumnIndex;
690
sortOrder[j] = colindex;
691
sortDirection[j] = exprColumns[i].isDescending() ? -1
696
private void sortResult(Session session, Result r) throws HsqlException {
698
if (iOrderLen == 0) {
702
r.sortResult(session, sortOrder, sortDirection);
706
* Check result columns for aggregate or group by violation.
707
* If any result column is aggregated, then all result columns need to be
708
* aggregated, unless it is included in the group by clause.
710
private void checkAggregateOrGroupByColumns(int start,
69
import org.hsqldb.HsqlNameManager.HsqlName;
70
import org.hsqldb.lib.HashMap;
71
import org.hsqldb.lib.HashSet;
72
import org.hsqldb.lib.HsqlArrayList;
73
import org.hsqldb.lib.Iterator;
75
// fredt@users 20010701 - patch 1.6.1 by hybris
76
// basic implementation of LIMIT n m
77
// fredt@users 20020130 - patch 471710 by fredt - LIMIT rewritten
78
// for SELECT LIMIT n m DISTINCT
79
// fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
80
// type and logging attributes of sIntotable
81
// fredt@users 20020230 - patch 495938 by johnhobs@users - GROUP BY order
82
// fred@users 20020522 - patch 1.7.0 - aggregate functions with DISTINCT
83
// rougier@users 20020522 - patch 552830 - COUNT(DISTINCT)
84
// fredt@users 20020804 - patch 580347 by dkkopp - view speedup
85
// tony_lai@users 20021020 - patch 1.7.2 - improved aggregates and HAVING
86
// boucherb@users 20030811 - patch 1.7.2 - prepared statement support
87
// fredt@users 20031012 - patch 1.7.2 - better OUTER JOIN implementation
88
// fredt@users 20031012 - patch 1.7.2 - SQL standard ORDER BY with UNION and other set queries
89
// fredt@users 200408xx - patch 1.7.2 - correct evaluation of the precedence of nested UNION and other set query
92
* The compiled representation of an SQL SELECT.
94
* Extended in successive versions of HSQLDB.
96
* @author Thomas Mueller (Hypersonic SQL Group)
98
* @since Hypersonic SQL
102
boolean isDistinctSelect;
103
boolean isAggregated;
104
private boolean isGrouped;
105
private HashSet groupColumnNames;
106
TableFilter[] tFilter;
107
Expression limitCondition;
108
Expression queryCondition; // null means no condition
109
Expression havingCondition; // null means none
110
Expression[] exprColumns; // 'result', 'group' and 'order' columns
111
int iResultLen; // number of columns that are 'result'
112
int iGroupLen; // number of columns that are 'group'
113
int iHavingLen; // number of columns that are 'group'
114
int iOrderLen; // number of columns that are 'order'
117
boolean sortUnion; // if true, sort the result of the full union
118
HsqlName sIntoTable; // null means not select..into
120
Select[] unionArray; // only set in the first Select in a union chain
121
int unionMaxDepth; // max unionDepth in chain
122
Select unionSelect; // null means no union select
125
static final int NOUNION = 0,
130
private boolean simpleLimit; // true if maxrows can be uses as is
131
Result.ResultMetaData resultMetaData;
136
* Map the column aliases to expressions in order to resolve alias names
140
HashMap getColumnAliases() {
142
HashMap aliasMap = new HashMap();
144
for (int i = 0; i < iResultLen; i++) {
145
String alias = exprColumns[i].getAlias();
148
aliasMap.put(alias, exprColumns[i]);
159
* @throws HsqlException
161
void resolve(Session session) throws HsqlException {
164
resolveTypes(session);
165
setFilterConditions(session);
172
* @throws HsqlException
174
private void resolveTables() throws HsqlException {
176
// replace the aliases with expressions
177
for (int i = iResultLen; i < exprColumns.length; i++) {
178
if (exprColumns[i].getType() == Expression.COLUMN) {
179
if (exprColumns[i].joinedTableColumnIndex == -1) {
180
boolean descending = exprColumns[i].isDescending();
183
exprColumns[i].getExpressionForAlias(exprColumns,
187
exprColumns[i].setDescending();
191
exprColumns[i].replaceAliases(exprColumns, iResultLen);
195
if (queryCondition != null) {
196
queryCondition.replaceAliases(exprColumns, iResultLen);
199
int len = tFilter.length;
201
for (int i = 0; i < len; i++) {
202
resolveTables(tFilter[i]);
207
* Converts the types of the columns in set operations to those in the first
210
void resolveUnionColumnTypes() throws HsqlException {
212
if (unionSelect != null) {
213
if (unionSelect.iResultLen != iResultLen) {
214
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
217
for (int i = 0; i < iResultLen; i++) {
218
Expression e = exprColumns[i];
220
if (!e.isTypeEqual(unionSelect.exprColumns[i])) {
221
unionSelect.exprColumns[i] =
222
new Expression(unionSelect.exprColumns[i],
223
e.getDataType(), e.getColumnSize(),
231
* Sets the types of all the expressions that have so far resolved.
233
* @throws HsqlException
235
void resolveTypes(Session session) throws HsqlException {
237
int len = exprColumns.length;
239
for (int i = 0; i < len; i++) {
240
exprColumns[i].resolveTypes(session);
243
if (queryCondition != null) {
244
queryCondition.resolveTypes(session);
248
void resolveTablesUnion(TableFilter f) throws HsqlException {
250
if (unionArray == null) {
253
for (int i = 0; i < unionArray.length; i++) {
254
unionArray[i].resolveTables(f);
260
* Resolves the tables for all the Expression in the Select object
261
* if it is possible to do so with the given TableFilter.
265
* @throws HsqlException
267
void resolveTables(TableFilter f) throws HsqlException {
269
int len = exprColumns.length;
271
for (int i = 0; i < len; i++) {
272
exprColumns[i].resolveTables(f);
275
if (queryCondition != null) {
276
queryCondition.resolveTables(f);
280
private void setFilterConditions(Session session) throws HsqlException {
282
if (queryCondition == null) {
286
for (int i = 0; i < tFilter.length; i++) {
287
tFilter[i].setConditions(session, queryCondition);
292
* Check all Expression have resolved. Return true or false as a result.
293
* Throw if false and check parameter is true.
295
* @throws HsqlException
297
boolean checkResolved(boolean check) throws HsqlException {
299
boolean result = true;
300
int len = exprColumns.length;
302
for (int i = 0; i < len; i++) {
303
result = result && exprColumns[i].checkResolved(check);
306
if (queryCondition != null) {
307
result = result && queryCondition.checkResolved(check);
310
if (havingCondition != null) {
311
result = result && havingCondition.checkResolved(check);
314
for (int i = 0; i < tFilter.length; i++) {
315
if (tFilter[i].filterIndex == null) {
316
tFilter[i].filterIndex =
317
tFilter[i].filterTable.getPrimaryIndex();
325
* Removes all the TableFilters from the Expressions.
327
* @throws HsqlException
330
void removeFilters() throws HsqlException {
332
int len = eColumn.length;
334
for (int i = 0; i < len; i++) {
335
eColumn[i].removeFilters();
338
if (eCondition != null) {
339
eCondition.removeFilters();
345
* Returns a single value result or throws if the result has more than
346
* one row with one value.
348
* @param type data type
349
* @param session context
350
* @return the single valued result
351
* @throws HsqlException
353
Object getValue(Session session, int type) throws HsqlException {
357
Result r = getResult(session, 2); // 2 records are required for test
358
int size = r.getSize();
359
int len = r.getColumnCount();
364
} else if (size == 1) {
365
Object o = r.rRoot.data[0];
367
return r.metaData.colTypes[0] == type ? o
368
: Column.convertObject(
371
throw Trace.error(Trace.CARDINALITY_VIOLATION_NO_SUBCLASS);
376
Trace.error(Trace.CARDINALITY_VIOLATION_NO_SUBCLASS);
378
throw new HsqlInternalException(e);
382
* Resolves expressions and pepares thre metadata for the result.
384
void prepareResult(Session session) throws HsqlException {
386
resolveAll(session, true);
388
if (iGroupLen > 0) { // has been set in Parser
390
groupColumnNames = new HashSet();
392
for (int i = iResultLen; i < iResultLen + iGroupLen; i++) {
394
// MarcH: this is wrong for a CASE WHEN statement in a SELECT CASE WHEN ...,<something aggregate> statement
395
// collectColumnName collects no columns if exprColumns[i]'s expressiontype is Expression.CASEWHEN
396
// collectAllColumnNames collects all columns used in the CASE WHEN statement
397
// exprColumns[i].collectColumnName(groupColumnNames);
398
exprColumns[i].collectAllColumnNames(groupColumnNames);
402
int len = exprColumns.length;
404
resultMetaData = new Result.ResultMetaData(len);
406
Result.ResultMetaData rmd = resultMetaData;
408
// tony_lai@users having
409
int groupByStart = iResultLen;
410
int groupByEnd = groupByStart + iGroupLen;
411
int orderByStart = groupByEnd + iHavingLen;
412
int orderByEnd = orderByStart + iOrderLen;
414
for (int i = 0; i < len; i++) {
415
Expression e = exprColumns[i];
417
rmd.colTypes[i] = e.getDataType();
418
rmd.colSizes[i] = e.getColumnSize();
419
rmd.colScales[i] = e.getColumnScale();
421
if (e.isAggregate()) {
425
if (i >= groupByStart && i < groupByEnd
426
&&!exprColumns[i].canBeInGroupBy()) {
427
Trace.error(Trace.INVALID_GROUP_BY, exprColumns[i]);
430
if (i >= groupByEnd && i < groupByEnd + iHavingLen
431
&&!exprColumns[i].isConditional()) {
432
Trace.error(Trace.INVALID_HAVING, exprColumns[i]);
435
if (i >= orderByStart && i < orderByEnd
436
&&!exprColumns[i].canBeInOrderBy()) {
437
Trace.error(Trace.INVALID_ORDER_BY, exprColumns[i]);
440
if (i < iResultLen) {
441
rmd.colLabels[i] = e.getAlias();
442
rmd.isLabelQuoted[i] = e.isAliasQuoted();
443
rmd.schemaNames[i] = e.getTableSchemaName();
444
rmd.tableNames[i] = e.getTableName();
445
rmd.colNames[i] = e.getColumnName();
447
if (rmd.isTableColumn(i)) {
448
rmd.colNullable[i] = e.nullability;
449
rmd.isIdentity[i] = e.isIdentity;
450
rmd.isWritable[i] = e.isWritable;
453
rmd.classNames[i] = e.getValueClassName();
458
checkAggregateOrGroupByColumns(0, iResultLen);
461
checkAggregateOrGroupByColumns(groupByEnd, orderByStart);
464
checkAggregateOrGroupByOrderColumns(orderByStart, orderByEnd);
467
simpleLimit = (isDistinctSelect == false && isGrouped == false
468
&& unionSelect == null && iOrderLen == 0);
472
* This is called externally only on the first Select in a UNION chain.
474
void prepareUnions() throws HsqlException {
478
for (Select current = this; current != null;
479
current = current.unionSelect, count++) {}
482
if (unionDepth != 0) {
483
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
489
unionArray = new Select[count];
492
for (Select current = this; current != null;
493
current = current.unionSelect, count++) {
494
unionArray[count] = current;
495
unionMaxDepth = current.unionDepth > unionMaxDepth
500
if (unionArray[unionArray.length - 1].unionDepth != 0) {
501
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
506
* Returns the result of executing this Select.
508
* @param maxrows may be 0 to indicate no limit on the number of rows.
509
* Positive values limit the size of the result set.
510
* @return the result of executing this Select
511
* @throws HsqlException if a database access error occurs
513
Result getResult(Session session, int maxrows) throws HsqlException {
517
if (unionArray == null) {
518
r = getSingleResult(session, maxrows);
520
r = getResultMain(session);
523
sortResult(session, r);
524
r.trimResult(getLimitStart(session),
525
getLimitCount(session, maxrows));
529
// fredt - now there is no need for the sort and group columns
530
r.setColumnCount(iResultLen);
535
private Result getResultMain(Session session) throws HsqlException {
537
Result[] unionResults = new Result[unionArray.length];
539
for (int i = 0; i < unionArray.length; i++) {
540
unionResults[i] = unionArray[i].getSingleResult(session,
544
for (int depth = unionMaxDepth; depth >= 0; depth--) {
545
for (int pass = 0; pass < 2; pass++) {
546
for (int i = 0; i < unionArray.length - 1; i++) {
547
if (unionResults[i] != null
548
&& unionArray[i].unionDepth >= depth) {
550
&& unionArray[i].unionType
551
!= Select.INTERSECT) {
556
&& unionArray[i].unionType
557
== Select.INTERSECT) {
561
int nextIndex = i + 1;
563
for (; nextIndex < unionArray.length; nextIndex++) {
564
if (unionResults[nextIndex] != null) {
569
if (nextIndex == unionArray.length) {
573
unionArray[i].mergeResults(session, unionResults[i],
574
unionResults[nextIndex]);
576
unionResults[nextIndex] = unionResults[i];
577
unionResults[i] = null;
583
return unionResults[unionResults.length - 1];
587
* Merges the second result into the first using the unionMode
590
private void mergeResults(Session session, Result first,
591
Result second) throws HsqlException {
596
first.append(second);
597
first.removeDuplicates(session, iResultLen);
601
first.append(second);
605
first.removeDifferent(session, second, iResultLen);
609
first.removeSecond(session, second, iResultLen);
614
int getLimitStart(Session session) throws HsqlException {
616
if (limitCondition != null) {
618
(Integer) limitCondition.getArg().getValue(session);
621
return limit.intValue();
629
* For SELECT LIMIT n m ....
630
* finds cases where the result does not have to be fully built and
631
* returns an adjusted rowCount with LIMIT params.
633
int getLimitCount(Session session, int rowCount) throws HsqlException {
637
if (limitCondition != null) {
639
(Integer) limitCondition.getArg2().getValue(session);
642
limitCount = limit.intValue();
646
if (rowCount != 0 && (limitCount == 0 || rowCount < limitCount)) {
647
limitCount = rowCount;
654
* translate the rowCount into total number of rows needed from query,
655
* including any rows skipped at the beginning
657
int getMaxRowCount(Session session, int rowCount) throws HsqlException {
659
int limitStart = getLimitStart(session);
660
int limitCount = getLimitCount(session, rowCount);
663
rowCount = Integer.MAX_VALUE;
666
rowCount = limitCount;
669
if (rowCount == 0 || rowCount > Integer.MAX_VALUE - limitStart) {
670
rowCount = Integer.MAX_VALUE;
672
rowCount += limitStart;
679
private Result getSingleResult(Session session,
680
int rowCount) throws HsqlException {
682
if (resultMetaData == null) {
683
prepareResult(session);
686
Result r = buildResult(session, getMaxRowCount(session, rowCount));
688
// the result is perhaps wider (due to group and order by)
689
// so use the visible columns to remove duplicates
690
if (isDistinctSelect) {
691
r.removeDuplicates(session, iResultLen);
695
sortResult(session, r);
696
r.trimResult(getLimitStart(session),
697
getLimitCount(session, rowCount));
703
private void prepareSort() {
705
if (iOrderLen == 0) {
709
sortOrder = new int[iOrderLen];
710
sortDirection = new int[iOrderLen];
712
int startCol = iResultLen + iGroupLen + iHavingLen;
714
for (int i = startCol, j = 0; j < iOrderLen; i++, j++) {
717
// fredt - when a union, use the visible select columns for sort comparison
718
// also whenever a column alias is used
719
if (exprColumns[i].joinedTableColumnIndex != -1) {
720
colindex = exprColumns[i].joinedTableColumnIndex;
723
sortOrder[j] = colindex;
724
sortDirection[j] = exprColumns[i].isDescending() ? -1
729
private void sortResult(Session session, Result r) throws HsqlException {
731
if (iOrderLen == 0) {
735
r.sortResult(session, sortOrder, sortDirection);
739
* Check result columns for aggregate or group by violation.
740
* If any result column is aggregated, then all result columns need to be
741
* aggregated, unless it is included in the group by clause.
743
private void checkAggregateOrGroupByColumns(int start,
744
int end) throws HsqlException {
747
HsqlArrayList colExps = new HsqlArrayList();
749
for (int i = start; i < end; i++) {
750
exprColumns[i].collectInGroupByExpressions(colExps);
753
for (int i = 0, size = colExps.size(); i < size; i++) {
754
Expression exp = (Expression) colExps.get(i);
756
if (inAggregateOrGroupByClause(exp)) {
760
throw Trace.error(Trace.NOT_IN_AGGREGATE_OR_GROUP_BY, exp);
765
private void checkAggregateOrGroupByOrderColumns(int start,
711
766
int end) throws HsqlException {
768
checkAggregateOrGroupByColumns(start, end);
770
if (start < end && isDistinctSelect) {
714
771
HsqlArrayList colExps = new HsqlArrayList();
716
773
for (int i = start; i < end; i++) {
720
777
for (int i = 0, size = colExps.size(); i < size; i++) {
721
778
Expression exp = (Expression) colExps.get(i);
723
if (inAggregateOrGroupByClause(exp)) {
727
if (isDistinctSelect) {
729
Trace.INVALID_ORDER_BY_IN_DISTINCT_SELECT, exp);
731
throw Trace.error(Trace.NOT_IN_AGGREGATE_OR_GROUP_BY,
739
* Check if the given expression is acceptable in a select that may
740
* include aggregate function and/or group by clause.
742
* The expression is acceptable if:
744
* <LI>The select does not containt any aggregate function;
745
* <LI>The expression itself can be included in an aggregate select;
746
* <LI>The expression is defined in the group by clause;
747
* <LI>All the columns in the expression are defined in the group by clause;
750
private boolean inAggregateOrGroupByClause(Expression exp) {
753
return isSimilarIn(exp, iResultLen, iResultLen + iGroupLen)
754
|| allColumnsAreDefinedIn(exp, groupColumnNames);
755
} else if (isAggregated) {
756
return exp.canBeInAggregate();
757
} else if (isDistinctSelect) {
758
return isSimilarIn(exp, 0, iResultLen);
765
* Check if the given expression is similar to any of the eColumn
766
* expressions within the given range.
768
private boolean isSimilarIn(Expression exp, int start, int end) {
770
for (int i = start; i < end; i++) {
771
if (exp.similarTo(exprColumns[i])) {
780
* Check if all the column names used in the given expression are defined
781
* in the given defined column names.
783
static boolean allColumnsAreDefinedIn(Expression exp,
784
HashSet definedColumns) {
786
HashSet colNames = new HashSet();
788
exp.collectAllColumnNames(colNames);
790
if ((colNames.size() > 0) && (definedColumns == null)) {
794
Iterator i = colNames.iterator();
796
while (i.hasNext()) {
797
if (!definedColumns.contains(i.next())) {
805
// fredt@users 20030810 - patch 1.7.2 - OUTER JOIN rewrite
806
private Result buildResult(Session session,
807
int limitcount) throws HsqlException {
809
GroupedResult gResult = new GroupedResult(this, resultMetaData);
810
final int len = exprColumns.length;
811
final int filter = tFilter.length;
812
boolean[] first = new boolean[filter];
813
boolean[] outerused = new boolean[filter];
816
// fredt - shortcut needed by OpenOffice to speed up empty query processing for metadata
817
boolean notempty = !(queryCondition != null
818
&& queryCondition.isFixedConditional()
819
&&!queryCondition.testCondition(session));
821
while (notempty && level >= 0) {
824
TableFilter t = tFilter[level];
829
found = t.findFirst(session);
831
// if outer join, and no inner result, get next outer row
832
// nonJoinIsNull disallows getting the next outer row in some circumstances
833
outerused[level] = outerfound = t.isOuterJoin &&!found
836
&& t.nextOuter(session);
837
first[level] = found;
839
found = t.next(session);
840
outerused[level] = outerfound = t.isOuterJoin &&!found
844
&& t.nextOuter(session);
845
first[level] = found;
848
if (!found &&!outerfound) {
854
if (level < filter - 1) {
859
while (outerused[level]) {
860
outerused[level--] = false;
865
if (queryCondition == null
866
|| queryCondition.testCondition(session)) {
868
Object[] row = new Object[len];
870
// gets the group by column values first.
871
for (int i = gResult.groupBegin; i < gResult.groupEnd;
873
row[i] = exprColumns[i].getValue(session);
876
row = gResult.getRow(row);
878
// Get all other values
879
for (int i = 0; i < gResult.groupBegin; i++) {
881
isAggregated && exprColumns[i].isAggregate()
882
? exprColumns[i].updateAggregatingValue(session,
884
: exprColumns[i].getValue(session);
887
for (int i = gResult.groupEnd; i < len; i++) {
889
isAggregated && exprColumns[i].isAggregate()
890
? exprColumns[i].updateAggregatingValue(session,
892
: exprColumns[i].getValue(session);
897
if (gResult.size() >= limitcount) {
900
} catch (HsqlInternalException e) {
906
if (isAggregated &&!isGrouped && gResult.size() == 0) {
907
Object[] row = new Object[len];
909
for (int i = 0; i < len; i++) {
910
row[i] = exprColumns[i].isAggregate() ? null
918
Iterator it = gResult.iterator();
920
while (it.hasNext()) {
921
Object[] row = (Object[]) it.next();
924
for (int i = 0; i < len; i++) {
925
if (exprColumns[i].isAggregate()) {
926
row[i] = exprColumns[i].getAggregatedValue(session,
932
if (iHavingLen > 0) {
934
// The test value, either aggregate or not, is set already.
935
// Removes the row that does not satisfy the HAVING
937
if (!Boolean.TRUE.equals(row[iResultLen + iGroupLen])) {
943
return gResult.getResult();
947
* Skeleton under development. Needs a lot of work.
949
public StringBuffer getDDL() throws HsqlException {
951
StringBuffer sb = new StringBuffer();
953
sb.append(Token.T_SELECT).append(' ');
957
for (int i = 0; i < iResultLen; i++) {
958
sb.append(exprColumns[i].getDDL());
960
if (i < iResultLen - 1) {
965
sb.append(Token.T_FROM);
967
for (int i = 0; i < tFilter.length; i++) {
969
// find out if any expression in any of the filters isInJoin then use this form
970
TableFilter filter = tFilter[i];
972
// if any expression isInJoin
974
if (filter.isOuterJoin) {
975
sb.append(Token.T_FROM).append(' ');
976
sb.append(Token.T_JOIN).append(' ');
979
// eStart and eEnd expressions
982
// otherwise use a comma delimited table list
986
// if there are any expressions that are not isInJoin
987
sb.append(' ').append(Token.T_WHERE).append(' ');
989
for (int i = 0; i < tFilter.length; i++) {
990
TableFilter filter = tFilter[i];
992
// eStart and eEnd expressions that are not isInJoin
996
sb.append(' ').append(Token.T_GROUP).append(' ');
998
for (int i = iResultLen; i < iResultLen + iGroupLen; i++) {
999
sb.append(exprColumns[i].getDDL());
1001
if (i < iResultLen + iGroupLen - 1) {
1007
sb.append(' ').append(Token.T_HAVING).append(' ');
1009
for (int i = iResultLen + iGroupLen;
1010
i < iResultLen + iGroupLen + iHavingLen; i++) {
1011
sb.append(exprColumns[i].getDDL());
1013
if (i < iResultLen + iGroupLen - 1) {
1018
if (unionSelect != null) {
1019
switch (unionType) {
1022
sb.append(' ').append(Token.T_EXCEPT).append(' ');
1026
sb.append(' ').append(Token.T_INTERSECT).append(' ');
1030
sb.append(' ').append(Token.T_UNION).append(' ');
1034
sb.append(' ').append(Token.T_UNION).append(' ').append(
1035
Token.T_ALL).append(' ');
1041
int groupByEnd = iResultLen + iGroupLen;
1042
int orderByStart = groupByEnd + iHavingLen;
1043
int orderByEnd = orderByStart + iOrderLen;
1045
sb.append(' ').append(Token.T_ORDER).append(Token.T_BY).append(' ');
1047
for (int i = orderByStart; i < orderByEnd; i++) {
1048
sb.append(exprColumns[i].getDDL());
1050
if (i < iResultLen + iGroupLen - 1) {
1058
boolean isResolved = false;
1060
boolean resolveAll(Session session, boolean check) throws HsqlException {
1062
boolean result = true;
1070
result = result && checkResolved(check);
1072
if (unionSelect != null) {
1073
if (unionSelect.iResultLen != iResultLen) {
1074
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
1077
unionSelect.resolveAll(session, check);
1080
isResolved = result;
1085
boolean isResolved() {
1089
public String describe(Session session) {
1094
// temporary : it is currently unclear whether this may affect
1095
// later attempts to retrieve an actual result (calls getResult(1)
1096
// in preProcess mode). Thus, toString() probably should not be called
1097
// on Select objects that will actually be used to retrieve results,
1098
// only on Select objects used by EXPLAIN PLAN FOR
1100
getResult(session, 1);
1101
} catch (HsqlException e) {}
1103
sb = new StringBuffer();
1105
sb.append(super.toString()).append("[\n");
1107
if (sIntoTable != null) {
1108
sb.append("into table=[").append(sIntoTable.name).append("]\n");
1111
if (limitCondition != null) {
1112
sb.append("offset=[").append(
1113
limitCondition.getArg().describe(session)).append("]\n");
1114
sb.append("limit=[").append(
1115
limitCondition.getArg2().describe(session)).append("]\n");
1118
sb.append("isDistinctSelect=[").append(isDistinctSelect).append(
1120
sb.append("isGrouped=[").append(isGrouped).append("]\n");
1121
sb.append("isAggregated=[").append(isAggregated).append("]\n");
1122
sb.append("columns=[");
1124
int columns = exprColumns.length - iOrderLen;
1126
for (int i = 0; i < columns; i++) {
1127
sb.append(exprColumns[i].describe(session));
1131
sb.append("tableFilters=[\n");
1133
for (int i = 0; i < tFilter.length; i++) {
1135
sb.append(tFilter[i].describe(session));
1141
temp = queryCondition == null ? "null"
1142
: queryCondition.describe(session);
1144
sb.append("eCondition=[").append(temp).append("]\n");
1146
temp = havingCondition == null ? "null"
1147
: havingCondition.describe(session);
1149
sb.append("havingCondition=[").append(temp).append("]\n");
1150
sb.append("groupColumns=[").append(groupColumnNames).append("]\n");
1152
if (unionSelect != null) {
1153
switch (unionType) {
1156
sb.append(" EXCEPT ");
1160
sb.append(" INTERSECT ");
1164
sb.append(" UNION ");
1168
sb.append(" UNION ALL ");
1172
sb.append(" UNKNOWN SET OPERATION ");
1175
sb.append("[\n").append(unionSelect.describe(session)).append(
1179
return sb.toString();
1182
Result describeResult() {
1185
Result.ResultMetaData rmd;
1188
r = new Result(ResultConstants.DATA, iResultLen);
1191
for (int i = 0; i < iResultLen; i++) {
1193
rmd.colTypes[i] = e.getDataType();
1194
rmd.colSizes[i] = e.getColumnSize();
1195
rmd.colScales[i] = e.getColumnScale();
1196
rmd.colLabels[i] = e.getAlias();
1197
rmd.isLabelQuoted[i] = e.isAliasQuoted();
1198
rmd.tableNames[i] = e.getTableName();
1199
rmd.colNames[i] = e.getColumnName();
1201
if (rmd.isTableColumn(i)) {
1202
rmd.colNullable[i] = e.nullability;
1203
rmd.isIdentity[i] = e.isIdentity;
1204
rmd.isWritable[i] = e.isWritable;
780
if (isSimilarIn(exp, 0, iResultLen)) {
784
throw Trace.error(Trace.INVALID_ORDER_BY_IN_DISTINCT_SELECT,
791
* Check if the given expression is acceptable in a select that may
792
* include aggregate function and/or group by clause.
794
* The expression is acceptable if:
796
* <LI>The select does not containt any aggregate function;
797
* <LI>The expression itself can be included in an aggregate select;
798
* <LI>The expression is defined in the group by clause;
799
* <LI>All the columns in the expression are defined in the group by clause;
802
private boolean inAggregateOrGroupByClause(Expression exp) {
805
return isSimilarIn(exp, iResultLen, iResultLen + iGroupLen)
806
|| allColumnsAreDefinedIn(exp, groupColumnNames);
807
} else if (isAggregated) {
808
return exp.canBeInAggregate();
815
* Check if the given expression is similar to any of the eColumn
816
* expressions within the given range.
818
private boolean isSimilarIn(Expression exp, int start, int end) {
820
for (int i = start; i < end; i++) {
821
if (exp.similarTo(exprColumns[i])) {
830
* Check if all the column names used in the given expression are defined
831
* in the given defined column names.
833
static boolean allColumnsAreDefinedIn(Expression exp,
834
HashSet definedColumns) {
836
HashSet colNames = new HashSet();
838
exp.collectAllColumnNames(colNames);
840
if ((colNames.size() > 0) && (definedColumns == null)) {
844
Iterator i = colNames.iterator();
846
while (i.hasNext()) {
847
if (!definedColumns.contains(i.next())) {
855
// fredt@users 20030810 - patch 1.7.2 - OUTER JOIN rewrite
856
private Result buildResult(Session session,
857
int limitcount) throws HsqlException {
859
GroupedResult gResult = new GroupedResult(this, resultMetaData);
860
final int len = exprColumns.length;
861
final int filter = tFilter.length;
862
boolean[] first = new boolean[filter];
863
boolean[] outerused = new boolean[filter];
866
// fredt - shortcut needed by OpenOffice to speed up empty query processing for metadata
867
boolean notempty = !(queryCondition != null
868
&& queryCondition.isFixedConditional()
869
&&!queryCondition.testCondition(session));
871
while (notempty && level >= 0) {
874
TableFilter t = tFilter[level];
879
found = t.findFirst(session);
881
// if outer join, and no inner result, get next outer row
882
// nonJoinIsNull disallows getting the next outer row in some circumstances
883
outerused[level] = outerfound = t.isOuterJoin &&!found
886
&& t.nextOuter(session);
887
first[level] = found;
889
found = t.next(session);
890
outerused[level] = outerfound = t.isOuterJoin &&!found
894
&& t.nextOuter(session);
895
first[level] = found;
898
if (!found &&!outerfound) {
904
if (level < filter - 1) {
909
while (outerused[level]) {
910
outerused[level--] = false;
915
if (queryCondition == null
916
|| queryCondition.testCondition(session)) {
918
Object[] row = new Object[len];
920
// gets the group by column values first.
921
for (int i = gResult.groupBegin; i < gResult.groupEnd;
923
row[i] = exprColumns[i].getValue(session);
926
row = gResult.getRow(row);
928
// Get all other values
929
for (int i = 0; i < gResult.groupBegin; i++) {
931
isAggregated && exprColumns[i].isAggregate()
932
? exprColumns[i].updateAggregatingValue(session,
934
: exprColumns[i].getValue(session);
937
for (int i = gResult.groupEnd; i < len; i++) {
939
isAggregated && exprColumns[i].isAggregate()
940
? exprColumns[i].updateAggregatingValue(session,
942
: exprColumns[i].getValue(session);
947
if (gResult.size() >= limitcount) {
950
} catch (HsqlInternalException e) {
956
if (isAggregated &&!isGrouped && gResult.size() == 0) {
957
Object[] row = new Object[len];
959
for (int i = 0; i < len; i++) {
960
row[i] = exprColumns[i].isAggregate() ? null
968
Iterator it = gResult.iterator();
970
while (it.hasNext()) {
971
Object[] row = (Object[]) it.next();
974
for (int i = 0; i < len; i++) {
975
if (exprColumns[i].isAggregate()) {
976
row[i] = exprColumns[i].getAggregatedValue(session,
982
if (iHavingLen > 0) {
984
// The test value, either aggregate or not, is set already.
985
// Removes the row that does not satisfy the HAVING
987
if (!Boolean.TRUE.equals(row[iResultLen + iGroupLen])) {
993
return gResult.getResult();
997
* Skeleton under development. Needs a lot of work.
999
public StringBuffer getDDL() throws HsqlException {
1001
StringBuffer sb = new StringBuffer();
1003
sb.append(Token.T_SELECT).append(' ');
1007
for (int i = 0; i < iResultLen; i++) {
1008
sb.append(exprColumns[i].getDDL());
1010
if (i < iResultLen - 1) {
1015
sb.append(Token.T_FROM);
1017
for (int i = 0; i < tFilter.length; i++) {
1019
// find out if any expression in any of the filters isInJoin then use this form
1020
TableFilter filter = tFilter[i];
1022
// if any expression isInJoin
1024
if (filter.isOuterJoin) {
1025
sb.append(Token.T_FROM).append(' ');
1026
sb.append(Token.T_JOIN).append(' ');
1029
// eStart and eEnd expressions
1032
// otherwise use a comma delimited table list
1036
// if there are any expressions that are not isInJoin
1037
sb.append(' ').append(Token.T_WHERE).append(' ');
1039
for (int i = 0; i < tFilter.length; i++) {
1040
TableFilter filter = tFilter[i];
1042
// eStart and eEnd expressions that are not isInJoin
1046
sb.append(' ').append(Token.T_GROUP).append(' ');
1048
for (int i = iResultLen; i < iResultLen + iGroupLen; i++) {
1049
sb.append(exprColumns[i].getDDL());
1051
if (i < iResultLen + iGroupLen - 1) {
1057
sb.append(' ').append(Token.T_HAVING).append(' ');
1059
for (int i = iResultLen + iGroupLen;
1060
i < iResultLen + iGroupLen + iHavingLen; i++) {
1061
sb.append(exprColumns[i].getDDL());
1063
if (i < iResultLen + iGroupLen - 1) {
1068
if (unionSelect != null) {
1069
switch (unionType) {
1072
sb.append(' ').append(Token.T_EXCEPT).append(' ');
1076
sb.append(' ').append(Token.T_INTERSECT).append(' ');
1080
sb.append(' ').append(Token.T_UNION).append(' ');
1084
sb.append(' ').append(Token.T_UNION).append(' ').append(
1085
Token.T_ALL).append(' ');
1091
int groupByEnd = iResultLen + iGroupLen;
1092
int orderByStart = groupByEnd + iHavingLen;
1093
int orderByEnd = orderByStart + iOrderLen;
1095
sb.append(' ').append(Token.T_ORDER).append(Token.T_BY).append(' ');
1097
for (int i = orderByStart; i < orderByEnd; i++) {
1098
sb.append(exprColumns[i].getDDL());
1100
if (i < iResultLen + iGroupLen - 1) {
1108
boolean isResolved = false;
1111
* @todo - post 1.8.0 - review resolve and check resolve -
1112
* determine if isResolved is specific to main query or the full set including UNION
1115
boolean resolveAll(Session session, boolean check) throws HsqlException {
1123
isResolved = checkResolved(check);
1125
if (unionSelect != null) {
1126
if (unionSelect.iResultLen != iResultLen) {
1127
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
1130
for (int i = 0; i < iResultLen; i++) {
1131
Expression e = exprColumns[i];
1133
if (!e.isTypeEqual(unionSelect.exprColumns[i])) {
1134
unionSelect.exprColumns[i] =
1135
new Expression(unionSelect.exprColumns[i],
1136
e.getDataType(), e.getColumnSize(),
1137
e.getColumnScale());
1141
isResolved &= unionSelect.resolveAll(session, check);
1147
boolean isResolved() {
1151
public String describe(Session session) {
1156
// temporary : it is currently unclear whether this may affect
1157
// later attempts to retrieve an actual result (calls getResult(1)
1158
// in preProcess mode). Thus, toString() probably should not be called
1159
// on Select objects that will actually be used to retrieve results,
1160
// only on Select objects used by EXPLAIN PLAN FOR
1162
getResult(session, 1);
1163
} catch (HsqlException e) {}
1165
sb = new StringBuffer();
1167
sb.append(super.toString()).append("[\n");
1169
if (sIntoTable != null) {
1170
sb.append("into table=[").append(sIntoTable.name).append("]\n");
1173
if (limitCondition != null) {
1174
sb.append("offset=[").append(
1175
limitCondition.getArg().describe(session)).append("]\n");
1176
sb.append("limit=[").append(
1177
limitCondition.getArg2().describe(session)).append("]\n");
1180
sb.append("isDistinctSelect=[").append(isDistinctSelect).append(
1182
sb.append("isGrouped=[").append(isGrouped).append("]\n");
1183
sb.append("isAggregated=[").append(isAggregated).append("]\n");
1184
sb.append("columns=[");
1186
int columns = exprColumns.length - iOrderLen;
1188
for (int i = 0; i < columns; i++) {
1189
sb.append(exprColumns[i].describe(session));
1193
sb.append("tableFilters=[\n");
1195
for (int i = 0; i < tFilter.length; i++) {
1197
sb.append(tFilter[i].describe(session));
1203
temp = queryCondition == null ? "null"
1204
: queryCondition.describe(session);
1206
sb.append("eCondition=[").append(temp).append("]\n");
1208
temp = havingCondition == null ? "null"
1209
: havingCondition.describe(session);
1211
sb.append("havingCondition=[").append(temp).append("]\n");
1212
sb.append("groupColumns=[").append(groupColumnNames).append("]\n");
1214
if (unionSelect != null) {
1215
switch (unionType) {
1218
sb.append(" EXCEPT ");
1222
sb.append(" INTERSECT ");
1226
sb.append(" UNION ");
1230
sb.append(" UNION ALL ");
1234
sb.append(" UNKNOWN SET OPERATION ");
1237
sb.append("[\n").append(unionSelect.describe(session)).append(
1241
return sb.toString();
1244
Result describeResult() {
1247
Result.ResultMetaData rmd;
1250
r = new Result(ResultConstants.DATA, iResultLen);
1253
for (int i = 0; i < iResultLen; i++) {
1255
rmd.colTypes[i] = e.getDataType();
1256
rmd.colSizes[i] = e.getColumnSize();
1257
rmd.colScales[i] = e.getColumnScale();
1258
rmd.colLabels[i] = e.getAlias();
1259
rmd.isLabelQuoted[i] = e.isAliasQuoted();
1260
rmd.tableNames[i] = e.getTableName();
1261
rmd.colNames[i] = e.getColumnName();
1263
if (rmd.isTableColumn(i)) {
1264
rmd.colNullable[i] = e.nullability;
1265
rmd.isIdentity[i] = e.isIdentity;
1266
rmd.isWritable[i] = e.isWritable;