/* Copyright (c) 2001-2009, 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.HSQLInterface.HSQLParseException;
import org.hsqldb.HsqlNameManager.SimpleName;
import org.hsqldb.ParserDQL.CompileContext;
import org.hsqldb.index.Index;
import org.hsqldb.lib.HashMap;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HashSet;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.navigator.RangeIterator;
import org.hsqldb.navigator.RowIterator;
import org.hsqldb.persist.PersistentStore;
import org.hsqldb.store.ValuePool;
import org.hsqldb.types.Type;
/**
* Metadata for range variables, including conditions.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.9.0
*/
final class RangeVariable {
static final RangeVariable[] emptyArray = new RangeVariable[]{};
//
final Table rangeTable;
final SimpleName tableAlias;
private OrderedHashSet columnAliases;
private SimpleName[] columnAliasNames;
private OrderedHashSet columnNames;
OrderedHashSet namedJoinColumns;
HashMap namedJoinColumnExpressions;
Index rangeIndex;
private final Object[] emptyData;
final boolean[] columnsInGroupBy;
boolean hasKeyedColumnInGroupBy;
final boolean[] usedColumns;
boolean[] updatedColumns;
// index conditions
Expression indexCondition;
Expression indexEndCondition;
boolean isJoinIndex;
// non-index consitions
Expression nonIndexJoinCondition;
Expression nonIndexWhereCondition;
//
boolean isLeftJoin; // table joined with LEFT / FULL OUTER JOIN
boolean isRightJoin; // table joined with RIGHT / FULL OUTER JOIN
boolean isMultiFindFirst; // findFirst() uses multi-column index
private Expression[] findFirstExpressions; // expressions for column values
private int multiColumnCount;
int level;
//
int rangePosition;
// for variable and argument lists
HashMappedList variables;
// variable v.s. argument
boolean isVariable;
RangeVariable(HashMappedList variables, boolean isVariable) {
this.variables = variables;
this.isVariable = isVariable;
rangeTable = null;
tableAlias = null;
emptyData = null;
columnsInGroupBy = null;
usedColumns = null;
}
RangeVariable(Table table, SimpleName alias, OrderedHashSet columnList,
SimpleName[] columnNameList, CompileContext compileContext) {
rangeTable = table;
tableAlias = alias;
columnAliases = columnList;
columnAliasNames = columnNameList;
emptyData = rangeTable.getEmptyRowData();
columnsInGroupBy = rangeTable.getNewColumnCheckList();
usedColumns = rangeTable.getNewColumnCheckList();
rangeIndex = rangeTable.getPrimaryIndex();
compileContext.registerRangeVariable(this);
}
/*
RangeVariable(Table table, String alias, OrderedHashSet columnList,
Index index, CompileContext compileContext) {
rangeTable = table;
tableAlias = alias;
columnAliases = columnList;
emptyData = rangeTable.getEmptyRowData();
columnsInGroupBy = rangeTable.getNewColumnCheckList();
usedColumns = rangeTable.getNewColumnCheckList();
rangeIndex = index;
compileContext.registerRangeVariable(this);
}
*/
RangeVariable(RangeVariable range) {
rangeTable = range.rangeTable;
tableAlias = null;
emptyData = rangeTable.getEmptyRowData();
columnsInGroupBy = rangeTable.getNewColumnCheckList();
usedColumns = rangeTable.getNewColumnCheckList();
rangeIndex = rangeTable.getPrimaryIndex();
rangePosition = range.rangePosition;
level = range.level;
}
void setJoinType(boolean isLeft, boolean isRight) {
isLeftJoin = isLeft;
isRightJoin = isRight;
}
public void addNamedJoinColumns(OrderedHashSet columns) {
namedJoinColumns = columns;
}
public void addColumn(int columnIndex) {
usedColumns[columnIndex] = true;
}
void addNamedJoinColumnExpression(String name, Expression e) {
if (namedJoinColumnExpressions == null) {
namedJoinColumnExpressions = new HashMap();
}
namedJoinColumnExpressions.put(name, e);
}
ExpressionColumn getColumnExpression(String name) {
return namedJoinColumnExpressions == null ? null
: (ExpressionColumn) namedJoinColumnExpressions
.get(name);
}
Table getTable() {
return rangeTable;
}
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;
}
/**
* Retruns index for column
*
* @param columnName name of column
* @return int index or -1 if not found
*/
public int findColumn(String columnName) {
if (namedJoinColumnExpressions != null
&& namedJoinColumnExpressions.containsKey(columnName)) {
return -1;
}
if (variables != null) {
return variables.getIndex(columnName);
} else if (columnAliases != null) {
return columnAliases.getIndex(columnName);
} else {
return rangeTable.findColumn(columnName);
}
}
ColumnSchema getColumn(String columnName) {
int index = findColumn(columnName);
return index < 0 ? null
: rangeTable.getColumn(index);
}
ColumnSchema getColumn(int i) {
if (variables != null) {
return (ColumnSchema) variables.get(i);
} else {
return rangeTable.getColumn(i);
}
}
String getColumnAlias(int i) {
SimpleName name = getColumnAliasName(i);
return name.name;
}
public SimpleName getColumnAliasName(int i) {
if (columnAliases != null) {
return columnAliasNames[i];
} else {
return rangeTable.getColumn(i).getName();
}
}
boolean hasColumnAlias() {
return columnAliases != null;
}
boolean resolvesTableName(ExpressionColumn e) {
if (e.tableName == null) {
return true;
}
if (e.schema == null) {
if (tableAlias == null) {
if (e.tableName.equals(rangeTable.tableName.name)) {
return true;
}
} else if (e.tableName.equals(tableAlias.name)) {
return true;
}
} else {
if (e.tableName.equals(rangeTable.tableName.name)
&& e.schema.equals(rangeTable.tableName.schema.name)) {
return true;
}
}
return false;
}
public boolean resolvesTableName(String name) {
if (name == null) {
return true;
}
if (tableAlias == null) {
if (name.equals(rangeTable.tableName.name)) {
return true;
}
} else if (name.equals(tableAlias.name)) {
return true;
}
return false;
}
boolean resolvesSchemaName(String name) {
if (name == null) {
return true;
}
if (tableAlias != null) {
return false;
}
return name.equals(rangeTable.tableName.schema.name);
}
/**
* Add all columns to a list of expressions
*/
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
*/
int addTableColumns(HsqlArrayList expList, 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, column, i);
expList.add(position++, e);
}
return position;
}
void addTableColumns(Expression expression, HashSet exclude) {
HsqlArrayList list = new HsqlArrayList();
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, column, 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
*/
void setForCheckConstraint() {
rangeIndex = null;
}
/**
*
* @param e condition
* @param index Index object
* @param isJoin whether a join or not
*/
void addIndexCondition(Expression e, Index index, boolean isJoin) {
rangeIndex = index;
isJoinIndex = isJoin;
switch (e.getType()) {
case OpTypes.NOT :
indexCondition = e;
break;
case OpTypes.IS_NULL :
indexEndCondition = e;
break;
case OpTypes.EQUAL :
indexCondition = e;
indexEndCondition = indexCondition;
break;
case OpTypes.GREATER :
case OpTypes.GREATER_EQUAL :
indexCondition = e;
break;
case OpTypes.SMALLER :
case OpTypes.SMALLER_EQUAL :
indexEndCondition = e;
break;
default :
Error.runtimeError(ErrorCode.U_S0500, "Expression");
}
}
/**
*
* @param e a join condition
*/
void addJoinCondition(Expression e) {
nonIndexJoinCondition =
ExpressionLogical.andExpressions(nonIndexJoinCondition, e);
}
/**
*
* @param e a where condition
*/
void addWhereCondition(Expression e) {
nonIndexWhereCondition =
ExpressionLogical.andExpressions(nonIndexWhereCondition, e);
}
void addCondition(Expression e, boolean isJoin) {
if (isJoin) {
addJoinCondition(e);
} else {
addWhereCondition(e);
}
}
/**
* Only multiple EQUAL conditions are used
*
* @param exprList list of expressions
* @param index Index to use
* @param isJoin whether a join or not
*/
void addIndexCondition(Expression[] exprList, Index index, int colCount,
boolean isJoin) {
rangeIndex = index;
isJoinIndex = isJoin;
for (int i = 0; i < colCount; i++) {
Expression e = exprList[i];
indexEndCondition =
ExpressionLogical.andExpressions(indexEndCondition, e);
}
if (colCount == 1) {
indexCondition = exprList[0];
} else {
findFirstExpressions = exprList;
isMultiFindFirst = true;
multiColumnCount = colCount;
}
}
boolean hasIndexCondition() {
return indexCondition != null;
}
/**
* Retreives 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) {
StringBuffer sb;
String temp;
Index index;
Index primaryIndex;
int[] primaryKey;
boolean hidden;
boolean fullScan;
sb = new StringBuffer();
index = rangeIndex;
primaryIndex = rangeTable.getPrimaryIndex();
primaryKey = rangeTable.getPrimaryKey();
hidden = false;
fullScan = (indexCondition == null && indexEndCondition == null);
if (index == null) {
index = primaryIndex;
}
if (index == primaryIndex && primaryKey.length == 0) {
hidden = true;
fullScan = true;
}
sb.append(super.toString()).append('\n');
sb.append("table=[").append(rangeTable.getName().name).append("]\n");
if (tableAlias != null) {
sb.append("alias=[").append(tableAlias.name).append("]\n");
}
sb.append("access=[").append(fullScan ? "FULL SCAN"
: "INDEX PRED").append("]\n");
sb.append("index=[");
sb.append(index == null ? "NONE"
: index.getName() == null ? "UNNAMED"
: index.getName()
.name);
sb.append(hidden ? "[HIDDEN]]\n"
: "]\n");
temp = "INNER";
if (isLeftJoin) {
temp = "LEFT OUTER";
if (isRightJoin) {
temp = "FULL";
}
} else if (isRightJoin) {
temp = "RIGHT OUTER";
}
sb.append("joinType=[").append(temp).append("]\n");
temp = indexCondition == null ? "null"
: indexCondition.describe(session);
if (findFirstExpressions != null) {
StringBuffer sbt = new StringBuffer();
for (int i = 0; i < multiColumnCount; i++) {
sbt.append(findFirstExpressions[i].describe(session));
}
temp = sbt.toString();
}
sb.append("eStart=[").append(temp).append("]\n");
temp = indexEndCondition == null ? "null"
: indexEndCondition.describe(session);
sb.append("eEnd=[").append(temp).append("]\n");
temp = nonIndexJoinCondition == null ? "null"
: nonIndexJoinCondition.describe(
session);
sb.append("eAnd=[").append(temp).append("]");
return sb.toString();
}
public RangeIteratorMain getIterator(Session session) {
RangeIteratorMain it = new RangeIteratorMain(session, this);
session.sessionContext.setRangeIterator(it);
return it;
}
public RangeIteratorMain getFullIterator(Session session,
RangeIteratorMain mainIterator) {
RangeIteratorMain it = new FullRangeIterator(session, this,
mainIterator);
session.sessionContext.setRangeIterator(it);
return it;
}
public static RangeIteratorMain 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 JoinedRangeIterator(iterators);
}
public static class RangeIteratorBase implements RangeIterator {
Session session;
int rangePosition;
RowIterator it;
PersistentStore store;
Object[] currentData;
Row currentRow;
boolean isBeforeFirst;
RangeIteratorBase() {}
public RangeIteratorBase(Session session, PersistentStore store,
TableBase t, int position) {
this.session = session;
this.rangePosition = position;
this.store = store;
it = t.rowIterator(store);
isBeforeFirst = true;
}
public boolean isBeforeFirst() {
return isBeforeFirst;
}
public boolean next() {
if (isBeforeFirst) {
isBeforeFirst = false;
} else {
if (it == null) {
return false;
}
}
currentRow = it.getNextRow();
if (currentRow == null) {
return false;
} else {
currentData = currentRow.getData();
return true;
}
}
public Row getCurrentRow() {
return currentRow;
}
public Object[] getCurrent() {
return currentData;
}
public long getRowid() {
return currentRow == null ? 0
: currentRow.getId();
}
public Object getRowidObject() {
return currentRow == null ? null
: Long.valueOf(currentRow.getId());
}
public void remove() {}
public void reset() {
if (it != null) {
it.release();
}
it = null;
currentRow = null;
isBeforeFirst = true;
}
public int getRangePosition() {
return rangePosition;
}
}
public static class RangeIteratorMain extends RangeIteratorBase {
boolean hasOuterRow;
boolean isFullIterator;
RangeVariable rangeVar;
//
Table lookupTable;
PersistentStore lookupStore;
RangeIteratorMain() {
super();
}
public RangeIteratorMain(Session session, RangeVariable rangeVar) {
this.rangePosition = rangeVar.rangePosition;
this.store = session.sessionData.getRowStore(rangeVar.rangeTable);
this.session = session;
this.rangeVar = rangeVar;
isBeforeFirst = true;
if (rangeVar.isRightJoin) {
lookupTable = TableUtil.newLookupTable(session.database);
lookupStore = session.sessionData.getRowStore(lookupTable);
}
}
public boolean isBeforeFirst() {
return isBeforeFirst;
}
public boolean next() {
if (isBeforeFirst) {
isBeforeFirst = false;
initialiseIterator();
} else {
if (it == null) {
return false;
}
}
return findNext();
}
public void remove() {}
public void reset() {
if (it != null) {
it.release();
}
it = null;
currentData = rangeVar.emptyData;
currentRow = null;
hasOuterRow = false;
isBeforeFirst = true;
}
public int getRangePosition() {
return rangeVar.rangePosition;
}
/**
*/
protected void initialiseIterator() {
hasOuterRow = rangeVar.isLeftJoin;
if (rangeVar.isMultiFindFirst) {
getFirstRowMulti();
if (!rangeVar.isJoinIndex) {
hasOuterRow = false;
}
} else if (rangeVar.indexCondition == null) {
if (rangeVar.indexEndCondition == null
|| rangeVar.indexEndCondition.getType()
== OpTypes.IS_NULL) {
it = rangeVar.rangeIndex.firstRow(session, store);
} else {
it = rangeVar.rangeIndex.findFirstRowNotNull(session,
store);
}
} else {
// only NOT NULL
if (rangeVar.indexCondition.getType() == OpTypes.NOT) {
it = rangeVar.rangeIndex.findFirstRowNotNull(session,
store);
} else {
getFirstRow();
}
if (!rangeVar.isJoinIndex) {
hasOuterRow = false;
}
}
}
/**
*/
private void getFirstRow() {
Object value =
rangeVar.indexCondition.getRightNode().getValue(session);
Type valueType =
rangeVar.indexCondition.getRightNode().getDataType();
Type targetType =
rangeVar.indexCondition.getLeftNode().getDataType();
int exprType = rangeVar.indexCondition.getType();
int range = 0;
if (targetType != valueType) {
range = targetType.compareToTypeRange(value);
}
if (range == 0) {
value = targetType.convertToType(session, value, valueType);
it = rangeVar.rangeIndex.findFirstRow(session, store, value,
exprType);
} else if (range < 0) {
switch (exprType) {
case OpTypes.GREATER_EQUAL :
case OpTypes.GREATER :
it = rangeVar.rangeIndex.findFirstRowNotNull(session,
store);
break;
default :
it = rangeVar.rangeIndex.emptyIterator();
}
} else {
switch (exprType) {
case OpTypes.SMALLER_EQUAL :
case OpTypes.SMALLER :
it = rangeVar.rangeIndex.findFirstRowNotNull(session,
store);
break;
default :
it = rangeVar.rangeIndex.emptyIterator();
}
}
return;
}
/**
* Uses multiple EQUAL expressions
*/
private void getFirstRowMulti() {
boolean convertible = true;
Object[] currentJoinData =
new Object[rangeVar.rangeIndex.getVisibleColumns()];
for (int i = 0; i < rangeVar.multiColumnCount; i++) {
Type valueType =
rangeVar.findFirstExpressions[i].getRightNode()
.getDataType();
Type targetType =
rangeVar.findFirstExpressions[i].getLeftNode()
.getDataType();
Object value =
rangeVar.findFirstExpressions[i].getRightNode().getValue(
session);
if (targetType.compareToTypeRange(value) != 0) {
convertible = false;
break;
}
currentJoinData[i] = targetType.convertToType(session, value,
valueType);
}
it = convertible
? rangeVar.rangeIndex.findFirstRow(session, store,
currentJoinData, rangeVar.multiColumnCount)
: rangeVar.rangeIndex.emptyIterator();
}
/**
* Advances to the next available value. <p>
*
* @return true if a next value is available upon exit
*/
protected boolean findNext() {
boolean result = false;
while (true) {
currentRow = it.getNextRow();
if (currentRow == null) {
break;
}
currentData = currentRow.getData();
if (rangeVar.indexEndCondition != null
&& !rangeVar.indexEndCondition.testCondition(
session)) {
if (!rangeVar.isJoinIndex) {
hasOuterRow = false;
}
break;
}
if (rangeVar.nonIndexJoinCondition != null
&& !rangeVar.nonIndexJoinCondition.testCondition(
session)) {
continue;
}
if (rangeVar.nonIndexWhereCondition != null
&& !rangeVar.nonIndexWhereCondition.testCondition(
session)) {
hasOuterRow = false;
continue;
}
addFoundRow();
result = true;
break;
}
if (result) {
hasOuterRow = false;
return true;
}
it.release();
currentRow = null;
currentData = rangeVar.emptyData;
if (hasOuterRow) {
result = (rangeVar.nonIndexWhereCondition == null
|| rangeVar.nonIndexWhereCondition.testCondition(
session));
}
hasOuterRow = false;
return result;
}
protected void addFoundRow() {
if (rangeVar.isRightJoin) {
try {
lookupTable.insertData(
lookupStore,
new Object[]{ ValuePool.getInt(currentRow.getPos()) });
} catch (HsqlException e) {}
}
}
}
public static class FullRangeIterator extends RangeIteratorMain {
public FullRangeIterator(Session session, RangeVariable rangeVar,
RangeIteratorMain rangeIterator) {
this.rangePosition = rangeVar.rangePosition;
this.store = session.sessionData.getRowStore(rangeVar.rangeTable);
this.session = session;
this.rangeVar = rangeVar;
isBeforeFirst = true;
lookupTable = rangeIterator.lookupTable;
lookupStore = rangeIterator.lookupStore;
it = rangeVar.rangeIndex.firstRow(session, store);
}
protected void initialiseIterator() {}
protected boolean findNext() {
boolean result;
while (true) {
currentRow = it.getNextRow();
if (currentRow == null) {
result = false;
break;
}
RowIterator lookupIterator =
lookupTable.indexList[0].findFirstRow(session,
lookupStore, ValuePool.getInt(currentRow.getPos()),
OpTypes.EQUAL);
result = !lookupIterator.hasNext();
lookupIterator.release();
if (result) {
currentData = currentRow.getData();
if (rangeVar.nonIndexWhereCondition != null
&& !rangeVar.nonIndexWhereCondition.testCondition(
session)) {
continue;
}
isBeforeFirst = false;
return true;
}
}
it.release();
currentRow = null;
currentData = rangeVar.emptyData;
return result;
}
}
public static class JoinedRangeIterator extends RangeIteratorMain {
RangeIteratorMain[] rangeIterators;
int currentIndex = 0;
public JoinedRangeIterator(RangeIteratorMain[] rangeIterators) {
this.rangeIterators = rangeIterators;
}
public boolean isBeforeFirst() {
return isBeforeFirst;
}
public boolean next() {
while (currentIndex >= 0) {
RangeIteratorMain it = rangeIterators[currentIndex];
if (it.next()) {
if (currentIndex < rangeIterators.length - 1) {
currentIndex++;
continue;
}
currentRow = rangeIterators[currentIndex].currentRow;
currentData = currentRow.getData();
return true;
} else {
it.reset();
currentIndex--;
continue;
}
}
currentData =
rangeIterators[rangeIterators.length - 1].rangeVar.emptyData;
currentRow = null;
for (int i = 0; i < rangeIterators.length; i++) {
rangeIterators[i].reset();
}
return false;
}
public void reset() {}
}
/*************** VOLTDB *********************/
/**
* VoltDB added method to get a non-catalog-dependent
* representation of this HSQLDB object.
* @param session The current Session object may be needed to resolve
* some names.
* @param indent A string of whitespace to be prepended to every line
* in the resulting XML.
* @return XML, correctly indented, representing this object.
* @throws HSQLParseException
*/
String voltGetXML(Session session, String orig_indent)
throws HSQLParseException
{
StringBuffer sb;
Index index;
Index primaryIndex;
int[] primaryKey;
boolean isSeqScan;
sb = new StringBuffer();
index = rangeIndex;
primaryIndex = rangeTable.getPrimaryIndex();
primaryKey = rangeTable.getPrimaryKey();
isSeqScan = indexCondition == null;
String indent = orig_indent + HSQLInterface.XML_INDENT;
// get the index for this scan (/filter)
// note: ignored if scan if full table scan
if (index == null)
index = primaryIndex;
// check if this is a sequential scan
if (index == primaryIndex && primaryKey.length == 0)
isSeqScan = true;
// output open tag + metadata
sb.append(orig_indent + "<tablescan type=\"");
if (isSeqScan) sb.append("sequential\" ");
else sb.append("index\" ");
sb.append("table=\"").append(rangeTable.getName().name).append("\"");
if ((index != null) && (isSeqScan == false)) {
String indexName = (index.getName() == null ? "UNNAMED" : index.getName().name);
sb.append(" index=\"").append(indexName).append("\"");
}
if (tableAlias != null && !rangeTable.getName().name.equals(tableAlias))
sb.append(" alias=\"").append(tableAlias).append("\"");
// note if this is an outer join
if (isLeftJoin || isRightJoin) {
sb.append(" isouterjoin=\"true\"");
}
sb.append(">\n");
// start with the indexCondition
Expression cond = indexCondition;
// then go to the indexEndCondition
if (indexEndCondition != null) {
if (cond != null) {
cond = new ExpressionLogical(OpTypes.AND, cond, indexEndCondition);
} else {
cond = indexEndCondition;
}
}
// then go to the nonIndexJoinCondition
if (nonIndexJoinCondition != null) {
if (cond != null) {
cond = new ExpressionLogical(OpTypes.AND, cond, nonIndexJoinCondition);
} else {
cond = nonIndexJoinCondition;
}
}
// then go to the nonIndexWhereCondition
if (nonIndexWhereCondition != null) {
if (cond != null) {
cond = new ExpressionLogical(OpTypes.AND, cond, nonIndexWhereCondition);
} else {
cond = nonIndexWhereCondition;
}
}
//
// END EXPRESSION
//
if (indexEndCondition != null) {
sb.append(indent + "<postexp>\n");
sb.append(cond.voltGetXML(session, indent + HSQLInterface.XML_INDENT)).append("\n");
sb.append(indent + "</postexp>\n");
}
sb.append(orig_indent + "</tablescan>");
return sb.toString();
}
}