use of org.apache.phoenix.expression.CoerceExpression in project phoenix by apache.
the class WhereOptimizer method getKeyExpressionCombination.
/**
* Get an optimal combination of key expressions for hash join key range optimization.
* @return returns true if the entire combined expression is covered by key range optimization
* @param result the optimal combination of key expressions
* @param context the temporary context to get scan ranges set by pushKeyExpressionsToScan()
* @param statement the statement being compiled
* @param expressions the join key expressions
* @return the optimal list of key expressions
*/
public static boolean getKeyExpressionCombination(List<Expression> result, StatementContext context, FilterableStatement statement, List<Expression> expressions) throws SQLException {
List<Integer> candidateIndexes = Lists.newArrayList();
final List<Integer> pkPositions = Lists.newArrayList();
PTable table = context.getCurrentTable().getTable();
for (int i = 0; i < expressions.size(); i++) {
Expression expression = expressions.get(i);
// TODO this is a temporary fix for PHOENIX-3029.
if (expression instanceof CoerceExpression && expression.getSortOrder() != expression.getChildren().get(0).getSortOrder()) {
continue;
}
KeyExpressionVisitor visitor = new KeyExpressionVisitor(context, table);
KeyExpressionVisitor.KeySlots keySlots = expression.accept(visitor);
int minPkPos = Integer.MAX_VALUE;
if (keySlots != null) {
Iterator<KeyExpressionVisitor.KeySlot> iterator = keySlots.iterator();
while (iterator.hasNext()) {
KeyExpressionVisitor.KeySlot slot = iterator.next();
if (slot.getPKPosition() < minPkPos) {
minPkPos = slot.getPKPosition();
}
}
if (minPkPos != Integer.MAX_VALUE) {
candidateIndexes.add(i);
pkPositions.add(minPkPos);
}
}
}
if (candidateIndexes.isEmpty())
return false;
Collections.sort(candidateIndexes, new Comparator<Integer>() {
@Override
public int compare(Integer left, Integer right) {
return pkPositions.get(left) - pkPositions.get(right);
}
});
List<Expression> candidates = Lists.newArrayList();
List<List<Expression>> sampleValues = Lists.newArrayList();
for (Integer index : candidateIndexes) {
candidates.add(expressions.get(index));
}
for (int i = 0; i < 2; i++) {
List<Expression> group = Lists.newArrayList();
for (Expression expression : candidates) {
PDataType type = expression.getDataType();
group.add(LiteralExpression.newConstant(type.getSampleValue(), type));
}
sampleValues.add(group);
}
int count = 0;
int offset = table.getBucketNum() == null ? 0 : SaltingUtil.NUM_SALTING_BYTES;
int maxPkSpan = 0;
Expression remaining = null;
while (count < candidates.size()) {
Expression lhs = count == 0 ? candidates.get(0) : new RowValueConstructorExpression(candidates.subList(0, count + 1), false);
Expression firstRhs = count == 0 ? sampleValues.get(0).get(0) : new RowValueConstructorExpression(sampleValues.get(0).subList(0, count + 1), true);
Expression secondRhs = count == 0 ? sampleValues.get(1).get(0) : new RowValueConstructorExpression(sampleValues.get(1).subList(0, count + 1), true);
Expression testExpression = InListExpression.create(Lists.newArrayList(lhs, firstRhs, secondRhs), false, context.getTempPtr(), context.getCurrentTable().getTable().rowKeyOrderOptimizable());
remaining = pushKeyExpressionsToScan(context, statement, testExpression);
if (context.getScanRanges().isPointLookup()) {
count++;
// found the best match
break;
}
int pkSpan = context.getScanRanges().getBoundPkColumnCount() - offset;
if (pkSpan <= maxPkSpan) {
break;
}
maxPkSpan = pkSpan;
count++;
}
result.addAll(candidates.subList(0, count));
return count == candidates.size() && (context.getScanRanges().isPointLookup() || context.getScanRanges().useSkipScanFilter()) && (remaining == null || remaining.equals(LiteralExpression.newConstant(true, Determinism.ALWAYS)));
}
Aggregations