/* Copyright (c) 2001-2010, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.hsqldb; import org.hsqldb.HsqlNameManager.HsqlName; import org.hsqldb.HsqlNameManager.SimpleName; import org.hsqldb.ParserDQL.CompileContext; import org.hsqldb.RangeVariable.RangeIteratorRight; import org.hsqldb.error.Error; import org.hsqldb.error.ErrorCode; import org.hsqldb.index.Index; import org.hsqldb.lib.ArrayListIdentity; import org.hsqldb.lib.ArrayUtil; import org.hsqldb.lib.HashMappedList; import org.hsqldb.lib.HashSet; import org.hsqldb.lib.HsqlArrayList; import org.hsqldb.lib.HsqlList; import org.hsqldb.lib.IntValueHashMap; import org.hsqldb.lib.OrderedHashSet; import org.hsqldb.lib.OrderedIntHashSet; import org.hsqldb.lib.Set; import org.hsqldb.navigator.RangeIterator; import org.hsqldb.navigator.RowSetNavigatorData; import org.hsqldb.navigator.RowSetNavigatorDataTable; import org.hsqldb.persist.PersistentStore; import org.hsqldb.result.Result; import org.hsqldb.result.ResultMetaData; import org.hsqldb.result.ResultProperties; import org.hsqldb.store.ValuePool; import org.hsqldb.types.Type; import org.hsqldb.types.Types; /** * Implementation of an SQL query specification, including SELECT. * * @author Fred Toussi (fredt@users dot sourceforge.net) * * @version 2.0.0 * @since 1.9.0 */ public class QuerySpecification extends QueryExpression { private final static int[] defaultLimits = new int[] { 0, Integer.MAX_VALUE, Integer.MAX_VALUE }; // public int resultRangePosition; public boolean isDistinctSelect; public boolean isAggregated; public boolean isGrouped; RangeVariable[] rangeVariables; private HsqlArrayList rangeVariableList; Expression queryCondition; Expression checkQueryCondition; private Expression havingCondition; Expression rowExpression; Expression[] exprColumns; private HsqlArrayList exprColumnList; public int indexLimitVisible; private int indexLimitRowId; private int groupByColumnCount; // columns in 'group by' private int havingColumnCount; // columns in 'having' (0 or 1) private int indexStartHaving; public int indexStartOrderBy; public int indexStartAggregates; private int indexLimitExpressions; public int indexLimitData; private boolean hasRowID; private boolean isSimpleCount; private boolean hasMemoryRow; // public boolean isUniqueResultRows; private boolean simpleLimit = true; // true if maxrows can be uses as is // Type[] columnTypes; private ArrayListIdentity aggregateSet; // private ArrayListIdentity resolvedSubqueryExpressions = null; // // private boolean[] aggregateCheck; // private OrderedHashSet tempSet = new OrderedHashSet(); // int[] columnMap; private Table baseTable; private OrderedHashSet conditionTables; // for view super-view references // public Index groupIndex; // QuerySpecification(Session session, Table table, CompileContext compileContext) { this(compileContext); RangeVariable range = new RangeVariable(table, null, null, null, compileContext); range.addTableColumns(exprColumnList, 0, null); indexLimitVisible = exprColumnList.size(); addRangeVariable(range); isMergeable = false; resolveReferences(session); resolveTypes(session); sortAndSlice = SortAndSlice.noSort; } QuerySpecification(CompileContext compileContext) { super(compileContext); this.compileContext = compileContext; resultRangePosition = compileContext.getNextRangeVarIndex(); rangeVariableList = new HsqlArrayList(); exprColumnList = new HsqlArrayList(); sortAndSlice = SortAndSlice.noSort; isMergeable = true; } void addRangeVariable(RangeVariable rangeVar) { rangeVariableList.add(rangeVar); } // range variable sub queries are resolves fully private void resolveRangeVariables(Session session) { if (rangeVariables == null || rangeVariables.length < rangeVariableList.size()) { rangeVariables = new RangeVariable[rangeVariableList.size()]; rangeVariableList.toArray(rangeVariables); } for (int i = 0; i < rangeVariables.length; i++) { rangeVariables[i].resolveRangeTable(session, rangeVariables, i); } } void addSelectColumnExpression(Expression e) { if (e.getType() == OpTypes.ROW) { throw Error.error(ErrorCode.X_42564); } if (indexLimitVisible > 0) { if (e.opType == OpTypes.MULTICOLUMN) { if (((ExpressionColumn) e).getTableName() == null) { throw Error.error(ErrorCode.X_42578); } } Expression first = ((Expression) exprColumnList.get(0)); if (first.opType == OpTypes.MULTICOLUMN && ((ExpressionColumn) first).getTableName() == null) { throw Error.error(ErrorCode.X_42578); } } exprColumnList.add(e); indexLimitVisible++; } void addQueryCondition(Expression e) { queryCondition = e; } void addGroupByColumnExpression(Expression e) { if (e.getType() == OpTypes.ROW) { throw Error.error(ErrorCode.X_42564); } exprColumnList.add(e); isGrouped = true; groupByColumnCount++; } void addHavingExpression(Expression e) { exprColumnList.add(e); havingCondition = e; havingColumnCount = 1; } void addSortAndSlice(SortAndSlice sortAndSlice) { this.sortAndSlice = sortAndSlice; } public void resolveReferences(Session session) { resolveRangeVariables(session); resolveColumnReferencesForAsterisk(); finaliseColumns(); resolveColumnReferences(); unionColumnTypes = new Type[indexLimitVisible]; setReferenceableColumns(); } /** * Resolves all column expressions in the GROUP BY clause and beyond. * Replaces any alias column expression in the ORDER BY cluase * with the actual select column expression. */ private void resolveColumnReferences() { if (isDistinctSelect || isGrouped) { acceptsSequences = false; } for (int i = 0; i < rangeVariables.length; i++) { Expression e = rangeVariables[i].getJoinCondition(); if (e == null) { continue; } resolveColumnReferencesAndAllocate(e, i + 1, false); } resolveColumnReferencesAndAllocate(queryCondition, rangeVariables.length, false); if (resolvedSubqueryExpressions != null) { // subqueries in conditions not to be converted to SIMPLE_COLUMN resolvedSubqueryExpressions.setSize(0); } for (int i = 0; i < indexLimitVisible; i++) { resolveColumnReferencesAndAllocate(exprColumns[i], rangeVariables.length, acceptsSequences); } for (int i = indexLimitVisible; i < indexStartHaving; i++) { exprColumns[i] = resolveColumnReferencesInGroupBy(exprColumns[i]); } for (int i = indexStartHaving; i < indexStartOrderBy; i++) { resolveColumnReferencesAndAllocate(exprColumns[i], rangeVariables.length, false); } resolveColumnRefernecesInOrderBy(sortAndSlice); } void resolveColumnRefernecesInOrderBy(SortAndSlice sortAndSlice) { // replace the aliases with expressions // replace column names with expressions and resolve the table columns int orderCount = sortAndSlice.getOrderLength(); for (int i = 0; i < orderCount; i++) { ExpressionOrderBy e = (ExpressionOrderBy) sortAndSlice.exprList.get(i); replaceColumnIndexInOrderBy(e); if (e.getLeftNode().queryTableColumnIndex != -1) { continue; } if (sortAndSlice.sortUnion) { if (e.getLeftNode().getType() != OpTypes.COLUMN) { throw Error.error(ErrorCode.X_42576); } } e.replaceAliasInOrderBy(exprColumns, indexLimitVisible); resolveColumnReferencesAndAllocate(e, rangeVariables.length, false); if (isAggregated || isGrouped) { boolean check = e.getLeftNode().isComposedOf(exprColumns, 0, indexLimitVisible + groupByColumnCount, Expression.aggregateFunctionSet); if (!check) { throw Error.error(ErrorCode.X_42576); } } } sortAndSlice.prepare(this); } private boolean resolveColumnReferences(Expression e, int rangeCount, boolean withSequences) { if (e == null) { return true; } int oldSize = unresolvedExpressions == null ? 0 : unresolvedExpressions .size(); unresolvedExpressions = e.resolveColumnReferences(rangeVariables, rangeCount, unresolvedExpressions, withSequences); int newSize = unresolvedExpressions == null ? 0 : unresolvedExpressions .size(); return oldSize == newSize; } private void resolveColumnReferencesForAsterisk() { for (int pos = 0; pos < indexLimitVisible; ) { Expression e = (Expression) (exprColumnList.get(pos)); if (e.getType() == OpTypes.MULTICOLUMN) { exprColumnList.remove(pos); String tablename = ((ExpressionColumn) e).getTableName(); if (tablename == null) { addAllJoinedColumns(e); } else { int rangeIndex = e.findMatchingRangeVariableIndex(rangeVariables); if (rangeIndex == -1) { throw Error.error(ErrorCode.X_42501, tablename); } RangeVariable range = rangeVariables[rangeIndex]; HashSet exclude = getAllNamedJoinColumns(); range.addTableColumns(e, exclude); } for (int i = 0; i < e.nodes.length; i++) { exprColumnList.add(pos, e.nodes[i]); pos++; } indexLimitVisible += e.nodes.length - 1; } else { pos++; } } } private void resolveColumnReferencesAndAllocate(Expression expression, int count, boolean withSequences) { if (expression == null) { return; } HsqlList list = expression.resolveColumnReferences(rangeVariables, count, null, withSequences); if (list != null) { for (int i = 0; i < list.size(); i++) { Expression e = (Expression) list.get(i); boolean resolved; if (e.isSelfAggregate()) { resolved = resolveColumnReferences(e.getLeftNode(), count, false); } else { resolved = resolveColumnReferences(e, count, withSequences); } if (resolved) { if (e.isSelfAggregate()) { if (aggregateSet == null) { aggregateSet = new ArrayListIdentity(); } aggregateSet.add(e); isAggregated = true; expression.setAggregate(); } if (resolvedSubqueryExpressions == null) { resolvedSubqueryExpressions = new ArrayListIdentity(); } resolvedSubqueryExpressions.add(e); } else { if (unresolvedExpressions == null) { unresolvedExpressions = new ArrayListIdentity(); } unresolvedExpressions.add(e); } } } } private Expression resolveColumnReferencesInGroupBy( Expression expression) { if (expression == null) { return null; } HsqlList list = expression.resolveColumnReferences(rangeVariables, rangeVariables.length, null, false); if (list != null) { // if not resolved, resolve as simple alias if (expression.getType() == OpTypes.COLUMN) { Expression resolved = expression.replaceAliasInOrderBy(exprColumns, indexLimitVisible); if (resolved != expression) { return resolved; } } // resolve and allocate to throw exception resolveColumnReferencesAndAllocate(expression, rangeVariables.length, false); } return expression; } private HashSet getAllNamedJoinColumns() { HashSet set = null; for (int i = 0; i < rangeVariableList.size(); i++) { RangeVariable range = (RangeVariable) rangeVariableList.get(i); if (range.namedJoinColumns != null) { if (set == null) { set = new HashSet(); } set.addAll(range.namedJoinColumns); } } return set; } public Expression getEquiJoinExpressions(OrderedHashSet nameSet, RangeVariable rightRange, boolean fullList) { HashSet set = new HashSet(); Expression result = null; OrderedHashSet joinColumnNames = new OrderedHashSet(); for (int i = 0; i < rangeVariableList.size(); i++) { RangeVariable range = (RangeVariable) rangeVariableList.get(i); HashMappedList columnList = range.rangeTable.columnList; for (int j = 0; j < columnList.size(); j++) { ColumnSchema column = (ColumnSchema) columnList.get(j); String name = range.getColumnAlias(j); boolean columnInList = nameSet.contains(name); boolean namedJoin = range.namedJoinColumns != null && range.namedJoinColumns.contains(name); boolean repeated = !namedJoin && !set.add(name); if (repeated && (!fullList || columnInList)) { throw Error.error(ErrorCode.X_42578, name); } if (!columnInList) { continue; } joinColumnNames.add(name); int leftPosition = range.rangeTable.getColumnIndex(column.getNameString()); int rightPosition = rightRange.rangeTable.getColumnIndex(name); Expression e = new ExpressionLogical(range, leftPosition, rightRange, rightPosition); result = ExpressionLogical.andExpressions(result, e); ExpressionColumn col = range.getColumnExpression(name); if (col == null) { col = new ExpressionColumn(new Expression[] { e.getLeftNode(), e.getRightNode() }, name); range.addNamedJoinColumnExpression(name, col); } else { col.nodes = (Expression[]) ArrayUtil.resizeArray(col.nodes, col.nodes.length + 1); col.nodes[col.nodes.length - 1] = e.getRightNode(); } rightRange.addNamedJoinColumnExpression(name, col); } } if (fullList && !joinColumnNames.containsAll(nameSet)) { throw Error.error(ErrorCode.X_42501); } rightRange.addNamedJoinColumns(joinColumnNames); return result; } private void addAllJoinedColumns(Expression e) { HsqlArrayList list = new HsqlArrayList(); for (int i = 0; i < rangeVariables.length; i++) { rangeVariables[i].addTableColumns(list); } Expression[] nodes = new Expression[list.size()]; list.toArray(nodes); e.nodes = nodes; } private void finaliseColumns() { indexLimitRowId = indexLimitVisible; indexStartHaving = indexLimitRowId + groupByColumnCount; indexStartOrderBy = indexStartHaving + havingColumnCount; indexStartAggregates = indexStartOrderBy + sortAndSlice.getOrderLength(); indexLimitData = indexLimitExpressions = indexStartAggregates; exprColumns = new Expression[indexLimitExpressions]; exprColumnList.toArray(exprColumns); for (int i = 0; i < indexLimitVisible; i++) { exprColumns[i].queryTableColumnIndex = i; } if (sortAndSlice.hasOrder()) { for (int i = 0; i < sortAndSlice.getOrderLength(); i++) { exprColumns[indexStartOrderBy + i] = (Expression) sortAndSlice.exprList.get(i); } } rowExpression = new Expression(OpTypes.ROW, exprColumns); } private void replaceColumnIndexInOrderBy(Expression orderBy) { Expression e = orderBy.getLeftNode(); if (e.getType() != OpTypes.VALUE) { return; } if (e.getDataType().typeCode == Types.SQL_INTEGER) { int i = ((Integer) e.getValue(null)).intValue(); if (0 < i && i <= indexLimitVisible) { orderBy.setLeftNode(exprColumns[i - 1]); return; } } throw Error.error(ErrorCode.X_42576); } void collectRangeVariables(RangeVariable[] rangeVars, Set set) { for (int i = 0; i < indexStartAggregates; i++) { exprColumns[i].collectRangeVariables(rangeVars, set); } if (queryCondition != null) { queryCondition.collectRangeVariables(rangeVars, set); } if (havingCondition != null) { havingCondition.collectRangeVariables(rangeVars, set); } } public boolean hasReference(RangeVariable range) { if (unresolvedExpressions == null) { return false; } for (int i = 0; i < unresolvedExpressions.size(); i++) { if (((Expression) unresolvedExpressions.get(i)).hasReference( range)) { return true; } } return false; } /** * Sets the types of all the expressions used in this SELECT list. */ public void resolveExpressionTypes(Session session, Expression parent) { for (int i = 0; i < indexStartAggregates; i++) { Expression e = exprColumns[i]; e.resolveTypes(session, parent); if (e.getType() == OpTypes.ROW) { throw Error.error(ErrorCode.X_42564); } } for (int i = 0, len = rangeVariables.length; i < len; i++) { Expression e = rangeVariables[i].getJoinCondition(); if (e != null) { e.resolveTypes(session, null); if (e.getDataType() != Type.SQL_BOOLEAN) { throw Error.error(ErrorCode.X_42568); } } } if (queryCondition != null) { queryCondition.resolveTypes(session, null); if (queryCondition.getDataType() != Type.SQL_BOOLEAN) { throw Error.error(ErrorCode.X_42568); } } if (havingCondition != null) { havingCondition.resolveTypes(session, null); if (havingCondition.getDataType() != Type.SQL_BOOLEAN) { throw Error.error(ErrorCode.X_42568); } } } private void resolveAggregates() { tempSet.clear(); if (isAggregated) { aggregateCheck = new boolean[indexStartAggregates]; tempSet.addAll(aggregateSet); indexLimitData = indexLimitExpressions = exprColumns.length + tempSet.size(); exprColumns = (Expression[]) ArrayUtil.resizeArray(exprColumns, indexLimitExpressions); for (int i = indexStartAggregates, j = 0; i < indexLimitExpressions; i++, j++) { Expression e = (Expression) tempSet.get(j); exprColumns[i] = e.duplicate(); exprColumns[i].nodes = e.nodes; // keep original nodes exprColumns[i].dataType = e.dataType; } tempSet.clear(); } } public boolean areColumnsResolved() { return unresolvedExpressions == null || unresolvedExpressions.isEmpty(); } private void setRangeVariableConditions(Session session) { RangeVariableResolver rangeResolver = new RangeVariableResolver(rangeVariables, queryCondition, compileContext); rangeResolver.processConditions(session); rangeVariables = rangeResolver.rangeVariables; } public void resolveTypes(Session session) { if (isResolved) { return; } resolveTypesPartOne(session); resolveTypesPartTwo(session); ArrayUtil.copyArray(resultTable.colTypes, unionColumnTypes, unionColumnTypes.length); for (int i = 0; i < indexStartHaving; i++) { if (exprColumns[i].dataType == null) { throw Error.error(ErrorCode.X_42567); } } } void resolveTypesPartOne(Session session) { resolveExpressionTypes(session, rowExpression); resolveAggregates(); for (int i = 0; i < unionColumnTypes.length; i++) { unionColumnTypes[i] = Type.getAggregateType(unionColumnTypes[i], exprColumns[i].getDataType()); } } void resolveTypesPartTwo(Session session) { resolveGroups(); for (int i = 0; i < unionColumnTypes.length; i++) { Type type = unionColumnTypes[i]; if (type == null) { throw Error.error(ErrorCode.X_42567); } exprColumns[i].setDataType(session, type); } for (int i = 0; i < indexStartHaving; i++) { if (exprColumns[i].dataType == null) { throw Error.error(ErrorCode.X_42567); } } checkLobUsage(); setMergeability(); setUpdatability(); createResultMetaData(); createTable(session); if (isMergeable) { mergeQuery(); } setRangeVariableConditions(session); if (isAggregated && !isGrouped && !sortAndSlice.hasOrder() && !sortAndSlice.hasLimit() && aggregateSet.size() == 1 && indexLimitVisible == 1) { Expression e = exprColumns[indexStartAggregates]; int opType = e.getType(); switch (opType) { case OpTypes.MAX : case OpTypes.MIN : { SortAndSlice slice = new SortAndSlice(); slice.isGenerated = true; slice.addLimitCondition(ExpressionOp.limitOneExpression); if (slice.prepareSpecial(session, this)) { this.sortAndSlice = slice; } break; } case OpTypes.COUNT : { if (rangeVariables.length == 1 && queryCondition == null && e.getLeftNode().getType() == OpTypes.ASTERISK) { isSimpleCount = true; } } } } sortAndSlice.setSortRange(this); isResolved = true; } void checkLobUsage() { if (!isDistinctSelect && !isGrouped) { return; } for (int i = 0; i < indexStartHaving; i++) { if (exprColumns[i].dataType.isLobType()) { throw Error.error(ErrorCode.X_42534); } } } private void resolveGroups() { // - 1.9.0 is standard compliant but has more extended support for // referencing columns // - check there is no direct aggregate expression in group by // - check each expression in select list can be // decomposed into the expressions in group by or any aggregates // this allows direct function of group by expressions, but // doesn't allow indirect functions. e.g. // select 2*abs(cola) , sum(colb) from t group by abs(cola) // ok // select 2*(cola + 10) , sum(colb) from t group by cola + 10 // ok // select abs(cola) , sum(colb) from t group by cola // ok // select 2*cola + 20 , sum(colb) from t group by cola + 10 // not allowed although correct // select cola , sum(colb) from t group by abs(cola) // not allowed because incorrect // - group by can introduce invisible, derived columns into the query table // - check the having expression can be decomposed into // select list expresions plus group by expressions // - having cannot introduce additional, derived columns // - having cannot reference columns not in the select or group by list // - if there is any aggregate in select list but no group by, no // non-aggregates is allowed // - check order by columns // - if distinct select, order by must be composed of the select list columns // - if grouped by, then order by should be decomposed into the // select list plus group by list // - references to column aliases are allowed only in order by (Standard // compliance) and take precendence over references to non-alias // column names. // - references to table / correlation and column list in correlation // names are handled according to the Standard // fredt@users tempSet.clear(); if (isGrouped) { for (int i = indexLimitVisible; i < indexLimitVisible + groupByColumnCount; i++) { exprColumns[i].collectAllExpressions( tempSet, Expression.aggregateFunctionSet, Expression.subqueryExpressionSet); if (!tempSet.isEmpty()) { throw Error.error(ErrorCode.X_42572, ((Expression) tempSet.get(0)).getSQL()); } } for (int i = 0; i < indexLimitVisible; i++) { if (!exprColumns[i].isComposedOf( exprColumns, indexLimitVisible, indexLimitVisible + groupByColumnCount, Expression.subqueryAggregateExpressionSet)) { tempSet.add(exprColumns[i]); } } if (!tempSet.isEmpty() && !resolveForGroupBy(tempSet)) { throw Error.error(ErrorCode.X_42574, ((Expression) tempSet.get(0)).getSQL()); } } else if (isAggregated) { for (int i = 0; i < indexLimitVisible; i++) { exprColumns[i].collectAllExpressions( tempSet, Expression.columnExpressionSet, Expression.aggregateFunctionSet); if (!tempSet.isEmpty()) { throw Error.error(ErrorCode.X_42574, ((Expression) tempSet.get(0)).getSQL()); } } } tempSet.clear(); if (havingCondition != null) { if (unresolvedExpressions != null) { tempSet.addAll(unresolvedExpressions); } for (int i = indexLimitVisible; i < indexLimitVisible + groupByColumnCount; i++) { tempSet.add(exprColumns[i]); } if (!havingCondition.isComposedOf( tempSet, Expression.subqueryAggregateExpressionSet)) { throw Error.error(ErrorCode.X_42573); } tempSet.clear(); } if (isDistinctSelect) { int orderCount = sortAndSlice.getOrderLength(); for (int i = 0; i < orderCount; i++) { Expression e = (Expression) sortAndSlice.exprList.get(i); if (e.queryTableColumnIndex != -1) { continue; } if (!e.isComposedOf(exprColumns, 0, indexLimitVisible, Expression.emptyExpressionSet)) { throw Error.error(ErrorCode.X_42576); } } } if (isGrouped) { int orderCount = sortAndSlice.getOrderLength(); for (int i = 0; i < orderCount; i++) { Expression e = (Expression) sortAndSlice.exprList.get(i); if (e.queryTableColumnIndex != -1) { continue; } if (!e.isAggregate() && !e.isComposedOf( exprColumns, 0, indexLimitVisible + groupByColumnCount, Expression.emptyExpressionSet)) { throw Error.error(ErrorCode.X_42576); } } } if (isDistinctSelect || isGrouped) { simpleLimit = false; } if (!isAggregated) { return; } OrderedHashSet expressions = new OrderedHashSet(); OrderedHashSet columnExpressions = new OrderedHashSet(); for (int i = indexStartAggregates; i < indexLimitExpressions; i++) { Expression e = exprColumns[i]; Expression c = new ExpressionColumn(e, i, resultRangePosition); expressions.add(e); columnExpressions.add(c); } for (int i = 0; i < indexStartHaving; i++) { if (exprColumns[i].isAggregate()) { continue; } Expression e = exprColumns[i]; if (expressions.add(e)) { Expression c = new ExpressionColumn(e, i, resultRangePosition); columnExpressions.add(c); } } // order by with aggregate int orderCount = sortAndSlice.getOrderLength(); for (int i = 0; i < orderCount; i++) { Expression e = (Expression) sortAndSlice.exprList.get(i); if (e.getLeftNode().isAggregate()) { e.setAggregate(); } } for (int i = indexStartOrderBy; i < indexStartAggregates; i++) { if (exprColumns[i].getLeftNode().isAggregate()) { exprColumns[i].setAggregate(); } } for (int i = 0; i < indexStartAggregates; i++) { Expression e = exprColumns[i]; if (!e.isAggregate() && !e.isCorrelated() ) { continue; } aggregateCheck[i] = true; if (e.isAggregate()) { e.convertToSimpleColumn(expressions, columnExpressions); } } for (int i = 0; i < aggregateSet.size(); i++) { Expression e = (Expression) aggregateSet.get(i); e.convertToSimpleColumn(expressions, columnExpressions); } if (resolvedSubqueryExpressions != null) { for (int i = 0; i < resolvedSubqueryExpressions.size(); i++) { Expression e = (Expression) resolvedSubqueryExpressions.get(i); e.convertToSimpleColumn(expressions, columnExpressions); } } } boolean resolveForGroupBy(HsqlList unresolvedSet) { for (int i = indexLimitVisible; i < indexLimitVisible + groupByColumnCount; i++) { Expression e = exprColumns[i]; if (e.getType() == OpTypes.COLUMN) { RangeVariable range = e.getRangeVariable(); int colIndex = e.getColumnIndex(); range.columnsInGroupBy[colIndex] = true; } } for (int i = 0; i < rangeVariables.length; i++) { RangeVariable range = rangeVariables[i]; range.hasKeyedColumnInGroupBy = range.rangeTable.getUniqueNotNullColumnGroup( range.columnsInGroupBy) != null; } OrderedHashSet set = null; for (int i = 0; i < unresolvedSet.size(); i++) { Expression e = (Expression) unresolvedSet.get(i); set = e.getUnkeyedColumns(set); } return set == null; } int[] getLimits(Session session, int maxRows) { int skipRows = 0; int limitRows = Integer.MAX_VALUE; int limitFetch = Integer.MAX_VALUE; boolean hasLimits = false; if (sortAndSlice.hasLimit()) { Integer value = (Integer) sortAndSlice.limitCondition.getLeftNode().getValue( session); if (value == null || value.intValue() < 0) { throw Error.error(ErrorCode.X_2201X); } skipRows = value.intValue(); hasLimits = skipRows != 0; if (sortAndSlice.limitCondition.getRightNode() != null) { value = (Integer) sortAndSlice.limitCondition.getRightNode() .getValue(session); if (value == null || value.intValue() <= 0) { throw Error.error(ErrorCode.X_2201W); } if (value.intValue() == 0) { limitRows = Integer.MAX_VALUE; } else { limitRows = value.intValue(); hasLimits = true; } } } if (maxRows != 0) { if (maxRows < limitRows) { limitRows = maxRows; } hasLimits = true; } if (hasLimits && simpleLimit && (!sortAndSlice.hasOrder() || sortAndSlice.skipSort) && (!sortAndSlice.hasLimit() || sortAndSlice.skipFullResult)) { if (limitFetch - skipRows > limitRows) { limitFetch = skipRows + limitRows; } } return hasLimits ? new int[] { skipRows, limitRows, limitFetch } : defaultLimits; } /** * 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 */ Result getResult(Session session, int maxrows) { Result r = getSingleResult(session, maxrows); r.getNavigator().reset(); return r; } private Result getSingleResult(Session session, int maxRows) { int[] limits = getLimits(session, maxRows); Result r = buildResult(session, limits[2]); RowSetNavigatorData navigator = (RowSetNavigatorData) r.getNavigator(); if (isDistinctSelect) { navigator.removeDuplicates(); } if (sortAndSlice.hasOrder()) { navigator.sortOrder(); } if (limits != defaultLimits) { navigator.trim(limits[0], limits[1]); } return r; } private Result buildResult(Session session, int limitcount) { RowSetNavigatorData navigator = new RowSetNavigatorData(session, (QuerySpecification) this); Result result = Result.newResult(navigator); result.metaData = resultMetaData; if (isUpdatable) { result.rsProperties = ResultProperties.updatablePropsValue; } if (this.isSimpleCount) { Object[] data = new Object[indexLimitData]; Table table = rangeVariables[0].getTable(); PersistentStore store = table.getRowStore(session); int count = table.getIndex(0).size(session, store); data[0] = data[indexStartAggregates] = ValuePool.getInt(count); navigator.add(data); return result; } int fullJoinIndex = 0; RangeIterator[] rangeIterators = new RangeIterator[rangeVariables.length]; for (int i = 0; i < rangeVariables.length; i++) { rangeIterators[i] = rangeVariables[i].getIterator(session); } for (int currentIndex = 0; ; ) { if (currentIndex < fullJoinIndex) { // finished current span // or finished outer rows on right navigator boolean end = true; for (int i = fullJoinIndex + 1; i < rangeVariables.length; i++) { if (rangeVariables[i].isRightJoin) { fullJoinIndex = i; currentIndex = i; end = false; ((RangeIteratorRight) rangeIterators[i]) .setOnOuterRows(); break; } } if (end) { break; } } RangeIterator it = rangeIterators[currentIndex]; if (it.next()) { if (currentIndex < rangeVariables.length - 1) { currentIndex++; continue; } } else { it.reset(); currentIndex--; continue; } session.sessionData.startRowProcessing(); Object[] data = new Object[indexLimitData]; for (int i = 0; i < indexStartAggregates; i++) { if (isAggregated && aggregateCheck[i]) { continue; } else { data[i] = exprColumns[i].getValue(session); } } for (int i = indexLimitVisible; i < indexLimitRowId; i++) { if (i == indexLimitVisible) { data[i] = it.getRowidObject(); } else { data[i] = it.getCurrentRow(); } } Object[] groupData = null; if (isAggregated || isGrouped) { groupData = navigator.getGroupData(data); if (groupData != null) { data = groupData; } } for (int i = indexStartAggregates; i < indexLimitExpressions; i++) { data[i] = exprColumns[i].updateAggregatingValue(session, data[i]); } if (groupData == null) { navigator.add(data); } else if (isAggregated) { navigator.update(groupData, data); } int rowCount = navigator.getSize(); if (rowCount == session.resultMaxMemoryRows && !isAggregated && !hasMemoryRow) { navigator = new RowSetNavigatorDataTable(session, this, navigator); result.setNavigator(navigator); } if (isAggregated || isGrouped) { if (!sortAndSlice.isGenerated) { continue; } } if (rowCount >= limitcount) { break; } } navigator.reset(); for (int i = 0; i < rangeVariables.length; i++) { rangeIterators[i].reset(); } if (!isGrouped && !isAggregated) { return result; } if (isAggregated) { if (!isGrouped && navigator.getSize() == 0) { Object[] data = new Object[exprColumns.length]; navigator.add(data); } navigator.reset(); session.sessionContext.setRangeIterator(navigator); while (navigator.next()) { Object[] data = navigator.getCurrent(); for (int i = indexStartAggregates; i < indexLimitExpressions; i++) { data[i] = exprColumns[i].getAggregatedValue(session, data[i]); } for (int i = 0; i < indexStartAggregates; i++) { if (aggregateCheck[i]) { data[i] = exprColumns[i].getValue(session); } } } } navigator.reset(); if (havingCondition != null) { while (navigator.hasNext()) { Object[] data = (Object[]) navigator.getNext(); if (!Boolean.TRUE.equals( data[indexLimitVisible + groupByColumnCount])) { navigator.remove(); } } navigator.reset(); } return result; } void setReferenceableColumns() { accessibleColumns = new boolean[indexLimitVisible]; IntValueHashMap aliases = new IntValueHashMap(); for (int i = 0; i < indexLimitVisible; i++) { Expression expression = exprColumns[i]; String alias = expression.getAlias(); if (alias.length() == 0) { SimpleName name = HsqlNameManager.getAutoColumnName(i); expression.setAlias(name); continue; } int index = aliases.get(alias, -1); if (index == -1) { aliases.put(alias, i); accessibleColumns[i] = true; } else { accessibleColumns[index] = false; } } } void setColumnAliases(SimpleName[] names) { if (names.length != indexLimitVisible) { throw Error.error(ErrorCode.X_42593); } for (int i = 0; i < indexLimitVisible; i++) { exprColumns[i].setAlias(names[i]); } } private void createResultMetaData() { columnTypes = new Type[indexLimitData]; for (int i = 0; i < indexStartAggregates; i++) { Expression e = exprColumns[i]; columnTypes[i] = e.getDataType(); } for (int i = indexLimitVisible; i < indexLimitRowId; i++) { if (i == indexLimitVisible) { columnTypes[i] = Type.SQL_BIGINT; } else { columnTypes[i] = Type.SQL_ALL_TYPES; } } for (int i = indexLimitRowId; i < indexLimitData; i++) { Expression e = exprColumns[i]; columnTypes[i] = e.getDataType(); } resultMetaData = ResultMetaData.newResultMetaData(columnTypes, columnMap, indexLimitVisible, indexLimitRowId); for (int i = 0; i < indexLimitVisible; i++) { Expression e = exprColumns[i]; resultMetaData.columnTypes[i] = e.getDataType(); if (i < indexLimitVisible) { ColumnBase column = e.getColumn(); if (column != null) { resultMetaData.columns[i] = column; resultMetaData.columnLabels[i] = e.getAlias(); continue; } column = new ColumnBase(); column.setType(e.getDataType()); resultMetaData.columns[i] = column; resultMetaData.columnLabels[i] = e.getAlias(); } } } void createTable(Session session) { createResultTable(session); mainIndex = resultTable.getPrimaryIndex(); if (sortAndSlice.hasOrder() && !sortAndSlice.skipSort) { orderIndex = resultTable.createAndAddIndexStructure(session, null, sortAndSlice.sortOrder, sortAndSlice.sortDescending, sortAndSlice.sortNullsLast, false, false, false); } if (isDistinctSelect || isFullOrder) { createFullIndex(session); } if (isGrouped) { int[] groupCols = new int[groupByColumnCount]; for (int i = 0; i < groupByColumnCount; i++) { groupCols[i] = indexLimitVisible + i; } groupIndex = resultTable.createAndAddIndexStructure(session, null, groupCols, null, null, false, false, false); } else if (isAggregated) { groupIndex = mainIndex; } if (isUpdatable && view == null) { int[] idCols = new int[]{ indexLimitVisible }; idIndex = resultTable.createAndAddIndexStructure(session, null, idCols, null, null, false, false, false); } } void createFullIndex(Session session) { int[] fullCols = new int[indexLimitVisible]; ArrayUtil.fillSequence(fullCols); fullIndex = resultTable.createAndAddIndexStructure(session, null, fullCols, null, null, false, false, false); resultTable.fullIndex = fullIndex; } void createResultTable(Session session) { HsqlName tableName; HashMappedList columnList; int tableType; tableName = session.database.nameManager.getSubqueryTableName(); tableType = persistenceScope == TableBase.SCOPE_STATEMENT ? TableBase.SYSTEM_SUBQUERY : TableBase.RESULT_TABLE; columnList = new HashMappedList(); for (int i = 0; i < indexLimitVisible; i++) { Expression e = exprColumns[i]; SimpleName simpleName = e.getSimpleName(); String nameString = simpleName.name; HsqlName name = session.database.nameManager.newColumnSchemaHsqlName(tableName, simpleName); if (!accessibleColumns[i]) { nameString = HsqlNameManager.getAutoNoNameColumnString(i); } ColumnSchema column = new ColumnSchema(name, e.dataType, true, false, null); columnList.add(nameString, column); } try { resultTable = new TableDerived(session.database, tableName, tableType, columnTypes, columnList, null, null); } catch (Exception e) {} } public String getSQL() { StringBuffer sb = new StringBuffer(); int limit; sb.append(Tokens.T_SELECT).append(' '); limit = indexLimitVisible; for (int i = 0; i < limit; i++) { if (i > 0) { sb.append(','); } sb.append(exprColumns[i].getSQL()); } sb.append(Tokens.T_FROM); limit = rangeVariables.length; for (int i = 0; i < limit; i++) { RangeVariable rangeVar = rangeVariables[i]; if (i > 0) { if (rangeVar.isLeftJoin && rangeVar.isRightJoin) { sb.append(Tokens.T_FULL).append(' '); } else if (rangeVar.isLeftJoin) { sb.append(Tokens.T_LEFT).append(' '); } else if (rangeVar.isRightJoin) { sb.append(Tokens.T_RIGHT).append(' '); } sb.append(Tokens.T_JOIN).append(' '); } sb.append(rangeVar.getTable().getName().statementName); } if (isGrouped) { sb.append(' ').append(Tokens.T_GROUP).append(' ').append( Tokens.T_BY); limit = indexLimitVisible + groupByColumnCount; for (int i = indexLimitVisible; i < limit; i++) { sb.append(exprColumns[i].getSQL()); if (i < limit - 1) { sb.append(','); } } } if (havingCondition != null) { sb.append(' ').append(Tokens.T_HAVING).append(' '); sb.append(havingCondition.getSQL()); } if (sortAndSlice.hasOrder()) { limit = indexStartOrderBy + sortAndSlice.getOrderLength(); sb.append(' ').append(Tokens.T_ORDER).append(Tokens.T_BY).append( ' '); for (int i = indexStartOrderBy; i < limit; i++) { sb.append(exprColumns[i].getSQL()); if (i < limit - 1) { sb.append(','); } } } if (sortAndSlice.hasLimit()) { sb.append(sortAndSlice.limitCondition.getLeftNode().getSQL()); } return sb.toString(); } public ResultMetaData getMetaData() { return resultMetaData; } public String describe(Session session, int blanks) { StringBuffer sb; String temp; String b = ValuePool.spaceString.substring(0, blanks); sb = new StringBuffer(); sb.append(b).append("isDistinctSelect=[").append( isDistinctSelect).append("]\n"); sb.append(b).append("isGrouped=[").append(isGrouped).append("]\n"); sb.append(b).append("isAggregated=[").append(isAggregated).append( "]\n"); sb.append(b).append("columns=["); for (int i = 0; i < indexLimitVisible; i++) { int index = i; if (exprColumns[i].getType() == OpTypes.SIMPLE_COLUMN) { index = exprColumns[i].columnIndex; } sb.append(b).append(exprColumns[index].describe(session, 2)); } sb.append("\n"); sb.append(b).append("]\n"); for (int i = 0; i < rangeVariables.length; i++) { sb.append(b).append("["); sb.append("range variable ").append(i + 1).append("\n"); sb.append(rangeVariables[i].describe(session, blanks + 2)); sb.append(b).append("]"); } sb.append(b).append("]\n"); temp = queryCondition == null ? "null" : queryCondition.describe(session, blanks); if (isGrouped) { sb.append(b).append("groupColumns=["); for (int i = indexLimitRowId; i < indexLimitRowId + groupByColumnCount; i++) { int index = i; if (exprColumns[i].getType() == OpTypes.SIMPLE_COLUMN) { index = exprColumns[i].columnIndex; } sb.append(exprColumns[index].describe(session, blanks)); } sb.append(b).append("]\n"); } if (havingCondition != null) { temp = havingCondition.describe(session, blanks); sb.append(b).append("havingCondition=[").append(temp).append( "]\n"); } if (sortAndSlice.hasOrder()) { sb.append(b).append("order by=[\n"); for (int i = 0; i < sortAndSlice.exprList.size(); i++) { sb.append(b).append( ((Expression) sortAndSlice.exprList.get(i)).describe( session, blanks)); sb.append(b).append("\n]"); } sb.append(b).append("]\n"); } if (sortAndSlice.hasLimit()) { if (sortAndSlice.limitCondition.getLeftNode() != null) { sb.append(b).append("offset=[").append( sortAndSlice.limitCondition.getLeftNode().describe( session, 0)).append("]\n"); } if (sortAndSlice.limitCondition.getRightNode() != null) { sb.append(b).append("limit=[").append( sortAndSlice.limitCondition.getRightNode().describe( session, 0)).append("]\n"); } } return sb.toString(); } void setMergeability() { if (isGrouped || isDistinctSelect) { isMergeable = false; return; } if (sortAndSlice.hasLimit() || sortAndSlice.hasOrder()) { isMergeable = false; return; } if (rangeVariables.length != 1) { isMergeable = false; return; } } void setUpdatability() { if (!isUpdatable) { return; } isUpdatable = false; if (!isMergeable) { return; } if (!isTopLevel) { return; } if (isAggregated) { return; } if (sortAndSlice.hasLimit() || sortAndSlice.hasOrder()) { return; } RangeVariable rangeVar = rangeVariables[0]; Table table = rangeVar.getTable(); Table baseTable = table.getBaseTable(); if (baseTable == null) { return; } isInsertable = table.isInsertable(); isUpdatable = table.isUpdatable(); if (!isInsertable && !isUpdatable) { return; } IntValueHashMap columns = new IntValueHashMap(); boolean[] checkList; int[] baseColumnMap = table.getBaseTableColumnMap(); int[] columnMap = new int[indexLimitVisible]; if (queryCondition != null) { tempSet.clear(); collectSubQueriesAndReferences(tempSet, queryCondition); if (tempSet.contains(table.getName()) || tempSet.contains(baseTable.getName())) { isUpdatable = false; isInsertable = false; return; } } for (int i = 0; i < indexLimitVisible; i++) { Expression expression = exprColumns[i]; if (expression.getType() == OpTypes.COLUMN) { String name = expression.getColumn().getName().name; if (columns.containsKey(name)) { columns.put(name, 1); continue; } columns.put(name, 0); } else { tempSet.clear(); collectSubQueriesAndReferences(tempSet, expression); if (tempSet.contains(table.getName())) { isUpdatable = false; isInsertable = false; return; } } } isUpdatable = false; for (int i = 0; i < indexLimitVisible; i++) { if (accessibleColumns[i]) { Expression expression = exprColumns[i]; if (expression.getType() == OpTypes.COLUMN) { String name = expression.getColumn().getName().name; if (columns.get(name) == 0) { int index = table.findColumn(name); columnMap[i] = baseColumnMap[index]; if (columnMap[i] != -1) { isUpdatable = true; } continue; } } } columnMap[i] = -1; isInsertable = false; } if (isInsertable) { checkList = baseTable.getColumnCheckList(columnMap); for (int i = 0; i < checkList.length; i++) { if (checkList[i]) { continue; } ColumnSchema column = baseTable.getColumn(i); if (column.isIdentity() || column.isGenerated() || column.hasDefault() || column.isNullable()) {} else { isInsertable = false; break; } } } if (!isUpdatable) { isInsertable = false; } if (isUpdatable) { this.columnMap = columnMap; this.baseTable = baseTable; if (view != null) { return; } indexLimitRowId++; hasRowID = true; if (!baseTable.isFileBased()) { indexLimitRowId++; hasMemoryRow = true; } indexLimitData = indexLimitRowId; } } void mergeQuery() { RangeVariable rangeVar = rangeVariables[0]; Table table = rangeVar.getTable(); Expression localQueryCondition = queryCondition; if (table instanceof TableDerived) { QueryExpression baseQueryExpression = ((TableDerived) table).getQueryExpression(); if (baseQueryExpression == null || !baseQueryExpression.isMergeable) { isMergeable = false; return; } QuerySpecification baseSelect = baseQueryExpression.getMainSelect(); if (baseQueryExpression.view == null) { rangeVariables[0] = baseSelect.rangeVariables[0]; rangeVariables[0].resetConditions(); Expression[] newExprColumns = new Expression[indexLimitData]; for (int i = 0; i < indexLimitData; i++) { Expression e = exprColumns[i]; newExprColumns[i] = e.replaceColumnReferences(rangeVar, baseSelect.exprColumns); } exprColumns = newExprColumns; if (localQueryCondition != null) { localQueryCondition = localQueryCondition.replaceColumnReferences(rangeVar, baseSelect.exprColumns); } Expression baseQueryCondition = baseSelect.queryCondition; checkQueryCondition = baseSelect.checkQueryCondition; queryCondition = ExpressionLogical.andExpressions(baseQueryCondition, localQueryCondition); } else { RangeVariable[] newRangeVariables = new RangeVariable[1]; newRangeVariables[0] = baseSelect.rangeVariables[0].duplicate(); Expression[] newBaseExprColumns = new Expression[baseSelect.indexLimitData]; for (int i = 0; i < baseSelect.indexLimitData; i++) { Expression e = baseSelect.exprColumns[i].duplicate(); newBaseExprColumns[i] = e; e.replaceRangeVariables(baseSelect.rangeVariables, newRangeVariables); } for (int i = 0; i < indexLimitData; i++) { Expression e = exprColumns[i]; exprColumns[i] = e.replaceColumnReferences(rangeVar, newBaseExprColumns); } Expression baseQueryCondition = baseSelect.queryCondition; if (baseQueryCondition != null) { baseQueryCondition = baseQueryCondition.duplicate(); baseQueryCondition.replaceRangeVariables( baseSelect.rangeVariables, newRangeVariables); } if (localQueryCondition != null) { localQueryCondition = localQueryCondition.replaceColumnReferences(rangeVar, newBaseExprColumns); } checkQueryCondition = baseSelect.checkQueryCondition; if (checkQueryCondition != null) { checkQueryCondition = checkQueryCondition.duplicate(); checkQueryCondition.replaceRangeVariables( baseSelect.rangeVariables, newRangeVariables); } queryCondition = ExpressionLogical.andExpressions(baseQueryCondition, localQueryCondition); rangeVariables = newRangeVariables; } } if (view != null) { switch (view.getCheckOption()) { case SchemaObject.ViewCheckModes.CHECK_LOCAL : if (!isUpdatable) { throw Error.error(ErrorCode.X_42537); } checkQueryCondition = localQueryCondition; break; case SchemaObject.ViewCheckModes.CHECK_CASCADE : if (!isUpdatable) { throw Error.error(ErrorCode.X_42537); } checkQueryCondition = queryCondition; break; } } if (isAggregated) { isMergeable = false; } } static void collectSubQueriesAndReferences(OrderedHashSet set, Expression expression) { expression.collectAllExpressions(set, Expression.subqueryExpressionSet, Expression.emptyExpressionSet); int size = set.size(); for (int i = 0; i < size; i++) { Expression e = (Expression) set.get(i); e.collectObjectNames(set); } } public OrderedHashSet getSubqueries() { OrderedHashSet set = null; for (int i = 0; i < indexStartAggregates; i++) { set = exprColumns[i].collectAllSubqueries(set); } if (queryCondition != null) { set = queryCondition.collectAllSubqueries(set); } if (havingCondition != null) { set = havingCondition.collectAllSubqueries(set); } for (int i = 0; i < rangeVariables.length; i++) { OrderedHashSet temp = rangeVariables[i].getSubqueries(); set = OrderedHashSet.addAll(set, temp); } return set; } public Table getBaseTable() { return baseTable; } public OrderedHashSet collectAllSubqueries(OrderedHashSet set) { return set; } public OrderedHashSet collectAllExpressions(OrderedHashSet set, OrderedIntHashSet typeSet, OrderedIntHashSet stopAtTypeSet) { for (int i = 0; i < indexStartAggregates; i++) { set = exprColumns[i].collectAllExpressions(set, typeSet, stopAtTypeSet); } if (queryCondition != null) { set = queryCondition.collectAllExpressions(set, typeSet, stopAtTypeSet); } if (havingCondition != null) { set = havingCondition.collectAllExpressions(set, typeSet, stopAtTypeSet); } return set; } public void collectObjectNames(Set set) { for (int i = 0; i < indexStartAggregates; i++) { exprColumns[i].collectObjectNames(set); } if (queryCondition != null) { queryCondition.collectObjectNames(set); } if (havingCondition != null) { havingCondition.collectObjectNames(set); } for (int i = 0, len = rangeVariables.length; i < len; i++) { HsqlName name = rangeVariables[i].getTable().getName(); set.add(name); } } public void replaceColumnReference(RangeVariable range, Expression[] list) { for (int i = 0; i < indexStartAggregates; i++) { exprColumns[i].replaceColumnReferences(range, list); } if (queryCondition != null) { queryCondition.replaceColumnReferences(range, list); } if (havingCondition != null) { havingCondition.replaceColumnReferences(range, list); } for (int i = 0, len = rangeVariables.length; i < len; i++) { // } } public void replaceRangeVariables(RangeVariable[] ranges, RangeVariable[] newRanges) { for (int i = 0; i < indexStartAggregates; i++) { exprColumns[i].replaceRangeVariables(ranges, newRanges); } if (queryCondition != null) { queryCondition.replaceRangeVariables(ranges, newRanges); } if (havingCondition != null) { havingCondition.replaceRangeVariables(ranges, newRanges); } for (int i = 0, len = rangeVariables.length; i < len; i++) { rangeVariables[i].getSubqueries(); } } /** * Not for views. Only used on root node. */ public void setReturningResult() { setReturningResultSet(); acceptsSequences = true; isTopLevel = true; } void setReturningResultSet() { persistenceScope = TableBase.SCOPE_SESSION; } public boolean isSingleColumn() { return indexLimitVisible == 1; } public String[] getColumnNames() { String[] names = new String[indexLimitVisible]; for (int i = 0; i < indexLimitVisible; i++) { names[i] = exprColumns[i].getAlias(); } return names; } public Type[] getColumnTypes() { if (columnTypes.length == indexLimitVisible) { return columnTypes; } Type[] types = new Type[indexLimitVisible]; ArrayUtil.copyArray(columnTypes, types, types.length); return types; } public int getColumnCount() { return indexLimitVisible; } public int[] getBaseTableColumnMap() { return columnMap; } public Expression getCheckCondition() { return queryCondition; } void getBaseTableNames(OrderedHashSet set) { for (int i = 0; i < rangeVariables.length; i++) { Table rangeTable = rangeVariables[i].rangeTable; HsqlName name = rangeTable.getName(); if (rangeTable.isReadOnly() || rangeTable.isTemp()) { continue; } if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) { continue; } set.add(name); } } /** * returns true if almost equivalent */ boolean isEquivalent(QueryExpression other) { if (!(other instanceof QuerySpecification)) { return false; } QuerySpecification otherSpec = (QuerySpecification) other; if (!Expression.equals(exprColumns, otherSpec.exprColumns)) { return false; } if (!Expression.equals(queryCondition, otherSpec.queryCondition)) { return false; } if (rangeVariables.length != otherSpec.rangeVariables.length) { return false; } for (int i = 0; i < rangeVariables.length; i++) { if (rangeVariables[i].getTable() != otherSpec.rangeVariables[i].getTable()) { return false; } } return true; } }