blob: bbae160efd5a3423a5ef5b963e0c1a6c73939ea4 [file] [log] [blame]
/* 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;
}
}