📄 select.java
字号:
&&!exprColumns[i].canBeInGroupBy()) {
Trace.error(Trace.INVALID_GROUP_BY, exprColumns[i]);
}
if (i >= groupByEnd && i < groupByEnd + iHavingLen
&&!exprColumns[i].isConditional()) {
Trace.error(Trace.INVALID_HAVING, exprColumns[i]);
}
if (i >= orderByStart && i < orderByEnd
&&!exprColumns[i].canBeInOrderBy()) {
Trace.error(Trace.INVALID_ORDER_BY, exprColumns[i]);
}
if (i < iResultLen) {
rmd.colLabels[i] = e.getAlias();
rmd.isLabelQuoted[i] = e.isAliasQuoted();
rmd.schemaNames[i] = e.getTableSchemaName();
rmd.tableNames[i] = e.getTableName();
rmd.colNames[i] = e.getColumnName();
if (rmd.isTableColumn(i)) {
rmd.colNullable[i] = e.nullability;
rmd.isIdentity[i] = e.isIdentity;
rmd.isWritable[i] = e.isWritable;
}
rmd.classNames[i] = e.getValueClassName();
}
}
// selected columns
checkAggregateOrGroupByColumns(0, iResultLen);
// having columns
checkAggregateOrGroupByColumns(groupByEnd, orderByStart);
// order by columns
checkAggregateOrGroupByOrderColumns(orderByStart, orderByEnd); prepareSort();
simpleLimit = (isDistinctSelect == false && isGrouped == false
&& unionSelect == null && iOrderLen == 0);
}
/**
* This is called externally only on the first Select in a UNION chain.
*/
void prepareUnions() throws HsqlException {
int count = 0;
for (Select current = this; current != null;
current = current.unionSelect, count++) {}
if (count == 1) {
if (unionDepth != 0) {
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
}
return;
}
unionArray = new Select[count];
count = 0;
for (Select current = this; current != null;
current = current.unionSelect, count++) {
unionArray[count] = current;
unionMaxDepth = current.unionDepth > unionMaxDepth
? current.unionDepth
: unionMaxDepth;
}
if (unionArray[unionArray.length - 1].unionDepth != 0) {
throw Trace.error(Trace.MISSING_CLOSEBRACKET);
}
}
/**
* Returns the result of executing this Select.
*
* @param maxrows may be 0 to indicate no limit on the number of rows.
* Positive values limit the size of the result set.
* @return the result of executing this Select
* @throws HsqlException if a database access error occurs
*/
Result getResult(Session session, int maxrows) throws HsqlException {
Result r;
if (unionArray == null) {
r = getSingleResult(session, maxrows);
} else {
r = getResultMain(session);
if (sortUnion) {
sortResult(session, r);
r.trimResult(getLimitStart(session),
getLimitCount(session, maxrows));
}
}
// fredt - now there is no need for the sort and group columns
r.setColumnCount(iResultLen);
return r;
}
private Result getResultMain(Session session) throws HsqlException {
Result[] unionResults = new Result[unionArray.length];
for (int i = 0; i < unionArray.length; i++) {
unionResults[i] = unionArray[i].getSingleResult(session,
Integer.MAX_VALUE);
}
for (int depth = unionMaxDepth; depth >= 0; depth--) {
for (int pass = 0; pass < 2; pass++) {
for (int i = 0; i < unionArray.length - 1; i++) {
if (unionResults[i] != null
&& unionArray[i].unionDepth >= depth) {
if (pass == 0
&& unionArray[i].unionType
!= Select.INTERSECT) {
continue;
}
if (pass == 1
&& unionArray[i].unionType
== Select.INTERSECT) {
continue;
}
int nextIndex = i + 1;
for (; nextIndex < unionArray.length; nextIndex++) {
if (unionResults[nextIndex] != null) {
break;
}
}
if (nextIndex == unionArray.length) {
break;
}
unionArray[i].mergeResults(session, unionResults[i],
unionResults[nextIndex]);
unionResults[nextIndex] = unionResults[i];
unionResults[i] = null;
}
}
}
}
return unionResults[unionResults.length - 1];
}
/**
* Merges the second result into the first using the unionMode
* set operation.
*/
private void mergeResults(Session session, Result first,
Result second) throws HsqlException {
switch (unionType) {
case UNION :
first.append(second);
first.removeDuplicates(session, iResultLen);
break;
case UNIONALL :
first.append(second);
break;
case INTERSECT :
first.removeDifferent(session, second, iResultLen);
break;
case EXCEPT :
first.removeSecond(session, second, iResultLen);
break;
}
}
int getLimitStart(Session session) throws HsqlException {
if (limitCondition != null) {
Integer limit =
(Integer) limitCondition.getArg().getValue(session);
if (limit != null) {
return limit.intValue();
}
}
return 0;
}
/**
* For SELECT LIMIT n m ....
* finds cases where the result does not have to be fully built and
* returns an adjusted rowCount with LIMIT params.
*/
int getLimitCount(Session session, int rowCount) throws HsqlException {
int limitCount = 0;
if (limitCondition != null) {
Integer limit =
(Integer) limitCondition.getArg2().getValue(session);
if (limit != null) {
limitCount = limit.intValue();
}
}
if (rowCount != 0 && (limitCount == 0 || rowCount < limitCount)) {
limitCount = rowCount;
}
return limitCount;
}
/**
* translate the rowCount into total number of rows needed from query,
* including any rows skipped at the beginning
*/
int getMaxRowCount(Session session, int rowCount) throws HsqlException {
int limitStart = getLimitStart(session);
int limitCount = getLimitCount(session, rowCount);
if (!simpleLimit) {
rowCount = Integer.MAX_VALUE;
} else {
if (rowCount == 0) {
rowCount = limitCount;
}
if (rowCount == 0 || rowCount > Integer.MAX_VALUE - limitStart) {
rowCount = Integer.MAX_VALUE;
} else {
rowCount += limitStart;
}
}
return rowCount;
}
private Result getSingleResult(Session session,
int rowCount) throws HsqlException {
if (resultMetaData == null) {
prepareResult(session);
}
Result r = buildResult(session, getMaxRowCount(session, rowCount));
// the result is perhaps wider (due to group and order by)
// so use the visible columns to remove duplicates
if (isDistinctSelect) {
r.removeDuplicates(session, iResultLen);
}
if (!sortUnion) {
sortResult(session, r);
r.trimResult(getLimitStart(session),
getLimitCount(session, rowCount));
}
return r;
}
private void prepareSort() {
if (iOrderLen == 0) {
return;
}
sortOrder = new int[iOrderLen];
sortDirection = new int[iOrderLen];
int startCol = iResultLen + iGroupLen + iHavingLen;
for (int i = startCol, j = 0; j < iOrderLen; i++, j++) {
int colindex = i;
// fredt - when a union, use the visible select columns for sort comparison
// also whenever a column alias is used
if (exprColumns[i].joinedTableColumnIndex != -1) {
colindex = exprColumns[i].joinedTableColumnIndex;
}
sortOrder[j] = colindex;
sortDirection[j] = exprColumns[i].isDescending() ? -1
: 1;
}
}
private void sortResult(Session session, Result r) throws HsqlException {
if (iOrderLen == 0) {
return;
}
r.sortResult(session, sortOrder, sortDirection);
}
/**
* Check result columns for aggregate or group by violation.
* If any result column is aggregated, then all result columns need to be
* aggregated, unless it is included in the group by clause.
*/
private void checkAggregateOrGroupByColumns(int start,
int end) throws HsqlException {
if (start < end) {
HsqlArrayList colExps = new HsqlArrayList();
for (int i = start; i < end; i++) {
exprColumns[i].collectInGroupByExpressions(colExps);
}
for (int i = 0, size = colExps.size(); i < size; i++) {
Expression exp = (Expression) colExps.get(i);
if (inAggregateOrGroupByClause(exp)) {
continue;
}
throw Trace.error(Trace.NOT_IN_AGGREGATE_OR_GROUP_BY, exp); } } } private void checkAggregateOrGroupByOrderColumns(int start, int end) throws HsqlException { checkAggregateOrGroupByColumns(start, end); if (start < end && isDistinctSelect) { HsqlArrayList colExps = new HsqlArrayList(); for (int i = start; i < end; i++) { exprColumns[i].collectInGroupByExpressions(colExps); } for (int i = 0, size = colExps.size(); i < size; i++) { Expression exp = (Expression) colExps.get(i); if (isSimilarIn(exp, 0, iResultLen)) { continue; }
throw Trace.error(Trace.INVALID_ORDER_BY_IN_DISTINCT_SELECT, exp); }
}
}
/**
* Check if the given expression is acceptable in a select that may
* include aggregate function and/or group by clause.
* <p>
* The expression is acceptable if:
* <UL>
* <LI>The select does not containt any aggregate function;
* <LI>The expression itself can be included in an aggregate select;
* <LI>The expression is defined in the group by clause;
* <LI>All the columns in the expression are defined in the group by clause;
* </UL)
*/
private boolean inAggregateOrGroupByClause(Expression exp) {
if (isGrouped) {
return isSimilarIn(exp, iResultLen, iResultLen + iGroupLen)
|| allColumnsAreDefinedIn(exp, groupColumnNames);
} else if (isAggregated) {
return exp.canBeInAggregate();
} else {
return true;
}
}
/**
* Check if the given expression is similar to any of the eColumn
* expressions within the given range.
*/
private boolean isSimilarIn(Expression exp, int start, int end) {
for (int i = start; i < end; i++) {
if (exp.similarTo(exprColumns[i])) {
return true;
}
}
return false;
}
/**
* Check if all the column names used in the given expression are defined
* in the given defined column names.
*/
static boolean allColumnsAreDefinedIn(Expression exp,
HashSet definedColumns) {
HashSet colNames = new HashSet();
exp.collectAllColumnNames(colNames);
if ((colNames.size() > 0) && (definedColumns == null)) {
return false;
}
Iterator i = colNames.iterator();
while (i.hasNext()) {
if (!definedColumns.contains(i.next())) {
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -