/** * {@inheritDoc } */ @Override protected KeyRange getInputRangeProducing(BigDecimal result) { if(!hasEnoughPrecisionToProduce(result)) { throw new IllegalArgumentException("Cannot produce input range for decimal " + result + ", not enough precision with scale " + getRoundingScale()); } byte[] lowerRange = PDecimal.INSTANCE.toBytes(result); byte[] upperRange = PDecimal.INSTANCE.toBytes(stepNextInScale(result)); return KeyRange.getKeyRange(lowerRange, upperRange); }
/** * {@inheritDoc } */ @Override protected KeyRange getInputRangeProducing(BigDecimal result) { if(!hasEnoughPrecisionToProduce(result)) { throw new IllegalArgumentException("Cannot produce input range for decimal " + result + ", not enough precision with scale " + getRoundingScale()); } byte[] lowerRange = PDecimal.INSTANCE.toBytes(stepPrevInScale(result)); byte[] upperRange = PDecimal.INSTANCE.toBytes(result); return KeyRange.getKeyRange(lowerRange, false, upperRange, true); }
@Override public void abs(byte[] bytes, int offset, int length, SortOrder sortOrder, ImmutableBytesWritable outPtr) { if (sortOrder == SortOrder.DESC) { bytes = SortOrder.invert(bytes, offset, new byte[length], 0, length); offset = 0; } BigDecimal bigDecimal = toBigDecimal(bytes, offset, length); outPtr.set(toBytes(bigDecimal.abs())); } }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (cachedResult == null) { double ssd = sumSquaredDeviation(); double result = Math.sqrt(ssd / getDataPointsCount()); cachedResult = new BigDecimal(result); } if (buffer == null) { initBuffer(); } buffer = PDecimal.INSTANCE.toBytes(cachedResult); ptr.set(buffer); return true; }
/** * Finds the Decimal KeyRange that will produce the given result when fed into this * rounding expression. For example, a ROUND expression with scale 2 will produce the * result "2.05" with any decimal in the range [2.045, 2.0545). * The result must be pre-rounded to within this rounding expression's scale. * @param result the result to find an input range for. Must be producable. * @return a KeyRange of DECIMAL keys that can be rounded by this expression to produce result * @throws IllegalArgumentException if the result has more scale than this expression can produce */ protected KeyRange getInputRangeProducing(BigDecimal result) { if(!hasEnoughPrecisionToProduce(result)) { throw new IllegalArgumentException("Cannot produce input range for decimal " + result + ", not enough precision with scale " + getRoundingScale()); } byte[] lowerRange = PDecimal.INSTANCE.toBytes(halfStepPrevInScale(result)); byte[] upperRange = PDecimal.INSTANCE.toBytes(halfStepNextInScale(result)); // inclusiveness changes depending on sign // e.g. -0.5 rounds "up" to -1 even though it is the lower boundary boolean lowerInclusive = result.signum() > 0; boolean upperInclusive = result.signum() < 0; return KeyRange.getKeyRange(lowerRange, lowerInclusive, upperRange, upperInclusive); }
private void testReadDecimalPrecisionAndScaleFromRawBytes(BigDecimal bd, SortOrder sortOrder) { byte[] b = PDecimal.INSTANCE.toBytes(bd, sortOrder); int[] v = PDataType.getDecimalPrecisionAndScale(b, 0, b.length, sortOrder); assertEquals(bd.toString(), bd.precision(), v[0]); assertEquals(bd.toString(), bd.scale(), v[1]); }
/** * Produces the next Decimal key relative to the given key. The new key will differ from the * old key in as small a unit as possible while still maintaining accurate serialization. * @param key bytes for the old Decimal key * @return bytes for the new Decimal key, a single unit next from the old one */ private static byte[] nextDecimalKey(byte[] key) { BigDecimal decimal = (BigDecimal) PDecimal.INSTANCE.toObject(key); BigDecimal next = decimal.add(getSmallestUnit(decimal)); return PDecimal.INSTANCE.toBytes(next); }
/** * Produces the previous Decimal key relative to the given key. The new key will differ from * the old key in as small a unit as possible while still maintaining accurate serialization. * @param key bytes for the old Decimal key * @return bytes for the new Decimal key, a single unit previous to the old one */ private static byte[] prevDecimalKey(byte[] key) { BigDecimal decimal = (BigDecimal) PDecimal.INSTANCE.toObject(key); BigDecimal prev = decimal.subtract(getSmallestUnit(decimal)); return PDecimal.INSTANCE.toBytes(prev); }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { Expression childExpr = children.get(0); if(childExpr.evaluate(tuple, ptr)) { if (ptr.getLength()==0) { return true; } BigDecimal value = (BigDecimal) PDecimal.INSTANCE.toObject(ptr, childExpr.getDataType(), childExpr.getSortOrder()); BigDecimal scaledValue = value.setScale(scale, getRoundingMode()); ptr.set(PDecimal.INSTANCE.toBytes(scaledValue)); return true; } return false; }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (!countFunc.evaluate(tuple, ptr)) { return false; } long count = countFunc.getDataType().getCodec().decodeLong(ptr, SortOrder.getDefault()); if (count == 0) { return false; } // Normal case where a column reference was used as the argument to AVG if (!countFunc.isConstantExpression()) { sumFunc.evaluate(tuple, ptr); BigDecimal sum = (BigDecimal) PDecimal.INSTANCE.toObject(ptr, sumFunc.getDataType()); // For the final column projection, we divide the sum by the count, both coerced to BigDecimal. // TODO: base the precision on column metadata instead of constant BigDecimal avg = sum.divide(BigDecimal.valueOf(count), PDataType.DEFAULT_MATH_CONTEXT); avg = avg.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(avg)); return true; } BigDecimal value = (BigDecimal) ((LiteralExpression)countFunc.getChildren().get(0)).getValue(); value = value.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(value)); return true; }
throw new DataExceedsCapacityException(PDecimal.INSTANCE, maxLength, scale); ptr.set(PDecimal.INSTANCE.toBytes(result)); return true;
@Test public void testFloorDecimalExpressionKeyRangeSimple() throws Exception { KeyPart baseKeyPart = getDecimalKeyPart(); ScalarFunction floorDecimalExpression = (ScalarFunction)FloorDecimalExpression.create(DUMMY_DECIMAL, 3); byte[] upperBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.239")); byte[] lowerBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.238")); KeyRange expectedKeyRange = KeyRange.getKeyRange(lowerBound, true, upperBound, false); KeyPart keyPart = floorDecimalExpression.newKeyPart(baseKeyPart); assertEquals(expectedKeyRange, keyPart.getKeyRange(CompareOp.EQUAL, LiteralExpression.newConstant(new BigDecimal("1.238"), PDecimal.INSTANCE))); }
@Test public void testCeilDecimalExpressionKeyRangeSimple() throws Exception { KeyPart baseKeyPart = getDecimalKeyPart(); ScalarFunction ceilDecimalExpression = (ScalarFunction)CeilDecimalExpression.create(DUMMY_DECIMAL, 3); byte[] upperBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.238")); byte[] lowerBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.237")); KeyRange expectedKeyRange = KeyRange.getKeyRange(lowerBound, false, upperBound, true); KeyPart keyPart = ceilDecimalExpression.newKeyPart(baseKeyPart); assertEquals(expectedKeyRange, keyPart.getKeyRange(CompareOp.EQUAL, LiteralExpression.newConstant(new BigDecimal("1.238"), PDecimal.INSTANCE))); }
@Test public void testRoundDecimalExpressionKeyRangeSimple() throws Exception { KeyPart baseKeyPart = getDecimalKeyPart(); ScalarFunction roundDecimalExpression = (ScalarFunction)RoundDecimalExpression.create(DUMMY_DECIMAL, 3); byte[] upperBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.2385")); byte[] lowerBound = PDecimal.INSTANCE.toBytes(new BigDecimal("1.2375")); KeyRange expectedKeyRange = KeyRange.getKeyRange(lowerBound, upperBound); KeyPart keyPart = roundDecimalExpression.newKeyPart(baseKeyPart); assertEquals(expectedKeyRange, keyPart.getKeyRange(CompareOp.EQUAL, LiteralExpression.newConstant(new BigDecimal("1.238"), PDecimal.INSTANCE))); }
throw new DataExceedsCapacityException(PDecimal.INSTANCE, getMaxLength(), getScale()); ptr.set(PDecimal.INSTANCE.toBytes(result)); return true;
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (!super.evaluate(tuple, ptr)) { return false; } if (isConstantExpression()) { PDataType type = getDataType(); Object constantValue = ((LiteralExpression)children.get(0)).getValue(); if (type == PDecimal.INSTANCE) { BigDecimal value = ((BigDecimal)constantValue).multiply((BigDecimal) PDecimal.INSTANCE.toObject(ptr, PLong.INSTANCE)); ptr.set(PDecimal.INSTANCE.toBytes(value)); } else { long constantLongValue = ((Number)constantValue).longValue(); long value = constantLongValue * type.getCodec().decodeLong(ptr, SortOrder.getDefault()); byte[] resultPtr = new byte[type.getByteSize()]; type.getCodec().encodeLong(value, resultPtr, 0); ptr.set(resultPtr); } } return true; }
throw new DataExceedsCapacityException(PDecimal.INSTANCE, getMaxLength(), getScale()); ptr.set(PDecimal.INSTANCE.toBytes(result)); return true;
@Test public void testDoubleToDecimalComparison() { // Basic tests assertTrue(PDouble.INSTANCE.compareTo(PDouble.INSTANCE.toBytes(1.23), 0, PDouble.INSTANCE.getByteSize(), SortOrder.getDefault(), PDecimal.INSTANCE.toBytes(BigDecimal.valueOf(1.24)), 0, PDecimal.INSTANCE.getByteSize(), SortOrder.getDefault(), PDecimal.INSTANCE) < 0); }
@Test public void testDescDecimalRange() throws SQLException { String ddl = "create table t (k1 bigint not null, k2 decimal, constraint pk primary key (k1,k2 desc))"; Connection conn = DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES)); conn.createStatement().execute(ddl); String query = "select * from t where k1 in (1,2) and k2>1.0"; Scan scan = compileStatement(query).getScan(); byte[] startRow = ByteUtil.concat(PLong.INSTANCE.toBytes(1), ByteUtil.nextKey(QueryConstants.SEPARATOR_BYTE_ARRAY), QueryConstants.DESC_SEPARATOR_BYTE_ARRAY); byte[] upperValue = PDecimal.INSTANCE.toBytes(BigDecimal.valueOf(1.0)); byte[] stopRow = ByteUtil.concat(PLong.INSTANCE.toBytes(2), SortOrder.invert(upperValue,0,upperValue.length), QueryConstants.DESC_SEPARATOR_BYTE_ARRAY); assertTrue(scan.getFilter() instanceof SkipScanFilter); assertArrayEquals(startRow, scan.getStartRow()); assertArrayEquals(stopRow, scan.getStopRow()); }
bytes = PDecimal.INSTANCE.toBytes(dec); Object b = PBoolean.INSTANCE.toObject(bytes, 0, bytes.length, PDecimal.INSTANCE, SortOrder.ASC); assertEquals(true, b); bytes = PDecimal.INSTANCE.toBytes(dec); b = PBoolean.INSTANCE.toObject(bytes, 0, bytes.length, PDecimal.INSTANCE, SortOrder.ASC); assertEquals(false, b); bytes = PDecimal.INSTANCE.toBytes(dec, SortOrder.DESC); b = PBoolean.INSTANCE.toObject(bytes, 0, bytes.length, PDecimal.INSTANCE, SortOrder.DESC); assertEquals(true, b); bytes = PDecimal.INSTANCE.toBytes(dec, SortOrder.DESC); b = PBoolean.INSTANCE.toObject(bytes, 0, bytes.length, PDecimal.INSTANCE, SortOrder.DESC); assertEquals(false, b);