Search in sources :

Example 1 with KeyPart

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) &gt; 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();
        }
    };
}
Also used : Expression(org.apache.phoenix.expression.Expression) LiteralExpression(org.apache.phoenix.expression.LiteralExpression) KeyRange(org.apache.phoenix.query.KeyRange) KeyPart(org.apache.phoenix.compile.KeyPart) List(java.util.List) BigDecimal(java.math.BigDecimal)

Example 2 with KeyPart

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();
        }
    };
}
Also used : PColumn(org.apache.phoenix.schema.PColumn) PDataType(org.apache.phoenix.schema.types.PDataType) Expression(org.apache.phoenix.expression.Expression) KeyPart(org.apache.phoenix.compile.KeyPart) List(java.util.List) CompareOp(org.apache.hadoop.hbase.filter.CompareFilter.CompareOp)

Example 3 with KeyPart

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();
        }
    };
}
Also used : ImmutableBytesWritable(org.apache.hadoop.hbase.io.ImmutableBytesWritable) PDataCodec(org.apache.phoenix.schema.types.PDataType.PDataCodec) PDataType(org.apache.phoenix.schema.types.PDataType) Expression(org.apache.phoenix.expression.Expression) LiteralExpression(org.apache.phoenix.expression.LiteralExpression) KeyPart(org.apache.phoenix.compile.KeyPart) List(java.util.List) CompareOp(org.apache.hadoop.hbase.filter.CompareFilter.CompareOp)

Example 4 with KeyPart

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();
        }
    };
}
Also used : PDataType(org.apache.phoenix.schema.types.PDataType) Expression(org.apache.phoenix.expression.Expression) KeyPart(org.apache.phoenix.compile.KeyPart) SortOrder(org.apache.phoenix.schema.SortOrder) CompareOp(org.apache.hadoop.hbase.filter.CompareFilter.CompareOp)

Example 5 with KeyPart

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);
    }
}
Also used : ScalarFunction(org.apache.phoenix.expression.function.ScalarFunction) KeyPart(org.apache.phoenix.compile.KeyPart) Test(org.junit.Test)

Aggregations

KeyPart (org.apache.phoenix.compile.KeyPart)10 ScalarFunction (org.apache.phoenix.expression.function.ScalarFunction)6 Test (org.junit.Test)6 BigDecimal (java.math.BigDecimal)4 Expression (org.apache.phoenix.expression.Expression)4 KeyRange (org.apache.phoenix.query.KeyRange)4 List (java.util.List)3 CompareOp (org.apache.hadoop.hbase.filter.CompareFilter.CompareOp)3 PDataType (org.apache.phoenix.schema.types.PDataType)3 LiteralExpression (org.apache.phoenix.expression.LiteralExpression)2 ImmutableBytesWritable (org.apache.hadoop.hbase.io.ImmutableBytesWritable)1 PColumn (org.apache.phoenix.schema.PColumn)1 SortOrder (org.apache.phoenix.schema.SortOrder)1 PDataCodec (org.apache.phoenix.schema.types.PDataType.PDataCodec)1