/* Copyright (c) 2001-2018, 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.
SimpleName;
import org.hsqldb.
ParserDQL.
CompileContext;
import org.hsqldb.error.
Error;
import org.hsqldb.error.
ErrorCode;
import org.hsqldb.index.
Index;
import org.hsqldb.lib.
ArrayUtil;
import org.hsqldb.lib.
HashMap;
import org.hsqldb.lib.
HashMappedList;
import org.hsqldb.lib.
HashSet;
import org.hsqldb.lib.
HsqlArrayList;
import org.hsqldb.lib.
HsqlList;
import org.hsqldb.lib.
OrderedHashSet;
import org.hsqldb.lib.
OrderedIntHashSet;
import org.hsqldb.lib.
OrderedLongHashSet;
import org.hsqldb.navigator.
RangeIterator;
import org.hsqldb.navigator.
RowIterator;
import org.hsqldb.persist.
PersistentStore;
import org.hsqldb.types.
Type;
/**
* Metadata for range variables, including conditions.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.4.1
* @since 1.9.0
*/
public class
RangeVariable {
static final
RangeVariable[]
emptyArray = new
RangeVariable[]{};
//
public static final int
TABLE_RANGE = 1;
public static final int
TRANSITION_RANGE = 2;
public static final int
PARAMETER_RANGE = 3;
public static final int
VARIALBE_RANGE = 4;
public static final int
PLACEHOLDER_RANGE = 5;
//
private static final
RowIterator emptyIterator = new
RangeIteratorEmpty();
//
Table rangeTable;
final
SimpleName tableAlias;
private
OrderedHashSet columnAliases;
private
SimpleName[]
columnAliasNames;
private
OrderedHashSet columnNames;
OrderedHashSet namedJoinColumns;
HashMap namedJoinColumnExpressions;
boolean[]
columnsInGroupBy;
boolean
hasKeyedColumnInGroupBy;
boolean[]
usedColumns;
boolean[]
updatedColumns;
boolean[]
namedJoinColumnCheck;
//
RangeVariableConditions[]
joinConditions;
RangeVariableConditions[]
whereConditions;
int
subRangeCount;
// non-index conditions
Expression joinCondition;
//
boolean
isLateral;
boolean
isLeftJoin; // table joined with LEFT / FULL OUTER JOIN
boolean
isRightJoin; // table joined with RIGHT / FULL OUTER JOIN
boolean
isJoin;
//
boolean
hasLateral;
boolean
hasLeftJoin;
boolean
hasRightJoin;
//
int
level;
//
int
indexDistinctCount;
//
int
rangePositionInJoin;
//
int
rangePosition;
//
boolean
isViewSubquery;
// for variable and parameter lists
HashMappedList variables;
// variable, parameter, table
int
rangeType;
//
boolean
isGenerated;
public
RangeVariable(
HashMappedList variables,
SimpleName rangeName,
boolean
isVariable, int
rangeType) {
this.
variables =
variables;
this.
rangeType =
rangeType;
rangeTable = null;
tableAlias =
rangeName;
columnsInGroupBy = null;
usedColumns = null;
joinConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, true) };
whereConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, false) };
switch (
rangeType) {
case
TRANSITION_RANGE :
usedColumns = new boolean[
variables.
size()];
case
PARAMETER_RANGE :
case
VARIALBE_RANGE :
case
PLACEHOLDER_RANGE :
break;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "RangeVariable");
}
}
public
RangeVariable(
Table table,
SimpleName alias,
OrderedHashSet columnList,
SimpleName[]
columnNameList,
CompileContext compileContext) {
rangeType =
TABLE_RANGE;
rangeTable =
table;
tableAlias =
alias;
columnAliases =
columnList;
columnAliasNames =
columnNameList;
joinConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, true) };
whereConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, false) };
compileContext.
registerRangeVariable(this);
if (
rangeTable.
getColumnCount() != 0) {
setRangeTableVariables();
}
}
public
RangeVariable(
Table table, int
position) {
rangeType =
TABLE_RANGE;
rangeTable =
table;
tableAlias = null;
columnsInGroupBy =
rangeTable.
getNewColumnCheckList();
usedColumns =
rangeTable.
getNewColumnCheckList();
rangePosition =
position;
joinConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, true) };
whereConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, false) };
}
public void
setRangeTableVariables() {
if (
columnAliasNames != null
&&
rangeTable.
getColumnCount() !=
columnAliasNames.length) {
throw
Error.
error(
ErrorCode.
X_42593);
}
columnsInGroupBy =
rangeTable.
getNewColumnCheckList();
usedColumns =
rangeTable.
getNewColumnCheckList();
joinConditions[0].
rangeIndex =
rangeTable.
getPrimaryIndex();
whereConditions[0].
rangeIndex =
rangeTable.
getPrimaryIndex();
}
public void
setJoinType(boolean
isLeft, boolean
isRight) {
isJoin = true;
isLeftJoin =
isLeft;
isRightJoin =
isRight;
if (
isRightJoin) {
whereConditions[0].
rangeIndex =
rangeTable.
getPrimaryIndex();
}
}
public void
addNamedJoinColumns(
OrderedHashSet columns) {
namedJoinColumns =
columns;
}
public void
addColumn(int
columnIndex) {
if (
usedColumns != null) {
usedColumns[
columnIndex] = true;
}
}
public void
addAllColumns() {
if (
usedColumns != null) {
ArrayUtil.
fillArray(
usedColumns, true);
}
}
public void
addNamedJoinColumnExpression(
String name,
Expression e,
int
position) {
if (
namedJoinColumnExpressions == null) {
namedJoinColumnExpressions = new
HashMap();
}
namedJoinColumnExpressions.
put(
name,
e);
if (
namedJoinColumnCheck == null) {
namedJoinColumnCheck =
rangeTable.
getNewColumnCheckList();
}
namedJoinColumnCheck[
position] = true;
}
public
ExpressionColumn getColumnExpression(
String name) {
return
namedJoinColumnExpressions == null ? null
: (
ExpressionColumn)
namedJoinColumnExpressions
.
get(
name);
}
public
Table getTable() {
return
rangeTable;
}
public boolean
hasAnyTerminalCondition() {
for (int
i = 0;
i <
joinConditions.length;
i++) {
if (
joinConditions[0].
terminalCondition != null) {
return true;
}
}
for (int
i = 0;
i <
whereConditions.length;
i++) {
if (
whereConditions[0].
terminalCondition != null) {
return true;
}
}
return false;
}
public boolean
hasAnyIndexCondition() {
for (int
i = 0;
i <
joinConditions.length;
i++) {
if (
joinConditions[0].
indexedColumnCount > 0) {
return true;
}
}
for (int
i = 0;
i <
whereConditions.length;
i++) {
if (
whereConditions[0].
indexedColumnCount > 0) {
return true;
}
}
return false;
}
public boolean
hasSingleIndexCondition() {
return
joinConditions.length == 1
&&
joinConditions[0].
indexedColumnCount > 0;
}
public boolean
setDistinctColumnsOnIndex(int[]
colMap) {
if (
joinConditions.length != 1) {
return false;
}
int[]
indexColMap =
joinConditions[0].
rangeIndex.
getColumns();
if (
colMap.length >
indexColMap.length) {
return false;
}
if (
colMap.length ==
indexColMap.length) {
if (
ArrayUtil.
haveEqualSets(
colMap,
indexColMap,
colMap.length)) {
indexDistinctCount =
colMap.length;
return true;
}
}
if (
ArrayUtil.
haveEqualArrays(
colMap,
indexColMap,
colMap.length)) {
indexDistinctCount =
colMap.length;
return true;
}
return false;
}
/**
* Used for sort
*/
public
Index getSortIndex() {
if (
joinConditions.length == 1) {
return
joinConditions[0].
rangeIndex;
} else {
return null;
}
}
/**
* Used for sort
*/
public boolean
setSortIndex(
Index index, boolean
reversed) {
if (
joinConditions.length == 1) {
if (
joinConditions[0].
indexedColumnCount == 0) {
joinConditions[0].
rangeIndex =
index;
joinConditions[0].
reversed =
reversed;
return true;
}
}
return false;
}
public boolean
reverseOrder() {
if (
joinConditions.length == 1) {
joinConditions[0].
reverseIndexCondition();
return true;
}
return false;
}
public
OrderedHashSet getColumnNames() {
if (
columnNames == null) {
columnNames = new
OrderedHashSet();
rangeTable.
getColumnNames(this.
usedColumns,
columnNames);
}
return
columnNames;
}
public
OrderedHashSet getUniqueColumnNameSet() {
OrderedHashSet set = new
OrderedHashSet();
if (
columnAliases != null) {
set.
addAll(
columnAliases);
return
set;
}
for (int
i = 0;
i <
rangeTable.
columnList.
size();
i++) {
String name =
rangeTable.
getColumn(
i).
getName().
name;
boolean
added =
set.
add(
name);
if (!
added) {
throw
Error.
error(
ErrorCode.
X_42578,
name);
}
}
return
set;
}
public int
findColumn(
String schemaName,
String tableName,
String columnName) {
if (
namedJoinColumnExpressions != null
&&
namedJoinColumnExpressions.
containsKey(
columnName)) {
if (
tableName != null && !
resolvesTableName(
tableName)) {
return -1;
}
}
if (
resolvesSchemaAndTableName(
schemaName,
tableName)) {
return
findColumn(
columnName);
}
return -1;
}
/**
* Returns index for column
*
* @param columnName name of column
* @return int index or -1 if not found
*/
private int
findColumn(
String columnName) {
if (
variables != null) {
return
variables.
getIndex(
columnName);
} else if (
columnAliases != null) {
return
columnAliases.
getIndex(
columnName);
} else {
return
rangeTable.
findColumn(
columnName);
}
}
public
ColumnSchema getColumn(int
i) {
if (
variables == null) {
return
rangeTable.
getColumn(
i);
} else {
return (
ColumnSchema)
variables.
get(
i);
}
}
public
SimpleName getColumnAlias(int
i) {
if (
columnAliases == null) {
return
rangeTable.
getColumn(
i).
getName();
} else {
return
columnAliasNames[
i];
}
}
public boolean
hasColumnAlias() {
return
columnAliases != null;
}
public boolean
hasTableAlias() {
return
tableAlias != null;
}
public boolean
isVariable() {
return
variables != null;
}
public
SimpleName getTableAlias() {
return
tableAlias == null ?
rangeTable.
getName()
:
tableAlias;
}
public
RangeVariable getRangeForTableName(
String name) {
if (
resolvesTableName(
name)) {
return this;
}
return null;
}
private boolean
resolvesSchemaAndTableName(
String schemaName,
String tableName) {
return
resolvesSchemaName(
schemaName) &&
resolvesTableName(
tableName);
}
private boolean
resolvesTableName(
String name) {
if (
name == null) {
return true;
}
if (
variables != null) {
if (
tableAlias != null) {
return
name.
equals(
tableAlias.
name);
}
return false;
}
if (
tableAlias == null) {
if (
name.
equals(
rangeTable.
getName().
name)) {
return true;
}
} else if (
name.
equals(
tableAlias.
name)) {
return true;
}
return false;
}
private boolean
resolvesSchemaName(
String name) {
if (
name == null) {
return true;
}
if (
variables != null) {
return false;
}
if (
tableAlias != null) {
return false;
}
return
name.
equals(
rangeTable.
getSchemaName().
name);
}
/**
* Add all columns to a list of expressions
*/
public void
addTableColumns(
HsqlArrayList exprList) {
if (
namedJoinColumns != null) {
int
count =
exprList.
size();
int
position = 0;
for (int
i = 0;
i <
count;
i++) {
Expression e = (
Expression)
exprList.
get(
i);
String columnName =
e.
getColumnName();
if (
namedJoinColumns.
contains(
columnName)) {
if (
position !=
i) {
exprList.
remove(
i);
exprList.
add(
position,
e);
}
e =
getColumnExpression(
columnName);
exprList.
set(
position,
e);
position++;
}
}
}
addTableColumns(
exprList,
exprList.
size(),
namedJoinColumns);
}
/**
* Add all columns to a list of expressions
*/
public int
addTableColumns(
HsqlArrayList exprList, int
position,
HashSet exclude) {
Table table =
getTable();
int
count =
table.
getColumnCount();
for (int
i = 0;
i <
count;
i++) {
ColumnSchema column =
table.
getColumn(
i);
String columnName =
columnAliases == null ?
column.
getName().
name
: (
String)
columnAliases
.
get(
i);
if (
exclude != null &&
exclude.
contains(
columnName)) {
continue;
}
Expression e = new
ExpressionColumn(this,
i);
exprList.
add(
position++,
e);
}
return
position;
}
public void
addTableColumns(
RangeVariable subRange,
Expression expression,
HashSet exclude) {
if (
subRange == this) {
Table table =
getTable();
int
count =
table.
getColumnCount();
addTableColumns(
expression, 0,
count,
exclude);
}
}
protected int
getFirstColumnIndex(
RangeVariable subRange) {
if (
subRange == this) {
return 0;
}
return -1;
}
protected void
addTableColumns(
Expression expression, int
start,
int
count,
HashSet exclude) {
Table table =
getTable();
HsqlArrayList list = new
HsqlArrayList();
for (int
i =
start;
i <
start +
count;
i++) {
ColumnSchema column =
table.
getColumn(
i);
String columnName =
columnAliases == null ?
column.
getName().
name
: (
String)
columnAliases
.
get(
i);
if (
exclude != null &&
exclude.
contains(
columnName)) {
continue;
}
Expression e = new
ExpressionColumn(this,
i);
list.
add(
e);
}
Expression[]
nodes = new
Expression[
list.
size()];
list.
toArray(
nodes);
expression.
nodes =
nodes;
}
/**
* Removes reference to Index to avoid possible memory leaks after alter
* table or drop index
*/
public void
setForCheckConstraint() {
joinConditions[0].
rangeIndex = null;
whereConditions[0].
rangeIndex = null;
rangePosition = 0;
}
/**
* used before condition processing
*/
public
Expression getJoinCondition() {
return
joinCondition;
}
public void
addJoinCondition(
Expression e) {
joinCondition =
ExpressionLogical.
andExpressions(
joinCondition,
e);
}
public void
resetConditions() {
Index index =
joinConditions[0].
rangeIndex;
joinConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, true) };
joinConditions[0].
rangeIndex =
index;
//
index =
whereConditions[0].
rangeIndex;
whereConditions = new
RangeVariableConditions[]{
new
RangeVariableConditions(this, false) };
whereConditions[0].
rangeIndex =
index;
}
public
OrderedHashSet getSubqueries() {
OrderedHashSet set = null;
if (
joinCondition != null) {
set =
joinCondition.
collectAllSubqueries(
set);
}
if (
rangeTable instanceof
TableDerived) {
QueryExpression queryExpression =
((
TableDerived)
rangeTable).
getQueryExpression();
if (
queryExpression == null) {
Expression dataExpression =
((
TableDerived)
rangeTable).
getDataExpression();
if (
dataExpression != null) {
if (
set == null) {
set = new
OrderedHashSet();
}
OrderedHashSet.
addAll(
set,
dataExpression.
getSubqueries());
}
} else {
OrderedHashSet temp =
queryExpression.
getSubqueries();
set =
OrderedHashSet.
addAll(
set,
temp);
set =
OrderedHashSet.
add(
set,
rangeTable);
}
}
return
set;
}
public
OrderedHashSet collectAllExpressions(
OrderedHashSet set,
OrderedIntHashSet typeSet,
OrderedIntHashSet stopAtTypeSet) {
if (
joinCondition != null) {
set =
joinCondition.
collectAllExpressions(
set,
typeSet,
stopAtTypeSet);
}
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
Expression dataExpression =
rangeTable.
getDataExpression();
if (
queryExpression != null) {
set =
queryExpression.
collectAllExpressions(
set,
typeSet,
stopAtTypeSet);
}
if (
dataExpression != null) {
set =
dataExpression.
collectAllExpressions(
set,
typeSet,
stopAtTypeSet);
}
return
set;
}
public void
replaceColumnReferences(
RangeVariable range,
Expression[]
list) {
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
Expression dataExpression =
rangeTable.
getDataExpression();
if (
dataExpression != null) {
dataExpression =
dataExpression.
replaceColumnReferences(
range,
list);
}
if (
queryExpression != null) {
queryExpression.
replaceColumnReferences(
range,
list);
}
if (
joinCondition != null) {
joinCondition =
joinCondition.
replaceColumnReferences(
range,
list);
}
for (int
i = 0;
i <
joinConditions.length;
i++) {
joinConditions[
i].
replaceColumnReferences(
range,
list);
}
for (int
i = 0;
i <
whereConditions.length;
i++) {
whereConditions[
i].
replaceColumnReferences(
range,
list);
}
}
public void
replaceRangeVariables(
RangeVariable[]
ranges,
RangeVariable[]
newRanges) {
if (
joinCondition != null) {
joinCondition.
replaceRangeVariables(
ranges,
newRanges);
}
}
public void
replaceExpressions(
OrderedHashSet expressions,
int
resultRangePosition) {
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
Expression dataExpression =
rangeTable.
getDataExpression();
if (
dataExpression != null) {
dataExpression =
dataExpression.
replaceExpressions(
expressions,
resultRangePosition);
}
if (
queryExpression != null) {
queryExpression.
replaceExpressions(
expressions,
resultRangePosition);
}
if (
joinCondition != null) {
joinCondition =
joinCondition.
replaceExpressions(
expressions,
resultRangePosition);
}
for (int
i = 0;
i <
joinConditions.length;
i++) {
joinConditions[
i].
replaceExpressions(
expressions,
resultRangePosition);
}
for (int
i = 0;
i <
whereConditions.length;
i++) {
whereConditions[
i].
replaceExpressions(
expressions,
resultRangePosition);
}
}
public void
resolveRangeTable(
Session session,
RangeGroup rangeGroup,
RangeGroup[]
rangeGroups) {
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
Expression dataExpression =
rangeTable.
getDataExpression();
if (
queryExpression == null &&
dataExpression == null) {
return;
}
rangeGroups = (
RangeGroup[])
ArrayUtil.
toAdjustedArray(
rangeGroups,
rangeGroup,
rangeGroups.length, 1);
if (
dataExpression != null) {
HsqlList unresolved =
dataExpression.
resolveColumnReferences(
session,
RangeGroup.
emptyGroup,
rangeGroups, null);
unresolved =
Expression.
resolveColumnSet(
session,
RangeVariable.
emptyArray,
RangeGroup.
emptyArray,
unresolved);
ExpressionColumn.
checkColumnsResolved(
unresolved);
dataExpression.
resolveTypes(
session, null);
setRangeTableVariables();
}
if (
queryExpression != null) {
queryExpression.
resolveReferences(
session,
rangeGroups);
HsqlList unresolved =
queryExpression.
getUnresolvedExpressions();
unresolved =
Expression.
resolveColumnSet(
session,
RangeVariable.
emptyArray,
RangeGroup.
emptyArray,
unresolved);
ExpressionColumn.
checkColumnsResolved(
unresolved);
queryExpression.
resolveTypesPartOne(
session);
queryExpression.
resolveTypesPartTwo(
session);
rangeTable.
prepareTable(
session);
setRangeTableVariables();
}
}
void
resolveRangeTableTypes(
Session session,
RangeVariable[]
ranges) {
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
if (
queryExpression != null) {
if (
queryExpression instanceof
QuerySpecification) {
QuerySpecification qs = (
QuerySpecification)
queryExpression;
if (
qs.
isGrouped ||
qs.
isAggregated ||
qs.
isOrderSensitive) {
//
} else {
moveConditionsToInner(
session,
ranges);
}
}
queryExpression.
resolveTypesPartThree(
session);
}
}
void
moveConditionsToInner(
Session session,
RangeVariable[]
ranges) {
Expression[]
colExpr;
int
exclude;
HsqlArrayList conditionsList;
Expression condition = null;
if (
whereConditions.length > 1) {
return;
}
if (
joinConditions.length > 1) {
return;
}
for (int
i = 0;
i <
ranges.length;
i++) {
if (
ranges[
i].
isLeftJoin ||
ranges[
i].
isRightJoin) {
return;
}
}
exclude =
ArrayUtil.
find(
ranges, this);
conditionsList = new
HsqlArrayList();
addConditionsToList(
conditionsList,
joinConditions[0].
indexCond);
if (
joinConditions[0].
indexCond != null
&&
joinConditions[0].
indexCond[0]
!=
joinConditions[0].
indexEndCond[0]) {
addConditionsToList(
conditionsList,
joinConditions[0].
indexEndCond);
}
addConditionsToList(
conditionsList,
whereConditions[0].
indexCond);
addConditionsToList(
conditionsList,
whereConditions[0].
indexEndCond);
RangeVariableResolver.
decomposeAndConditions(
session,
joinConditions[0].
nonIndexCondition,
conditionsList);
RangeVariableResolver.
decomposeAndConditions(
session,
whereConditions[0].
nonIndexCondition,
conditionsList);
for (int
i =
conditionsList.
size() - 1;
i >= 0;
i--) {
Expression e = (
Expression)
conditionsList.
get(
i);
if (
e == null ||
e.
isTrue() ||
e.
hasReference(
ranges,
exclude)) {
conditionsList.
remove(
i);
}
}
if (
conditionsList.
size() == 0) {
if (
rangeTable.
isView()) {
((
TableDerived)
rangeTable).
resetToView();
}
return;
}
OrderedHashSet subquerySet = null;
for (int
i = 0;
i <
conditionsList.
size();
i++) {
Expression e = (
Expression)
conditionsList.
get(
i);
subquerySet =
e.
collectAllSubqueries(
subquerySet);
if (
subquerySet != null) {
return;
}
}
QueryExpression queryExpression =
rangeTable.
getQueryExpression();
colExpr = ((
QuerySpecification)
queryExpression).
exprColumns;
for (int
i = 0;
i <
conditionsList.
size();
i++) {
Expression e = (
Expression)
conditionsList.
get(
i);
e =
e.
duplicate();
e =
e.
replaceColumnReferences(this,
colExpr);
OrderedHashSet set =
e.
collectRangeVariables(null);
if (
set != null) {
for (int
j = 0;
j <
set.
size();
j++) {
RangeVariable range = (
RangeVariable)
set.
get(
j);
if (this !=
range
&&
range.
rangeType ==
RangeVariable.
TABLE_RANGE) {
queryExpression.
setCorrelated();
break;
}
}
}
condition =
ExpressionLogical.
andExpressions(
condition,
e);
}
queryExpression.
addExtraConditions(
condition);
}
private static void
addConditionsToList(
HsqlArrayList list,
Expression[]
array) {
if (
array == null) {
return;
}
for (int
i = 0;
i <
array.length;
i++) {
if (
array[
i] != null) {
if (
array[
i].
isSingleColumnCondition
||
array[
i].
isSingleColumnNull
||
array[
i].
isSingleColumnNotNull) {
list.
add(
array[
i]);
}
}
}
}
/**
* Retrieves a String representation of this obejct. <p>
*
* The returned String describes this object's table, alias
* access mode, index, join mode, Start, End and And conditions.
*
* @return a String representation of this object
*/
public
String describe(
Session session, int
blanks) {
StringBuffer sb;
StringBuffer b = new
StringBuffer(
blanks);
for (int
i = 0;
i <
blanks;
i++) {
b.
append(' ');
}
sb = new
StringBuffer();
String temp = "INNER";
if (
isLeftJoin) {
temp = "LEFT OUTER";
if (
isRightJoin) {
temp = "FULL";
}
} else if (
isRightJoin) {
temp = "RIGHT OUTER";
}
sb.
append(
b).
append("join type=").
append(
temp).
append("\n");
sb.
append(
b).
append("table=").
append(
rangeTable.
getName().
name).
append(
"\n");
if (
tableAlias != null) {
sb.
append(
b).
append("alias=").
append(
tableAlias.
name).
append("\n");
}
RangeVariableConditions[]
conditions =
joinConditions;
if (
whereConditions[0].
hasIndexCondition()) {
conditions =
whereConditions;
}
sb.
append(
b).
append("cardinality=");
sb.
append(
rangeTable.
getRowStore(
session).
elementCount()).
append("\n");
boolean
fullScan = !
conditions[0].
hasIndexCondition();
sb.
append(
b);
if (
conditions ==
whereConditions) {
if (
joinConditions[0].
nonIndexCondition != null) {
sb.
append("join condition = [");
sb.
append(
joinConditions[0].
nonIndexCondition.
describe(
session,
blanks));
sb.
append(
b).
append("]\n");
sb.
append(
b);
}
}
sb.
append("access=").
append(
fullScan ? "FULL SCAN"
: "INDEX PRED").
append("\n");
for (int
i = 0;
i <
conditions.length;
i++) {
if (
i > 0) {
sb.
append(
b).
append("OR condition = [");
} else {
sb.
append(
b);
if (
conditions ==
whereConditions) {
sb.
append("where condition = [");
} else {
sb.
append("join condition = [");
}
}
sb.
append(
conditions[
i].
describe(
session,
blanks + 2));
sb.
append(
b).
append("]\n");
}
if (
conditions ==
joinConditions) {
sb.
append(
b);
if (
whereConditions[0].
nonIndexCondition != null) {
sb.
append("where condition = [");
sb.
append(
whereConditions[0].
nonIndexCondition.
describe(
session,
blanks));
sb.
append(
b).
append("]\n");
sb.
append(
b);
}
}
return
sb.
toString();
}
public
RangeIteratorMain getIterator(
Session session) {
RangeIteratorMain it;
if (this.
isRightJoin) {
it = new
RangeIteratorRight(
session, this, null);
} else {
it = new
RangeIteratorMain(
session, this);
}
session.
sessionContext.
setRangeIterator(
it);
return
it;
}
public static
RangeIterator getIterator(
Session session,
RangeVariable[]
rangeVars) {
if (
rangeVars.length == 1) {
return
rangeVars[0].
getIterator(
session);
}
RangeIteratorMain[]
iterators =
new
RangeIteratorMain[
rangeVars.length];
for (int
i = 0;
i <
rangeVars.length;
i++) {
iterators[
i] =
rangeVars[
i].
getIterator(
session);
}
return new
RangeIteratorJoined(
iterators);
}
public static class
RangeIteratorBase implements
RangeIterator {
Session session;
int
rangePosition;
RowIterator it =
emptyIterator;
PersistentStore store;
boolean
isBeforeFirst;
RangeVariable rangeVar;
private
RangeIteratorBase() {}
public boolean
isBeforeFirst() {
return
isBeforeFirst;
}
public boolean
next() {
if (
isBeforeFirst) {
isBeforeFirst = false;
} else {
if (
it ==
emptyIterator) {
return false;
}
}
if (
session.
abortTransaction) {
throw
Error.
error(
ErrorCode.
X_40000);
}
if (
session.
abortAction) {
throw
Error.
error(
ErrorCode.
X_40502);
}
if (
it.
next()) {
return true;
} else {
return false;
}
}
public
Row getCurrentRow() {
return
it.
getCurrentRow();
}
public
Object[]
getCurrent() {
return
it.
getCurrent();
}
public
Object getField(int
i) {
return
it.
getField(
i);
}
public void
setCurrent(
Object[]
data) {
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "RangeVariable");
}
public long
getRowId() {
return ((long)
rangeVar.
rangeTable.
getId() << 32) +
it.
getRowId();
}
public void
removeCurrent() {}
public void
reset() {
it.
release();
it =
emptyIterator;
isBeforeFirst = true;
}
public int
getRangePosition() {
return
rangePosition;
}
public boolean
hasNext() {
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "RangeVariable");
}
public void
release() {
it.
release();
}
}
public static class
RangeIteratorMain extends
RangeIteratorBase {
boolean
hasLeftOuterRow;
boolean
isFullIterator;
RangeVariableConditions[]
conditions;
RangeVariableConditions[]
whereConditions;
RangeVariableConditions[]
joinConditions;
int
condIndex = 0;
//
OrderedLongHashSet lookup;
//
Object[]
currentJoinData = null;
RangeIteratorMain() {
super();
}
private
RangeIteratorMain(
Session session,
RangeVariable rangeVar) {
this.
rangePosition =
rangeVar.
rangePosition;
this.
store =
rangeVar.
rangeTable.
getRowStore(
session);
this.
session =
session;
this.
rangeVar =
rangeVar;
isBeforeFirst = true;
whereConditions =
rangeVar.
whereConditions;
joinConditions =
rangeVar.
joinConditions;
if (
rangeVar.
isRightJoin) {
lookup = new
OrderedLongHashSet();
}
conditions =
rangeVar.
joinConditions;
if (
rangeVar.
whereConditions[0].
hasIndexCondition()) {
conditions =
rangeVar.
whereConditions;
}
}
public boolean
isBeforeFirst() {
return
isBeforeFirst;
}
public boolean
next() {
if (
session.
abortTransaction) {
throw
Error.
error(
ErrorCode.
X_40000);
}
if (
session.
abortAction) {
throw
Error.
error(
ErrorCode.
X_40502);
}
while (
condIndex <
conditions.length) {
if (
isBeforeFirst) {
isBeforeFirst = false;
initialiseIterator();
}
boolean
result =
findNext();
if (
result) {
return true;
}
it.
release();
it =
emptyIterator;
isBeforeFirst = true;
condIndex++;
}
condIndex = 0;
return false;
}
public void
removeCurrent() {}
public void
reset() {
it.
release();
it =
emptyIterator;
isBeforeFirst = true;
condIndex = 0;
}
public int
getRangePosition() {
return
rangeVar.
rangePosition;
}
/**
*/
protected void
initialiseIterator() {
if (
condIndex == 0) {
hasLeftOuterRow =
rangeVar.
isLeftJoin;
}
if (
conditions[
condIndex].
isFalse) {
it =
conditions[
condIndex].
rangeIndex.
emptyIterator();
return;
}
rangeVar.
rangeTable.
materialiseCorrelated(
session);
if (
conditions[
condIndex].
indexCond == null) {
if (
conditions[
condIndex].
reversed) {
it =
conditions[
condIndex].
rangeIndex.
lastRow(
session,
store,
rangeVar.
indexDistinctCount, null);
} else {
it =
conditions[
condIndex].
rangeIndex.
firstRow(
session,
store,
rangeVar.
indexDistinctCount, null);
}
} else {
getFirstRow();
if (!
conditions[
condIndex].
isJoin) {
hasLeftOuterRow = false;
}
}
}
private void
getFirstRow() {
if (
currentJoinData == null
||
currentJoinData.length
<
conditions[
condIndex].
indexedColumnCount) {
currentJoinData =
new
Object[
conditions[
condIndex].
indexedColumnCount];
}
int
opType =
conditions[
condIndex].
opType;
for (int
i = 0;
i <
conditions[
condIndex].
indexedColumnCount;
i++) {
int
range = 0;
int
tempType =
conditions[
condIndex].
opTypes[
i];
if (
tempType ==
OpTypes.
IS_NULL ||
tempType ==
OpTypes.
NOT
||
tempType ==
OpTypes.
MAX) {
currentJoinData[
i] = null;
continue;
}
Type valueType =
conditions[
condIndex].
indexCond[
i].
getRightNode()
.
getDataType();
Object value =
conditions[
condIndex].
indexCond[
i].
getRightNode().
getValue(
session);
Type targetType =
conditions[
condIndex].
indexCond[
i].
getLeftNode()
.
getDataType();
if (
i == 0 &&
value == null) {
it =
conditions[
condIndex].
rangeIndex.
emptyIterator();
return;
}
if (
targetType !=
valueType) {
range =
targetType.
compareToTypeRange(
value);
if (
range == 0) {
if (
targetType.
typeComparisonGroup
!=
valueType.
typeComparisonGroup) {
value =
targetType.
convertToType(
session,
value,
valueType);
}
}
}
if (
i == 0) {
int
exprType =
conditions[
condIndex].
indexCond[0].
getType();
if (
range < 0) {
switch (
exprType) {
case
OpTypes.
GREATER :
case
OpTypes.
GREATER_EQUAL :
case
OpTypes.
GREATER_EQUAL_PRE :
opType =
OpTypes.
NOT;
value = null;
break;
default :
it =
conditions[
condIndex].
rangeIndex
.
emptyIterator();
return;
}
} else if (
range > 0) {
switch (
exprType) {
case
OpTypes.
NOT :
value = null;
break;
case
OpTypes.
SMALLER :
case
OpTypes.
SMALLER_EQUAL :
if (
conditions[
condIndex].
reversed) {
opType =
OpTypes.
MAX;
value = null;
break;
}
default :
it =
conditions[
condIndex].
rangeIndex
.
emptyIterator();
return;
}
}
}
currentJoinData[
i] =
value;
}
it =
conditions[
condIndex].
rangeIndex.
findFirstRow(
session,
store,
currentJoinData,
conditions[
condIndex].
indexedColumnCount,
rangeVar.
indexDistinctCount,
opType,
conditions[
condIndex].
reversed, null);
}
/**
* Advances to the next available value. <p>
*
* @return true if a next value is available upon exit
*/
private boolean
findNext() {
boolean
result = false;
while (true) {
if (
session.
abortTransaction) {
throw
Error.
error(
ErrorCode.
X_40000);
}
if (
session.
abortAction) {
throw
Error.
error(
ErrorCode.
X_40502);
}
if (
it.
next()) {}
else {
it =
emptyIterator;
break;
}
if (
conditions[
condIndex].
terminalCondition != null) {
if (!
conditions[
condIndex].
terminalCondition.
testCondition(
session)) {
break;
}
}
if (
conditions[
condIndex].
indexEndCondition != null) {
if (!
conditions[
condIndex].
indexEndCondition.
testCondition(
session)) {
if (!
conditions[
condIndex].
isJoin) {
hasLeftOuterRow = false;
}
break;
}
}
if (
joinConditions[
condIndex].
nonIndexCondition != null) {
if (!
joinConditions[
condIndex].
nonIndexCondition
.
testCondition(
session)) {
continue;
}
}
if (
whereConditions[
condIndex].
nonIndexCondition != null) {
if (!
whereConditions[
condIndex].
nonIndexCondition
.
testCondition(
session)) {
hasLeftOuterRow = false;
addFoundRow();
continue;
}
}
Expression e =
conditions[
condIndex].
excludeConditions;
if (
e != null &&
e.
testCondition(
session)) {
continue;
}
addFoundRow();
hasLeftOuterRow = false;
return true;
}
it.
release();
it =
emptyIterator;
if (
hasLeftOuterRow &&
condIndex ==
conditions.length - 1) {
result =
(
whereConditions[
condIndex].
nonIndexCondition == null
||
whereConditions[
condIndex].
nonIndexCondition
.
testCondition(
session));
hasLeftOuterRow = false;
}
return
result;
}
private void
addFoundRow() {
if (
rangeVar.
isRightJoin) {
long
position =
it.
getRowId();
lookup.
add(
position);
}
}
}
public static class
RangeIteratorRight extends
RangeIteratorMain {
private
RangeIteratorRight(
Session session,
RangeVariable rangeVar,
RangeIteratorMain main) {
super(
session,
rangeVar);
isFullIterator = true;
}
boolean
isOnRightOuterRows;
public void
setOnOuterRows() {
conditions =
rangeVar.
whereConditions;
isOnRightOuterRows = true;
hasLeftOuterRow = false;
condIndex = 0;
initialiseIterator();
}
public boolean
next() {
if (
isOnRightOuterRows) {
if (
it ==
emptyIterator) {
return false;
}
return
findNextRight();
} else {
return super.next();
}
}
private boolean
findNextRight() {
boolean
result = false;
while (true) {
if (
it.
next()) {}
else {
it =
emptyIterator;
break;
}
if (
conditions[
condIndex].
indexEndCondition != null
&& !
conditions[
condIndex].
indexEndCondition
.
testCondition(
session)) {
break;
}
if (
conditions[
condIndex].
nonIndexCondition != null
&& !
conditions[
condIndex].
nonIndexCondition
.
testCondition(
session)) {
continue;
}
if (!
lookupAndTest()) {
continue;
}
result = true;
break;
}
if (
result) {
return true;
}
it.
release();
return
result;
}
private boolean
lookupAndTest() {
long
position =
it.
getRowId();
boolean
result = !
lookup.
contains(
position);
if (
result) {
if (
conditions[
condIndex].
nonIndexCondition != null
&& !
conditions[
condIndex].
nonIndexCondition
.
testCondition(
session)) {
result = false;
}
}
return
result;
}
}
public static class
RangeIteratorJoined extends
RangeIteratorBase {
RangeIteratorMain[]
rangeIterators;
int
currentIndex = 0;
RangeIterator currentRange = null;
public
RangeIteratorJoined(
RangeIteratorMain[]
rangeIterators) {
this.
rangeIterators =
rangeIterators;
isBeforeFirst = true;
}
public
Row getCurrentRow() {
return
currentRange.
getCurrentRow();
}
public
Object[]
getCurrent() {
return
currentRange.
getCurrent();
}
public boolean
isBeforeFirst() {
return
isBeforeFirst;
}
public boolean
next() {
while (
currentIndex >= 0) {
currentRange =
rangeIterators[
currentIndex];
if (
currentRange.
next()) {
if (
currentIndex <
rangeIterators.length - 1) {
currentIndex++;
continue;
}
return true;
} else {
currentRange.
reset();
currentIndex--;
continue;
}
}
currentRange = null;
for (int
i = 0;
i <
rangeIterators.length;
i++) {
rangeIterators[
i].
reset();
}
return false;
}
public void
removeCurrent() {}
public void
release() {
it.
release();
for (int
i = 0;
i <
rangeIterators.length;
i++) {
rangeIterators[
i].
reset();
}
}
public void
reset() {
super.reset();
for (int
i = 0;
i <
rangeIterators.length;
i++) {
rangeIterators[
i].
reset();
}
}
public int
getRangePosition() {
return 0;
}
}
static final class
RangeIteratorEmpty implements
RowIterator {
public
Object getField(int
col) {
return null;
}
public boolean
next() {
return false;
}
public
Row getCurrentRow() {
return null;
}
public
Object[]
getCurrent() {
return null;
}
public boolean
hasNext() {
return false;
}
public long
getPos() {
return -1;
}
public int
getStorageSize() {
return 0;
}
public void
release() {}
public void
removeCurrent() {}
public long
getRowId() {
return 0L;
}
}
static final class
RangeIteratorCheck implements
RangeIterator {
final int
rangePosition;
Object[]
currentData;
RangeIteratorCheck() {
this.
rangePosition = 0;
}
RangeIteratorCheck(int
rangePosition) {
this.
rangePosition =
rangePosition;
}
public
Object getField(int
col) {
return
currentData[
col];
}
public boolean
next() {
return false;
}
public
Row getCurrentRow() {
return null;
}
public
Object[]
getCurrent() {
return
currentData;
}
public boolean
hasNext() {
return false;
}
public long
getPos() {
return -1;
}
public int
getStorageSize() {
return 0;
}
public void
release() {}
public void
removeCurrent() {}
public long
getRowId() {
return 0L;
}
public boolean
isBeforeFirst() {
return false;
}
public void
setCurrent(
Object[]
data) {
this.
currentData =
data;
}
public void
reset() {}
public int
getRangePosition() {
return
rangePosition;
}
}
public static class
RangeVariableConditions {
final
RangeVariable rangeVar;
Expression[]
indexCond;
Expression[]
indexEndCond;
int[]
opTypes;
int[]
opTypesEnd;
Expression indexEndCondition;
int
indexedColumnCount;
Index rangeIndex;
final boolean
isJoin;
Expression excludeConditions;
Expression nonIndexCondition;
Expression terminalCondition;
int
opType;
int
opTypeEnd;
boolean
isFalse;
boolean
reversed;
boolean
hasIndex;
RangeVariableConditions(
RangeVariable rangeVar, boolean
isJoin) {
this.
rangeVar =
rangeVar;
this.
isJoin =
isJoin;
}
RangeVariableConditions(
RangeVariableConditions base) {
this.
rangeVar =
base.
rangeVar;
this.
isJoin =
base.
isJoin;
nonIndexCondition =
base.
nonIndexCondition;
}
boolean
hasIndexCondition() {
return
indexedColumnCount > 0;
}
boolean
hasIndex() {
return
hasIndex;
}
void
addCondition(
Expression e) {
if (
e == null) {
return;
}
if (
e instanceof
ExpressionLogical) {
if (((
ExpressionLogical)
e).
isTerminal) {
terminalCondition =
e;
}
}
nonIndexCondition =
ExpressionLogical.
andExpressions(
nonIndexCondition,
e);
if (
Expression.
EXPR_FALSE.
equals(
nonIndexCondition)) {
isFalse = true;
}
if (
rangeIndex == null ||
rangeIndex.
getColumnCount() == 0) {
return;
}
if (
indexedColumnCount == 0) {
return;
}
if (
e.
getIndexableExpression(
rangeVar) == null) {
return;
}
int
colIndex =
e.
getLeftNode().
getColumnIndex();
int[]
indexCols =
rangeIndex.
getColumns();
switch (
e.
getType()) {
case
OpTypes.
GREATER :
case
OpTypes.
GREATER_EQUAL :
case
OpTypes.
GREATER_EQUAL_PRE : {
// replaces existing condition
if (
opType ==
OpTypes.
NOT) {
if (
indexCols[
indexedColumnCount - 1] ==
colIndex) {
nonIndexCondition =
ExpressionLogical.
andExpressions(
nonIndexCondition,
indexCond[
indexedColumnCount - 1]);
indexCond[
indexedColumnCount - 1] =
e;
opType =
e.
opType;
opTypes[
indexedColumnCount - 1] =
e.
opType;
if (
e.
getType() ==
OpTypes.
GREATER_EQUAL_PRE
&&
indexedColumnCount == 1) {
indexEndCond[
indexedColumnCount - 1] =
ExpressionLogical.
andExpressions(
indexEndCond[
indexedColumnCount - 1],
e.
nodes[2]);
}
}
} else {
addToIndexConditions(
e);
}
break;
}
case
OpTypes.
SMALLER :
case
OpTypes.
SMALLER_EQUAL : {
if (
opType ==
OpTypes.
GREATER
||
opType ==
OpTypes.
GREATER_EQUAL
||
opType ==
OpTypes.
GREATER_EQUAL_PRE
||
opType ==
OpTypes.
NOT) {
if (
opTypeEnd !=
OpTypes.
MAX) {
break;
}
if (
indexCols[
indexedColumnCount - 1] ==
colIndex) {
indexEndCond[
indexedColumnCount - 1] =
e;
indexEndCondition =
ExpressionLogical.
andExpressions(
indexEndCondition,
e);
opTypeEnd =
e.
opType;
opTypesEnd[
indexedColumnCount - 1] =
e.
opType;
}
} else {
addToIndexEndConditions(
e);
}
break;
}
default :
}
}
private boolean
addToIndexConditions(
Expression e) {
if (
opType ==
OpTypes.
EQUAL ||
opType ==
OpTypes.
IS_NULL) {
if (
indexedColumnCount <
rangeIndex.
getColumnCount()) {
if (
rangeIndex.
getColumns()[
indexedColumnCount]
==
e.
getLeftNode().
getColumnIndex()) {
indexCond[
indexedColumnCount] =
e;
opType =
e.
opType;
opTypes[
indexedColumnCount] =
e.
opType;
opTypeEnd =
OpTypes.
MAX;
opTypesEnd[
indexedColumnCount] =
OpTypes.
MAX;
indexedColumnCount++;
return true;
}
}
}
return false;
}
private boolean
addToIndexEndConditions(
Expression e) {
if (
opType ==
OpTypes.
EQUAL ||
opType ==
OpTypes.
IS_NULL) {
if (
indexedColumnCount <
rangeIndex.
getColumnCount()) {
if (
rangeIndex.
getColumns()[
indexedColumnCount]
==
e.
getLeftNode().
getColumnIndex()) {
Expression condition =
ExpressionLogical.
newNotNullCondition(
e.
getLeftNode());
indexCond[
indexedColumnCount] =
condition;
indexEndCond[
indexedColumnCount] =
e;
indexEndCondition =
ExpressionLogical.
andExpressions(
indexEndCondition,
e);
opType =
OpTypes.
NOT;
opTypes[
indexedColumnCount] =
OpTypes.
NOT;
opTypeEnd =
e.
opType;
opTypesEnd[
indexedColumnCount] =
e.
opType;
indexedColumnCount++;
return true;
}
}
}
return false;
}
/**
*
* @param exprList has the same length as index column count
* @param index Index to use
* @param colCount number of columns searched
*/
void
addIndexCondition(
Expression[]
exprList,
Index index,
int
colCount) {
int
indexColCount =
index.
getColumnCount();
rangeIndex =
index;
indexCond = new
Expression[
indexColCount];
indexEndCond = new
Expression[
indexColCount];
opTypes = new int[
indexColCount];
opTypesEnd = new int[
indexColCount];
opType =
exprList[0].
opType;
opTypes[0] =
exprList[0].
opType;
switch (
opType) {
case
OpTypes.
NOT :
indexCond =
exprList;
opTypeEnd =
OpTypes.
MAX;
opTypesEnd[0] =
OpTypes.
MAX;
break;
case
OpTypes.
GREATER :
case
OpTypes.
GREATER_EQUAL :
case
OpTypes.
GREATER_EQUAL_PRE :
indexCond =
exprList;
if (
exprList[0].
getType() ==
OpTypes.
GREATER_EQUAL_PRE) {
indexEndCond[0] =
indexEndCondition =
exprList[0].
nodes[2];
}
opTypeEnd =
OpTypes.
MAX;
opTypesEnd[0] =
OpTypes.
MAX;
break;
case
OpTypes.
SMALLER :
case
OpTypes.
SMALLER_EQUAL : {
Expression e =
exprList[0].
getLeftNode();
e = new
ExpressionLogical(
OpTypes.
IS_NULL,
e);
e = new
ExpressionLogical(
OpTypes.
NOT,
e);
indexCond[0] =
e;
indexEndCond[0] =
indexEndCondition =
exprList[0];
opTypeEnd =
opType;
opTypesEnd[0] =
opType;
opType =
OpTypes.
NOT;
opTypes[0] =
OpTypes.
NOT;
break;
}
case
OpTypes.
IS_NULL :
case
OpTypes.
EQUAL : {
indexCond =
exprList;
for (int
i = 0;
i <
colCount;
i++) {
Expression e =
exprList[
i];
indexEndCond[
i] =
e;
indexEndCondition =
ExpressionLogical.
andExpressions(
indexEndCondition,
e);
opType =
e.
opType;
opTypes[
i] =
e.
opType;
opTypesEnd[
i] =
e.
opType;
}
opTypeEnd =
opType;
break;
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"RangeVariable");
}
indexedColumnCount =
colCount;
hasIndex = true;
}
private void
reverseIndexCondition() {
if (
indexedColumnCount == 0) {
reversed = true;
return;
}
if (
opType ==
OpTypes.
EQUAL ||
opType ==
OpTypes.
IS_NULL) {
//
} else {
indexEndCondition = null;
Expression[]
temp =
indexCond;
indexCond =
indexEndCond;
indexEndCond =
temp;
int[]
temptypes =
opTypes;
opTypes =
opTypesEnd;
opTypesEnd =
temptypes;
for (int
i = 0;
i <
indexedColumnCount;
i++) {
Expression e =
indexEndCond[
i];
indexEndCondition =
ExpressionLogical.
andExpressions(
indexEndCondition,
e);
}
if (
indexedColumnCount > 1
&&
opTypes[
indexedColumnCount - 1] ==
OpTypes.
MAX) {
indexedColumnCount--;
opTypes[
indexedColumnCount] = 0;
opTypesEnd[
indexedColumnCount] = 0;
}
opType =
opTypes[
indexedColumnCount - 1];
opTypeEnd =
opTypesEnd[
indexedColumnCount - 1];
}
reversed = true;
}
String describe(
Session session, int
blanks) {
StringBuffer sb = new
StringBuffer();
StringBuffer b = new
StringBuffer(
blanks);
for (int
i = 0;
i <
blanks;
i++) {
b.
append(' ');
}
sb.
append("index=").
append(
rangeIndex.
getName().
name).
append("\n");
if (
hasIndexCondition()) {
if (
indexedColumnCount > 0) {
sb.
append(
b).
append("start conditions=[");
for (int
j = 0;
j <
indexedColumnCount;
j++) {
if (
indexCond != null &&
indexCond[
j] != null) {
sb.
append(
indexCond[
j].
describe(
session,
blanks));
}
}
sb.
append("]\n");
}
if (this.
opTypeEnd !=
OpTypes.
EQUAL
&&
indexEndCondition != null) {
String temp =
indexEndCondition.
describe(
session,
blanks);
sb.
append(
b).
append("end condition=[").
append(
temp).
append(
"]\n");
}
}
if (
nonIndexCondition != null) {
String temp =
nonIndexCondition.
describe(
session,
blanks);
sb.
append(
b).
append("other condition=[").
append(
temp).
append(
"]\n");
}
return
sb.
toString();
}
private void
replaceColumnReferences(
RangeVariable range,
Expression[]
list) {
if (
indexCond != null) {
for (int
i = 0;
i <
indexCond.length;
i++) {
if (
indexCond[
i] != null) {
indexCond[
i] =
indexCond[
i].
replaceColumnReferences(
range,
list);
}
}
}
if (
indexEndCond != null) {
for (int
i = 0;
i <
indexEndCond.length;
i++) {
if (
indexEndCond[
i] != null) {
indexEndCond[
i] =
indexEndCond[
i].
replaceColumnReferences(
range,
list);
}
}
}
if (
indexEndCondition != null) {
indexEndCondition =
indexEndCondition.
replaceColumnReferences(
range,
list);
}
if (
excludeConditions != null) {
excludeConditions =
excludeConditions.
replaceColumnReferences(
range,
list);
}
if (
nonIndexCondition != null) {
nonIndexCondition =
nonIndexCondition.
replaceColumnReferences(
range,
list);
}
if (
terminalCondition != null) {
terminalCondition =
terminalCondition.
replaceColumnReferences(
range,
list);
}
}
private void
replaceExpressions(
OrderedHashSet expressions,
int
resultRangePosition) {
if (
indexCond != null) {
for (int
i = 0;
i <
indexCond.length;
i++) {
if (
indexCond[
i] != null) {
indexCond[
i] =
indexCond[
i].
replaceExpressions(
expressions,
resultRangePosition);
}
}
}
if (
indexEndCond != null) {
for (int
i = 0;
i <
indexEndCond.length;
i++) {
if (
indexEndCond[
i] != null) {
indexEndCond[
i] =
indexEndCond[
i].
replaceExpressions(
expressions,
resultRangePosition);
}
}
}
if (
indexEndCondition != null) {
indexEndCondition =
indexEndCondition.
replaceExpressions(
expressions,
resultRangePosition);
}
if (
excludeConditions != null) {
excludeConditions =
excludeConditions.
replaceExpressions(
expressions,
resultRangePosition);
}
if (
nonIndexCondition != null) {
nonIndexCondition =
nonIndexCondition.
replaceExpressions(
expressions,
resultRangePosition);
}
if (
terminalCondition != null) {
terminalCondition =
terminalCondition.
replaceExpressions(
expressions,
resultRangePosition);
}
}
}
}