This is an automated email from the ASF dual-hosted git repository. skadam pushed a commit to branch 4.x-HBase-1.5 in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.x-HBase-1.5 by this push: new 58f1fa8 PHOENIX-5390:Changing anonymous inner classes 58f1fa8 is described below commit 58f1fa833ceeda8b72449735ddb5e2c8547df764 Author: Neha <neha.gu...@salesforce.com> AuthorDate: Fri Jul 26 11:43:01 2019 -0700 PHOENIX-5390:Changing anonymous inner classes Adding nit changes Signed-off-by: s.kadam <ska...@apache.org> --- .../org/apache/phoenix/execute/CorrelatePlan.java | 194 +++++++++++---------- .../expression/function/InvertFunction.java | 88 +++++----- .../expression/function/PrefixFunction.java | 110 ++++++------ .../phoenix/iterate/OrderedResultIterator.java | 100 ++++++----- .../apache/phoenix/optimize/QueryOptimizer.java | 116 ++++++------ 5 files changed, 323 insertions(+), 285 deletions(-) diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java index b5491aa..68b1505 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/CorrelatePlan.java @@ -56,6 +56,7 @@ public class CorrelatePlan extends DelegateQueryPlan { private final KeyValueSchema rhsSchema; private final int rhsFieldPosition; + public CorrelatePlan(QueryPlan lhs, QueryPlan rhs, String variableId, JoinType joinType, boolean isSingleValueOnly, RuntimeContext runtimeContext, PTable joinedTable, @@ -104,99 +105,7 @@ public class CorrelatePlan extends DelegateQueryPlan { @Override public ResultIterator iterator(final ParallelScanGrouper scanGrouper, final Scan scan) throws SQLException { - return new ResultIterator() { - private final ValueBitSet destBitSet = ValueBitSet.newInstance(joinedSchema); - private final ValueBitSet lhsBitSet = ValueBitSet.newInstance(lhsSchema); - private final ValueBitSet rhsBitSet = - (joinType == JoinType.Semi || joinType == JoinType.Anti) ? - ValueBitSet.EMPTY_VALUE_BITSET - : ValueBitSet.newInstance(rhsSchema); - private final ResultIterator iter = delegate.iterator(scanGrouper, scan); - private ResultIterator rhsIter = null; - private Tuple current = null; - private boolean closed = false; - - @Override - public void close() throws SQLException { - if (!closed) { - closed = true; - iter.close(); - if (rhsIter != null) { - rhsIter.close(); - } - } - } - - @Override - public Tuple next() throws SQLException { - if (closed) - return null; - - Tuple rhsCurrent = null; - if (rhsIter != null) { - rhsCurrent = rhsIter.next(); - if (rhsCurrent == null) { - rhsIter.close(); - rhsIter = null; - } else if (isSingleValueOnly) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.SINGLE_ROW_SUBQUERY_RETURNS_MULTIPLE_ROWS).build().buildException(); - } - } - while (rhsIter == null) { - current = iter.next(); - if (current == null) { - close(); - return null; - } - runtimeContext.setCorrelateVariableValue(variableId, current); - rhsIter = rhs.iterator(); - rhsCurrent = rhsIter.next(); - if ((rhsCurrent == null && (joinType == JoinType.Inner || joinType == JoinType.Semi)) - || (rhsCurrent != null && joinType == JoinType.Anti)) { - rhsIter.close(); - rhsIter = null; - } - } - - Tuple joined; - try { - joined = rhsBitSet == ValueBitSet.EMPTY_VALUE_BITSET ? - current : TupleProjector.mergeProjectedValue( - convertLhs(current), destBitSet, - rhsCurrent, rhsBitSet, rhsFieldPosition, true); - } catch (IOException e) { - throw new SQLException(e); - } - - if ((joinType == JoinType.Semi || rhsCurrent == null) && rhsIter != null) { - rhsIter.close(); - rhsIter = null; - } - - return joined; - } - - @Override - public void explain(List<String> planSteps) { - } - - private ProjectedValueTuple convertLhs(Tuple lhs) throws IOException { - ProjectedValueTuple t; - if (lhs instanceof ProjectedValueTuple) { - t = (ProjectedValueTuple) lhs; - } else { - ImmutableBytesWritable ptr = getContext().getTempPtr(); - TupleProjector.decodeProjectedValue(lhs, ptr); - lhsBitSet.clear(); - lhsBitSet.or(ptr); - int bitSetLen = lhsBitSet.getEstimatedLength(); - t = new ProjectedValueTuple(lhs, lhs.getValue(0).getTimestamp(), - ptr.get(), ptr.getOffset(), ptr.getLength(), bitSetLen); - - } - return t; - } - }; + return new CorrelateResultIterator(scanGrouper, scan) ; } @Override @@ -227,4 +136,103 @@ public class CorrelatePlan extends DelegateQueryPlan { return cost.plus(lhsCost).plus(rhs.getCost()); } + private class CorrelateResultIterator implements ResultIterator { + private final ValueBitSet destBitSet = ValueBitSet.newInstance(joinedSchema); + private final ValueBitSet lhsBitSet = ValueBitSet.newInstance(lhsSchema); + private final ValueBitSet rhsBitSet = + (joinType == JoinType.Semi || joinType == JoinType.Anti) ? + ValueBitSet.EMPTY_VALUE_BITSET + : ValueBitSet.newInstance(rhsSchema); + private final ResultIterator iter; + private ResultIterator rhsIter = null; + private Tuple current = null; + private boolean closed = false; + + private CorrelateResultIterator(ParallelScanGrouper scanGrouper, Scan scan) + throws SQLException { + iter = delegate.iterator(scanGrouper, scan); + } + + @Override + public void close() throws SQLException { + if (!closed) { + closed = true; + iter.close(); + if (rhsIter != null) { + rhsIter.close(); + } + } + } + + @Override + public Tuple next() throws SQLException { + if (closed) + return null; + + Tuple rhsCurrent = null; + if (rhsIter != null) { + rhsCurrent = rhsIter.next(); + if (rhsCurrent == null) { + rhsIter.close(); + rhsIter = null; + } else if (isSingleValueOnly) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.SINGLE_ROW_SUBQUERY_RETURNS_MULTIPLE_ROWS) + .build().buildException(); + } + } + while (rhsIter == null) { + current = iter.next(); + if (current == null) { + close(); + return null; + } + runtimeContext.setCorrelateVariableValue(variableId, current); + rhsIter = rhs.iterator(); + rhsCurrent = rhsIter.next(); + if ((rhsCurrent == null && (joinType == JoinType.Inner || joinType == JoinType.Semi)) + || (rhsCurrent != null && joinType == JoinType.Anti)) { + rhsIter.close(); + rhsIter = null; + } + } + + Tuple joined; + try { + joined = rhsBitSet == ValueBitSet.EMPTY_VALUE_BITSET ? + current : TupleProjector.mergeProjectedValue( + convertLhs(current), destBitSet, + rhsCurrent, rhsBitSet, rhsFieldPosition, true); + } catch (IOException e) { + throw new SQLException(e); + } + + if ((joinType == JoinType.Semi || rhsCurrent == null) && rhsIter != null) { + rhsIter.close(); + rhsIter = null; + } + + return joined; + } + + @Override + public void explain(List<String> planSteps) { } + + private ProjectedValueTuple convertLhs(Tuple lhs) throws IOException { + ProjectedValueTuple tuple; + if (lhs instanceof ProjectedValueTuple) { + tuple = (ProjectedValueTuple) lhs; + } else { + ImmutableBytesWritable ptr = getContext().getTempPtr(); + TupleProjector.decodeProjectedValue(lhs, ptr); + lhsBitSet.clear(); + lhsBitSet.or(ptr); + int bitSetLen = lhsBitSet.getEstimatedLength(); + tuple = new ProjectedValueTuple(lhs, lhs.getValue(0).getTimestamp(), + ptr.get(), ptr.getOffset(), ptr.getLength(), bitSetLen); + + } + return tuple; + } + } + } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java index 8ef5914..038221d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java @@ -91,46 +91,7 @@ public class InvertFunction extends ScalarFunction { */ @Override public KeyPart newKeyPart(final KeyPart childPart) { - return new KeyPart() { - - @Override - public KeyRange getKeyRange(CompareOp op, Expression rhs) { - KeyRange range = childPart.getKeyRange(op, rhs); - byte[] lower = range.getLowerRange(); - if (!range.lowerUnbound()) { - lower = SortOrder.invert(lower, 0, lower.length); - } - byte[] upper; - if (range.isSingleKey()) { - upper = lower; - } else { - upper = range.getUpperRange(); - if (!range.upperUnbound()) { - upper = SortOrder.invert(upper, 0, upper.length); - } - } - range = KeyRange.getKeyRange(lower, range.isLowerInclusive(), upper, range.isUpperInclusive()); - if (getColumn().getSortOrder() == SortOrder.DESC) { - range = range.invert(); - } - return range; - } - - @Override - public List<Expression> getExtractNodes() { - return childPart.getExtractNodes(); - } - - @Override - public PColumn getColumn() { - return childPart.getColumn(); - } - - @Override - public PTable getTable() { - return childPart.getTable(); - } - }; + return new InvertKeyPart(childPart); } @Override @@ -141,4 +102,51 @@ public class InvertFunction extends ScalarFunction { private Expression getChildExpression() { return children.get(0); } + + private static class InvertKeyPart implements KeyPart { + + private final KeyPart childPart; + + public InvertKeyPart(KeyPart childPart) { + this.childPart = childPart; + } + + @Override + public KeyRange getKeyRange(CompareOp op, Expression rhs) { + KeyRange range = childPart.getKeyRange(op, rhs); + byte[] lower = range.getLowerRange(); + if (!range.lowerUnbound()) { + lower = SortOrder.invert(lower, 0, lower.length); + } + byte[] upper; + if (range.isSingleKey()) { + upper = lower; + } else { + upper = range.getUpperRange(); + if (!range.upperUnbound()) { + upper = SortOrder.invert(upper, 0, upper.length); + } + } + range = KeyRange.getKeyRange(lower, range.isLowerInclusive(), upper, range.isUpperInclusive()); + if (getColumn().getSortOrder() == SortOrder.DESC) { + range = range.invert(); + } + return range; + } + + @Override + public List<Expression> getExtractNodes() { + return childPart.getExtractNodes(); + } + + @Override + public PColumn getColumn() { + return childPart.getColumn(); + } + + @Override + public PTable getTable() { + return childPart.getTable(); + } + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java index ff3e74d..b09c14d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java @@ -21,7 +21,6 @@ package org.apache.phoenix.expression.function; import java.util.Arrays; import java.util.Collections; import java.util.List; - import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.phoenix.compile.KeyPart; import org.apache.phoenix.expression.Expression; @@ -34,8 +33,7 @@ import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.util.ByteUtil; abstract public class PrefixFunction extends ScalarFunction { - public PrefixFunction() { - } + public PrefixFunction() { } public PrefixFunction(List<Expression> children) { super(children); @@ -52,26 +50,36 @@ abstract public class PrefixFunction extends ScalarFunction { @Override public KeyPart newKeyPart(final KeyPart childPart) { - return new KeyPart() { - private final List<Expression> extractNodes = extractNode() ? Collections.<Expression>singletonList(PrefixFunction.this) : Collections.<Expression>emptyList(); + return new PrefixKeyPart(childPart); + } - @Override - public PColumn getColumn() { - return childPart.getColumn(); - } + private class PrefixKeyPart implements KeyPart { + private final List<Expression> extractNodes = extractNode() ? + Collections.<Expression>singletonList(PrefixFunction.this) + : Collections.<Expression>emptyList(); + private final KeyPart childPart; - @Override - public List<Expression> getExtractNodes() { - return extractNodes; - } + PrefixKeyPart(KeyPart childPart) { + this.childPart = childPart; + } + + @Override + public PColumn getColumn() { + return childPart.getColumn(); + } + + @Override + public List<Expression> getExtractNodes() { + return extractNodes; + } - @Override - public KeyRange getKeyRange(CompareOp op, Expression rhs) { - byte[] lowerRange = KeyRange.UNBOUND; - byte[] upperRange = KeyRange.UNBOUND; - boolean lowerInclusive = true; - PDataType type = getColumn().getDataType(); - switch (op) { + @Override + public KeyRange getKeyRange(CompareOp op, Expression rhs) { + byte[] lowerRange = KeyRange.UNBOUND; + byte[] upperRange = KeyRange.UNBOUND; + boolean lowerInclusive = true; + PDataType type = getColumn().getDataType(); + switch (op) { case EQUAL: lowerRange = evaluateExpression(rhs); upperRange = ByteUtil.nextKey(lowerRange); @@ -85,44 +93,42 @@ abstract public class PrefixFunction extends ScalarFunction { break; default: return childPart.getKeyRange(op, rhs); - } - PColumn column = getColumn(); - Integer length = column.getMaxLength(); - if (type.isFixedWidth()) { - if (length != null) { // Sanity check - shouldn't be necessary - // Don't pad based on current sort order, but instead use our - // minimum byte as otherwise we'll end up skipping rows in - // the case of descending, since rows with more padding appear - // *after* rows with no padding. - if (lowerRange != KeyRange.UNBOUND) { - lowerRange = type.pad(lowerRange, length, SortOrder.ASC); - } - if (upperRange != KeyRange.UNBOUND) { - upperRange = type.pad(upperRange, length, SortOrder.ASC); - } - } - } else if (column.getSortOrder() == SortOrder.DESC && getTable().rowKeyOrderOptimizable()) { - // Append a zero byte if descending since a \xFF byte will be appended to the lowerRange - // causing rows to be skipped that should be included. For example, with rows 'ab', 'a', - // a lowerRange of 'a\xFF' would skip 'ab', while 'a\x00\xFF' would not. + } + PColumn column = getColumn(); + Integer length = column.getMaxLength(); + if (type.isFixedWidth()) { + if (length != null) { // Sanity check - shouldn't be necessary + // Don't pad based on current sort order, but instead use our + // minimum byte as otherwise we'll end up skipping rows in + // the case of descending, since rows with more padding appear + // *after* rows with no padding. if (lowerRange != KeyRange.UNBOUND) { - lowerRange = Arrays.copyOf(lowerRange, lowerRange.length+1); - lowerRange[lowerRange.length-1] = QueryConstants.SEPARATOR_BYTE; + lowerRange = type.pad(lowerRange, length, SortOrder.ASC); + } + if (upperRange != KeyRange.UNBOUND) { + upperRange = type.pad(upperRange, length, SortOrder.ASC); } } - KeyRange range = KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, false); - if (column.getSortOrder() == SortOrder.DESC) { - range = range.invert(); + } else if (column.getSortOrder() == SortOrder.DESC && getTable().rowKeyOrderOptimizable()) { + // Append a zero byte if descending since a \xFF byte will be appended to the lowerRange + // causing rows to be skipped that should be included. For example, with rows 'ab', 'a', + // a lowerRange of 'a\xFF' would skip 'ab', while 'a\x00\xFF' would not. + if (lowerRange != KeyRange.UNBOUND) { + lowerRange = Arrays.copyOf(lowerRange, lowerRange.length+1); + lowerRange[lowerRange.length-1] = QueryConstants.SEPARATOR_BYTE; } - return range; } - - @Override - public PTable getTable() { - return childPart.getTable(); + KeyRange range = KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, false); + if (column.getSortOrder() == SortOrder.DESC) { + range = range.invert(); } - }; - } + return range; + } + @Override + public PTable getTable() { + return childPart.getTable(); + } + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java index 212410c..5430226 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/OrderedResultIterator.java @@ -257,52 +257,7 @@ public class OrderedResultIterator implements PeekingResultIterator { final SizeAwareQueue<ResultEntry> queueEntries = PhoenixQueues.newResultEntrySortedQueue(comparator, limit, spoolingEnabled, thresholdBytes); - resultIterator = new PeekingResultIterator() { - int count = 0; - - @Override - public Tuple next() throws SQLException { - ResultEntry entry = queueEntries.poll(); - while (entry != null && offset != null && count < offset) { - count++; - if (entry.getResult() == null) { return null; } - entry = queueEntries.poll(); - } - if (entry == null || (limit != null && count++ > limit)) { - resultIterator.close(); - resultIterator = PeekingResultIterator.EMPTY_ITERATOR; - return null; - } - return entry.getResult(); - } - - @Override - public Tuple peek() throws SQLException { - ResultEntry entry = queueEntries.peek(); - while (entry != null && offset != null && count < offset) { - entry = queueEntries.poll(); - count++; - if (entry == null) { return null; } - } - if (limit != null && count > limit) { return null; } - entry = queueEntries.peek(); - if (entry == null) { return null; } - return entry.getResult(); - } - - @Override - public void explain(List<String> planSteps) { - } - - @Override - public void close() throws SQLException { - try { - queueEntries.close(); - } catch (IOException e) { - throw new SQLException(e); - } - } - }; + resultIterator = new RecordPeekingResultIterator(queueEntries); for (Tuple result = delegate.next(); result != null; result = delegate.next()) { int pos = 0; ImmutableBytesWritable[] sortKeys = new ImmutableBytesWritable[numSortKeys]; @@ -356,4 +311,57 @@ public class OrderedResultIterator implements PeekingResultIterator { + ", resultIterator=" + resultIterator + ", byteSize=" + byteSize + "]"; } + + private class RecordPeekingResultIterator implements PeekingResultIterator { + int count = 0; + + private SizeAwareQueue<ResultEntry> queueEntries; + + RecordPeekingResultIterator(SizeAwareQueue<ResultEntry> queueEntries){ + this.queueEntries = queueEntries; + } + + @Override + public Tuple next() throws SQLException { + ResultEntry entry = queueEntries.poll(); + while (entry != null && offset != null && count < offset) { + count++; + if (entry.getResult() == null) { return null; } + entry = queueEntries.poll(); + } + if (entry == null || (limit != null && count++ > limit)) { + resultIterator.close(); + resultIterator = PeekingResultIterator.EMPTY_ITERATOR; + return null; + } + return entry.getResult(); + } + + @Override + public Tuple peek() throws SQLException { + ResultEntry entry = queueEntries.peek(); + while (entry != null && offset != null && count < offset) { + entry = queueEntries.poll(); + count++; + if (entry == null) { return null; } + } + if (limit != null && count > limit) { return null; } + entry = queueEntries.peek(); + if (entry == null) { return null; } + return entry.getResult(); + } + + @Override + public void explain(List<String> planSteps) { + } + + @Override + public void close() throws SQLException { + try { + queueEntries.close(); + } catch (IOException e) { + throw new SQLException(e); + } + } + } } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java index 45c7e7d..7cad7ec 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java @@ -590,71 +590,79 @@ public class QueryOptimizer { final PhoenixConnection connection, final ColumnResolver resolver, final SelectStatement select, final Map<TableRef, TableRef> replacement) throws SQLException { TableNode from = select.getFrom(); - TableNode newFrom = from.accept(new TableNodeVisitor<TableNode>() { - private TableRef resolveTable(String alias, TableName name) throws SQLException { - if (alias != null) - return resolver.resolveTable(null, alias); + TableNode newFrom = from.accept(new QueryOptimizerTableNode(resolver, replacement)); + if (from == newFrom) { + return select; + } - return resolver.resolveTable(name.getSchemaName(), name.getTableName()); - } + SelectStatement indexSelect = IndexStatementRewriter.translate(FACTORY.select(select, newFrom), resolver, replacement); + for (TableRef indexTableRef : replacement.values()) { + // replace expressions with corresponding matching columns for functional indexes + indexSelect = ParseNodeRewriter.rewrite(indexSelect, new IndexExpressionParseNodeRewriter(indexTableRef.getTable(), indexTableRef.getTableAlias(), connection, indexSelect.getUdfParseNodes())); + } - private TableName getReplacedTableName(TableRef tableRef) { - String schemaName = tableRef.getTable().getSchemaName().getString(); - return TableName.create(schemaName.length() == 0 ? null : schemaName, tableRef.getTable().getTableName().getString()); - } + return indexSelect; + } + private static class QueryOptimizerTableNode implements TableNodeVisitor<TableNode> { + private final ColumnResolver resolver; + private final Map<TableRef, TableRef> replacement; - @Override - public TableNode visit(BindTableNode boundTableNode) throws SQLException { - TableRef tableRef = resolveTable(boundTableNode.getAlias(), boundTableNode.getName()); - TableRef replaceRef = replacement.get(tableRef); - if (replaceRef == null) - return boundTableNode; - - String alias = boundTableNode.getAlias(); - return FACTORY.bindTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef)); - } + QueryOptimizerTableNode (ColumnResolver resolver, final Map<TableRef, TableRef> replacement){ + this.resolver = resolver; + this.replacement = replacement; + } - @Override - public TableNode visit(JoinTableNode joinNode) throws SQLException { - TableNode lhs = joinNode.getLHS(); - TableNode rhs = joinNode.getRHS(); - TableNode lhsReplace = lhs.accept(this); - TableNode rhsReplace = rhs.accept(this); - if (lhs == lhsReplace && rhs == rhsReplace) - return joinNode; - - return FACTORY.join(joinNode.getType(), lhsReplace, rhsReplace, joinNode.getOnNode(), joinNode.isSingleValueOnly()); - } + private TableRef resolveTable(String alias, TableName name) throws SQLException { + if (alias != null) + return resolver.resolveTable(null, alias); - @Override - public TableNode visit(NamedTableNode namedTableNode) - throws SQLException { - TableRef tableRef = resolveTable(namedTableNode.getAlias(), namedTableNode.getName()); - TableRef replaceRef = replacement.get(tableRef); - if (replaceRef == null) - return namedTableNode; + return resolver.resolveTable(name.getSchemaName(), name.getTableName()); + } - String alias = namedTableNode.getAlias(); - return FACTORY.namedTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef), namedTableNode.getDynamicColumns(), namedTableNode.getTableSamplingRate()); - } + private TableName getReplacedTableName(TableRef tableRef) { + String schemaName = tableRef.getTable().getSchemaName().getString(); + return TableName.create(schemaName.length() == 0 ? null : schemaName, tableRef.getTable().getTableName().getString()); + } - @Override - public TableNode visit(DerivedTableNode subselectNode) - throws SQLException { - return subselectNode; - } - }); + @Override + public TableNode visit(BindTableNode boundTableNode) throws SQLException { + TableRef tableRef = resolveTable(boundTableNode.getAlias(), boundTableNode.getName()); + TableRef replaceRef = replacement.get(tableRef); + if (replaceRef == null) + return boundTableNode; + + String alias = boundTableNode.getAlias(); + return FACTORY.bindTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef)); + } - if (from == newFrom) { - return select; + @Override + public TableNode visit(JoinTableNode joinNode) throws SQLException { + TableNode lhs = joinNode.getLHS(); + TableNode rhs = joinNode.getRHS(); + TableNode lhsReplace = lhs.accept(this); + TableNode rhsReplace = rhs.accept(this); + if (lhs == lhsReplace && rhs == rhsReplace) + return joinNode; + + return FACTORY.join(joinNode.getType(), lhsReplace, rhsReplace, joinNode.getOnNode(), joinNode.isSingleValueOnly()); } - SelectStatement indexSelect = IndexStatementRewriter.translate(FACTORY.select(select, newFrom), resolver, replacement); - for (TableRef indexTableRef : replacement.values()) { - // replace expressions with corresponding matching columns for functional indexes - indexSelect = ParseNodeRewriter.rewrite(indexSelect, new IndexExpressionParseNodeRewriter(indexTableRef.getTable(), indexTableRef.getTableAlias(), connection, indexSelect.getUdfParseNodes())); + @Override + public TableNode visit(NamedTableNode namedTableNode) + throws SQLException { + TableRef tableRef = resolveTable(namedTableNode.getAlias(), namedTableNode.getName()); + TableRef replaceRef = replacement.get(tableRef); + if (replaceRef == null) + return namedTableNode; + + String alias = namedTableNode.getAlias(); + return FACTORY.namedTable(alias == null ? null : '"' + alias + '"', getReplacedTableName(replaceRef), namedTableNode.getDynamicColumns(), namedTableNode.getTableSamplingRate()); } - return indexSelect; + @Override + public TableNode visit(DerivedTableNode subselectNode) + throws SQLException { + return subselectNode; + } } }