use of org.apache.phoenix.compile.KeyPart in project phoenix by apache.
the class RoundDecimalExpression method newKeyPart.
@Override
public KeyPart newKeyPart(final KeyPart childPart) {
return new KeyPart() {
private final List<Expression> extractNodes = Collections.<Expression>singletonList(RoundDecimalExpression.this);
@Override
public PColumn getColumn() {
return childPart.getColumn();
}
@Override
public List<Expression> getExtractNodes() {
return extractNodes;
}
@Override
public KeyRange getKeyRange(CompareFilter.CompareOp op, Expression rhs) {
final BigDecimal rhsDecimal = (BigDecimal) PDecimal.INSTANCE.toObject(evaluateExpression(rhs));
// than needed for a match, it's impossible for there to be any matches
if (op == CompareFilter.CompareOp.EQUAL && !hasEnoughPrecisionToProduce(rhsDecimal)) {
return KeyRange.EMPTY_RANGE;
}
// if the decimal needs to be rounded, round it such that the given
// operator will still be valid
BigDecimal roundedDecimal = roundAndPreserveOperator(rhsDecimal, op);
// the range of big decimals that could be rounded to produce the rounded result
// alternatively, the "rounding bucket" that this decimal falls into
final KeyRange equalityRange = getInputRangeProducing(roundedDecimal);
boolean lowerInclusive = equalityRange.isLowerInclusive();
boolean upperInclusive = equalityRange.isUpperInclusive();
byte[] lowerRange = KeyRange.UNBOUND;
byte[] upperRange = KeyRange.UNBOUND;
switch(op) {
case EQUAL:
return equalityRange;
case GREATER:
// from the equality range and up, NOT including the equality range
lowerRange = equalityRange.getUpperRange();
lowerInclusive = !equalityRange.isUpperInclusive();
break;
case GREATER_OR_EQUAL:
// from the equality range and up, including the equality range
lowerRange = equalityRange.getLowerRange();
break;
case LESS:
// from the equality range and down, NOT including the equality range
upperRange = equalityRange.getLowerRange();
upperInclusive = !equalityRange.isLowerInclusive();
break;
case LESS_OR_EQUAL:
// from the equality range and down, including the equality range
upperRange = equalityRange.getUpperRange();
break;
default:
throw new AssertionError("Invalid CompareOp: " + op);
}
return KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, upperInclusive);
}
/**
* Produces a the given decimal rounded to this rounding expression's scale. If the
* decimal requires more scale precision to produce than this expression has, as in
* ROUND(?, 2) > 2.0098974, it ensures that the decimal is rounded such that the
* given operator will still produce correct results.
* @param decimal the decimal to round with this expression's scale
* @param op the operator to preserve comparison with in the event of lost precision
* @return the rounded decimal
*/
private BigDecimal roundAndPreserveOperator(BigDecimal decimal, CompareFilter.CompareOp op) {
final BigDecimal rounded = roundToScale(decimal);
// if we lost information, make sure that the rounding didn't break the operator
if (!hasEnoughPrecisionToProduce(decimal)) {
switch(op) {
case GREATER_OR_EQUAL:
// 'ROUND(dec, 2) >= 2.01' but should be 'ROUND(dec, 2) >= 2.02'
if (decimal.compareTo(rounded) > 0) {
return stepNextInScale(rounded);
}
break;
case GREATER:
// 'ROUND(dec, 2) > 2.02' but should be 'ROUND(dec, 2) > 2.01'
if (decimal.compareTo(rounded) < 0) {
return stepPrevInScale(rounded);
}
break;
case LESS_OR_EQUAL:
// 'ROUND(dec, 2) < 2.02' but should be 'ROUND(dec, 2) < 2.01'
if (decimal.compareTo(rounded) < 0) {
return stepPrevInScale(rounded);
}
break;
case LESS:
// 'ROUND(dec, 2) <= 2.01' but should be 'ROUND(dec, 2) <= 2.02'
if (decimal.compareTo(rounded) > 0) {
return stepNextInScale(rounded);
}
break;
}
}
// otherwise, rounding has not affected the operator, so return normally
return rounded;
}
@Override
public PTable getTable() {
return childPart.getTable();
}
};
}
use of org.apache.phoenix.compile.KeyPart in project phoenix by apache.
the class PrefixFunction method newKeyPart.
@Override
public KeyPart newKeyPart(final KeyPart childPart) {
return new KeyPart() {
private final List<Expression> extractNodes = extractNode() ? Collections.<Expression>singletonList(PrefixFunction.this) : Collections.<Expression>emptyList();
@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) {
case EQUAL:
lowerRange = evaluateExpression(rhs);
upperRange = ByteUtil.nextKey(lowerRange);
break;
case GREATER:
lowerRange = ByteUtil.nextKey(evaluateExpression(rhs));
break;
case LESS_OR_EQUAL:
upperRange = ByteUtil.nextKey(evaluateExpression(rhs));
lowerInclusive = false;
break;
default:
return childPart.getKeyRange(op, rhs);
}
PColumn column = getColumn();
Integer length = column.getMaxLength();
if (type.isFixedWidth()) {
if (length != null) {
// *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()) {
// 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 KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, false);
}
@Override
public PTable getTable() {
return childPart.getTable();
}
};
}
use of org.apache.phoenix.compile.KeyPart in project phoenix by apache.
the class RoundDateExpression method newKeyPart.
/**
* Form the key range from the key to the key right before or at the
* next rounded value.
*/
@Override
public KeyPart newKeyPart(final KeyPart childPart) {
return new KeyPart() {
private final List<Expression> extractNodes = Collections.<Expression>singletonList(RoundDateExpression.this);
@Override
public PColumn getColumn() {
return childPart.getColumn();
}
@Override
public List<Expression> getExtractNodes() {
return extractNodes;
}
@Override
public KeyRange getKeyRange(CompareOp op, Expression rhs) {
PDataType type = getColumn().getDataType();
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
rhs.evaluate(null, ptr);
byte[] key = ByteUtil.copyKeyBytesIfNecessary(ptr);
// No need to take into account SortOrder, because ROUND
// always forces the value to be in ascending order
PDataCodec codec = getKeyRangeCodec(type);
int offset = ByteUtil.isInclusive(op) ? 1 : 0;
long value = codec.decodeLong(key, 0, SortOrder.getDefault());
byte[] nextKey = new byte[type.getByteSize()];
switch(op) {
case EQUAL:
// boundary.
if (value % divBy != 0) {
return KeyRange.EMPTY_RANGE;
}
codec.encodeLong(value + divBy, nextKey, 0);
return type.getKeyRange(key, true, nextKey, false);
case GREATER:
case GREATER_OR_EQUAL:
codec.encodeLong((value + divBy - offset) / divBy * divBy, nextKey, 0);
return type.getKeyRange(nextKey, true, KeyRange.UNBOUND, false);
case LESS:
case LESS_OR_EQUAL:
codec.encodeLong((value + divBy - (1 - offset)) / divBy * divBy, nextKey, 0);
return type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false);
default:
return childPart.getKeyRange(op, rhs);
}
}
@Override
public PTable getTable() {
return childPart.getTable();
}
};
}
use of org.apache.phoenix.compile.KeyPart in project phoenix by apache.
the class RTrimFunction method newKeyPart.
@Override
public KeyPart newKeyPart(final KeyPart childPart) {
return new KeyPart() {
@Override
public KeyRange getKeyRange(CompareOp op, Expression rhs) {
byte[] lowerRange = KeyRange.UNBOUND;
byte[] upperRange = KeyRange.UNBOUND;
boolean lowerInclusive = true;
boolean upperInclusive = false;
PDataType type = getColumn().getDataType();
SortOrder sortOrder = getColumn().getSortOrder();
switch(op) {
case LESS_OR_EQUAL:
lowerInclusive = false;
case EQUAL:
upperRange = evaluateExpression(rhs);
if (op == CompareOp.EQUAL) {
lowerRange = upperRange;
}
if (sortOrder == SortOrder.ASC || !getTable().rowKeyOrderOptimizable()) {
upperRange = Arrays.copyOf(upperRange, upperRange.length + 1);
upperRange[upperRange.length - 1] = StringUtil.SPACE_UTF8;
ByteUtil.nextKey(upperRange, upperRange.length);
} else {
upperInclusive = true;
if (op == CompareOp.LESS_OR_EQUAL) {
// will be the RHS value.
break;
}
/*
* Somewhat tricky to get the range correct for the DESC equality case.
* The lower range is the RHS value followed by any number of inverted spaces.
* We need to add a zero byte as the lower range will have an \xFF byte
* appended to it and otherwise we'd skip past any rows where there is more
* than one space following the RHS.
* The upper range should span up to and including the RHS value. We need
* to add our own \xFF as otherwise this will look like a degenerate query
* since the lower would be bigger than the upper range.
*/
lowerRange = Arrays.copyOf(lowerRange, lowerRange.length + 2);
lowerRange[lowerRange.length - 2] = StringUtil.INVERTED_SPACE_UTF8;
lowerRange[lowerRange.length - 1] = QueryConstants.SEPARATOR_BYTE;
upperRange = Arrays.copyOf(upperRange, upperRange.length + 1);
upperRange[upperRange.length - 1] = QueryConstants.DESC_SEPARATOR_BYTE;
}
break;
default:
// TOOD: Is this ok for DESC?
return childPart.getKeyRange(op, rhs);
}
Integer length = getColumn().getMaxLength();
if (type.isFixedWidth() && length != null) {
// *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);
}
}
return KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, upperInclusive);
}
@Override
public List<Expression> getExtractNodes() {
// non blank characters such as 'foo bar' where the RHS constant is 'foo'.
return Collections.<Expression>emptyList();
}
@Override
public PColumn getColumn() {
return childPart.getColumn();
}
@Override
public PTable getTable() {
return childPart.getTable();
}
};
}
use of org.apache.phoenix.compile.KeyPart in project phoenix by apache.
the class RoundFloorCeilExpressionsTest method testCeilDecimalExpressionKeyRangeCoverage.
@Test
public void testCeilDecimalExpressionKeyRangeCoverage() throws Exception {
for (int scale : SCALES) {
ScalarFunction ceilDecimalExpression = (ScalarFunction) CeilDecimalExpression.create(DUMMY_DECIMAL, scale);
KeyPart keyPart = ceilDecimalExpression.newKeyPart(null);
verifyKeyPart(RoundingType.CEIL, scale, keyPart);
}
}
Aggregations