@Override public KeySlots visitLeave(InListExpression node, List<KeySlots> childParts) { if (childParts.isEmpty()) { return null; } List<Expression> keyExpressions = node.getKeyExpressions(); Set<KeyRange> ranges = Sets.newHashSetWithExpectedSize(keyExpressions.size()); KeySlot childSlot = childParts.get(0).getSlots().get(0); KeyPart childPart = childSlot.getKeyPart(); // Handles cases like WHERE substr(foo,1,3) IN ('aaa','bbb') for (Expression key : keyExpressions) { KeyRange range = childPart.getKeyRange(CompareOp.EQUAL, key); if (range == null) { return null; } if (range != KeyRange.EMPTY_RANGE) { // null means it can't possibly be in range ranges.add(range); } } return newKeyParts(childSlot, node, new ArrayList<KeyRange>(ranges)); }
@Override public KeySlots visitLeave(ComparisonExpression node, List<KeySlots> childParts) { // Delay adding to extractedNodes, until we're done traversing, // since we can't yet tell whether or not the PK column references // are contiguous if (childParts.isEmpty()) { return null; } Expression rhs = node.getChildren().get(1); KeySlots childSlots = childParts.get(0); KeySlot childSlot = childSlots.getSlots().get(0); KeyPart childPart = childSlot.getKeyPart(); //SortOrder sortOrder = childPart.getColumn().getSortOrder(); CompareOp op = node.getFilterOp(); //CompareOp op = sortOrder.transform(node.getFilterOp()); KeyRange keyRange = childPart.getKeyRange(op, rhs); return newKeyParts(childSlot, node, keyRange); }
/** * Checks that a given KeyPart produces the right key ranges for each relational operator and * a variety of right-hand-side decimals. * @param exprType the rounding expression type used to create this KeyPart * @param scale the scale used to create this KeyPart * @param keyPart the KeyPart to test */ private void verifyKeyPart(RoundingType exprType, int scale, KeyPart keyPart) throws SQLException { for(BigDecimal rhsDecimal : DECIMALS) { LiteralExpression rhsExpression = LiteralExpression.newConstant(rhsDecimal, PDecimal.INSTANCE); for(Relation relation : Relation.values()) { KeyRange keyRange = keyPart.getKeyRange(relation.compareOp, rhsExpression); verifyKeyRange(exprType, scale, relation, rhsDecimal, keyRange); } } }
@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))); }
@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))); }
default: return childPart.getKeyRange(op, rhs);
@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 KeyRange getKeyRange(CompareOp op, Expression rhs) { KeyRange range = childPart.getKeyRange(op, rhs); return range.invert(); }
break; default: return childPart.getKeyRange(op, rhs);
@Override public KeyRange getKeyRange(CompareOp op, Expression rhs) { KeyRange range = childPart.getKeyRange(op, rhs); byte[] lower = range.getLowerRange(); if (!range.lowerUnbound()) { ptr.set(lower); // Do the reverse translation so we can optimize out the coerce expression // For the actual type of the coerceBytes call, we use the node type instead of the rhs type, because // for IN, the rhs type will be VARBINARY and no coerce will be done in that case (and we need it to // be done). node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), SortOrder.ASC); lower = ByteUtil.copyKeyBytesIfNecessary(ptr); } byte[] upper = range.getUpperRange(); if (!range.upperUnbound()) { ptr.set(upper); // Do the reverse translation so we can optimize out the coerce expression node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), SortOrder.ASC); upper = ByteUtil.copyKeyBytesIfNecessary(ptr); } range = KeyRange.getKeyRange(lower, range.isLowerInclusive(), upper, range.isUpperInclusive()); return range; }
break; default: return childPart.getKeyRange(op, rhs);
@Override public KeySlots visitLeave(InListExpression node, List<KeySlots> childParts) { if (childParts.isEmpty()) { return null; } List<Expression> keyExpressions = node.getKeyExpressions(); Set<KeyRange> ranges = Sets.newHashSetWithExpectedSize(keyExpressions.size()); KeySlot childSlot = childParts.get(0).iterator().next(); KeyPart childPart = childSlot.getKeyPart(); // Handles cases like WHERE substr(foo,1,3) IN ('aaa','bbb') for (Expression key : keyExpressions) { KeyRange range = childPart.getKeyRange(CompareOp.EQUAL, key); if (range == null) { return null; } if (range != KeyRange.EMPTY_RANGE) { // null means it can't possibly be in range ranges.add(range); } } return newKeyParts(childSlot, node, new ArrayList<KeyRange>(ranges), null); }
@Override public KeySlots visitLeave(InListExpression node, List<KeySlots> childParts) { if (childParts.isEmpty()) { return null; } List<Expression> keyExpressions = node.getKeyExpressions(); Set<KeyRange> ranges = Sets.newHashSetWithExpectedSize(keyExpressions.size()); KeySlot childSlot = childParts.get(0).getSlots().get(0); KeyPart childPart = childSlot.getKeyPart(); // Handles cases like WHERE substr(foo,1,3) IN ('aaa','bbb') for (Expression key : keyExpressions) { KeyRange range = childPart.getKeyRange(CompareOp.EQUAL, key); if (range == null) { return null; } if (range != KeyRange.EMPTY_RANGE) { // null means it can't possibly be in range ranges.add(range); } } return newKeyParts(childSlot, node, new ArrayList<KeyRange>(ranges)); }
@Override public KeySlots visitLeave(ComparisonExpression node, List<KeySlots> childParts) { // Delay adding to extractedNodes, until we're done traversing, // since we can't yet tell whether or not the PK column references // are contiguous if (childParts.isEmpty()) { return null; } Expression rhs = node.getChildren().get(1); KeySlots childSlots = childParts.get(0); KeySlot childSlot = childSlots.getSlots().get(0); KeyPart childPart = childSlot.getKeyPart(); //SortOrder sortOrder = childPart.getColumn().getSortOrder(); CompareOp op = node.getFilterOp(); //CompareOp op = sortOrder.transform(node.getFilterOp()); KeyRange keyRange = childPart.getKeyRange(op, rhs); return newKeyParts(childSlot, node, keyRange); }
@Override public KeySlots visitLeave(ComparisonExpression node, List<KeySlots> childParts) { // Delay adding to extractedNodes, until we're done traversing, // since we can't yet tell whether or not the PK column references // are contiguous if (childParts.isEmpty()) { return null; } Expression rhs = node.getChildren().get(1); KeySlots childSlots = childParts.get(0); KeySlot childSlot = childSlots.iterator().next(); KeyPart childPart = childSlot.getKeyPart(); SortOrder sortOrder = childPart.getColumn().getSortOrder(); CompareOp op = sortOrder.transform(node.getFilterOp()); KeyRange keyRange = childPart.getKeyRange(op, rhs); return newKeyParts(childSlot, node, keyRange); }
@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; }
return type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false); default: return childPart.getKeyRange(op, rhs);
@Override public KeyRange getKeyRange(CompareOp op, Expression rhs) { KeyRange range = childPart.getKeyRange(op, rhs); byte[] lower = range.getLowerRange(); if (!range.lowerUnbound()) { ptr.set(lower); // Do the reverse translation so we can optimize out the coerce expression // For the actual type of the coerceBytes call, we use the node type instead of the rhs type, because // for IN, the rhs type will be VARBINARY and no coerce will be done in that case (and we need it to // be done). node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), SortOrder.ASC); lower = ByteUtil.copyKeyBytesIfNecessary(ptr); } byte[] upper = range.getUpperRange(); if (!range.upperUnbound()) { ptr.set(upper); // Do the reverse translation so we can optimize out the coerce expression node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), SortOrder.ASC); upper = ByteUtil.copyKeyBytesIfNecessary(ptr); } range = KeyRange.getKeyRange(lower, range.isLowerInclusive(), upper, range.isUpperInclusive()); return range; }
@Override public KeyRange getKeyRange(CompareOp op, Expression rhs) { KeyRange range = childPart.getKeyRange(op, rhs); byte[] lower = range.getLowerRange(); if (!range.lowerUnbound()) { ptr.set(lower); // Do the reverse translation so we can optimize out the coerce expression // For the actual type of the coerceBytes call, we use the node type instead of the rhs type, because // for IN, the rhs type will be VARBINARY and no coerce will be done in that case (and we need it to // be done). node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), node.getChild().getSortOrder()); lower = ByteUtil.copyKeyBytesIfNecessary(ptr); } byte[] upper = range.getUpperRange(); if (!range.upperUnbound()) { ptr.set(upper); // Do the reverse translation so we can optimize out the coerce expression node.getChild().getDataType().coerceBytes(ptr, node.getDataType(), rhs.getSortOrder(), node.getChild().getSortOrder()); upper = ByteUtil.copyKeyBytesIfNecessary(ptr); } return KeyRange.getKeyRange(lower, range.isLowerInclusive(), upper, range.isUpperInclusive()); }