use of com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet in project aws-athena-query-federation by awslabs.
the class JdbcSplitQueryBuilder method toPredicate.
private String toPredicate(String columnName, ValueSet valueSet, ArrowType type, List<TypeAndValue> accumulator) {
List<String> disjuncts = new ArrayList<>();
List<Object> singleValues = new ArrayList<>();
if (valueSet instanceof SortedRangeSet) {
if (valueSet.isNone() && valueSet.isNullAllowed()) {
return String.format("(%s IS NULL)", quote(columnName));
}
if (valueSet.isNullAllowed()) {
disjuncts.add(String.format("(%s IS NULL)", quote(columnName)));
}
Range rangeSpan = ((SortedRangeSet) valueSet).getSpan();
if (!valueSet.isNullAllowed() && rangeSpan.getLow().isLowerUnbounded() && rangeSpan.getHigh().isUpperUnbounded()) {
return String.format("(%s IS NOT NULL)", quote(columnName));
}
for (Range range : valueSet.getRanges().getOrderedRanges()) {
if (range.isSingleValue()) {
singleValues.add(range.getLow().getValue());
} else {
List<String> rangeConjuncts = new ArrayList<>();
if (!range.getLow().isLowerUnbounded()) {
switch(range.getLow().getBound()) {
case ABOVE:
rangeConjuncts.add(toPredicate(columnName, ">", range.getLow().getValue(), type, accumulator));
break;
case EXACTLY:
rangeConjuncts.add(toPredicate(columnName, ">=", range.getLow().getValue(), type, accumulator));
break;
case BELOW:
throw new IllegalArgumentException("Low marker should never use BELOW bound");
default:
throw new AssertionError("Unhandled bound: " + range.getLow().getBound());
}
}
if (!range.getHigh().isUpperUnbounded()) {
switch(range.getHigh().getBound()) {
case ABOVE:
throw new IllegalArgumentException("High marker should never use ABOVE bound");
case EXACTLY:
rangeConjuncts.add(toPredicate(columnName, "<=", range.getHigh().getValue(), type, accumulator));
break;
case BELOW:
rangeConjuncts.add(toPredicate(columnName, "<", range.getHigh().getValue(), type, accumulator));
break;
default:
throw new AssertionError("Unhandled bound: " + range.getHigh().getBound());
}
}
// If rangeConjuncts is null, then the range was ALL, which should already have been checked for
Preconditions.checkState(!rangeConjuncts.isEmpty());
disjuncts.add("(" + Joiner.on(" AND ").join(rangeConjuncts) + ")");
}
}
// Add back all of the possible single values either as an equality or an IN predicate
if (singleValues.size() == 1) {
disjuncts.add(toPredicate(columnName, "=", Iterables.getOnlyElement(singleValues), type, accumulator));
} else if (singleValues.size() > 1) {
for (Object value : singleValues) {
accumulator.add(new TypeAndValue(type, value));
}
String values = Joiner.on(",").join(Collections.nCopies(singleValues.size(), "?"));
disjuncts.add(quote(columnName) + " IN (" + values + ")");
}
}
return "(" + Joiner.on(" OR ").join(disjuncts) + ")";
}
use of com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet in project aws-athena-query-federation by awslabs.
the class PropertyGraphHandler method getQueryPartForContraintsMap.
/**
* Used to generate Gremlin Query part for Constraint Map
*
* @param traversal Gremlin Traversal, traversal is updated based on constraints
* map
* @param hasMap Constraint Hash Map
*
* @return A Gremlin Query Part equivalent to Contraint.
*/
public GraphTraversal getQueryPartForContraintsMap(GraphTraversal traversal, final ReadRecordsRequest recordsRequest) {
final Map<String, ValueSet> hashMap = recordsRequest.getConstraints().getSummary();
if (hashMap.size() == 0) {
return traversal;
}
logger.info("readWithContraint: Constaints Map " + hashMap.toString());
final Set<String> setOfkeys = (Set<String>) (hashMap.keySet());
for (final String key : setOfkeys) {
if (hashMap.get(key) instanceof SortedRangeSet) {
final List<Range> ranges = ((SortedRangeSet) hashMap.get(key)).getOrderedRanges();
for (final Range range : ranges) {
if (!range.getLow().isNullValue() && !range.getHigh().isNullValue()) {
if (range.getLow().getValue().toString().equals(range.getHigh().getValue().toString())) {
traversal = GremlinQueryPreProcessor.generateGremlinQueryPart(traversal, key, range.getLow().getValue().toString(), range.getType(), range.getLow().getBound(), GremlinQueryPreProcessor.Operator.EQUALTO);
break;
}
}
if (!range.getLow().isNullValue()) {
traversal = GremlinQueryPreProcessor.generateGremlinQueryPart(traversal, key, range.getLow().getValue().toString(), range.getType(), range.getLow().getBound(), GremlinQueryPreProcessor.Operator.GREATERTHAN);
}
if (!range.getHigh().isNullValue()) {
traversal = GremlinQueryPreProcessor.generateGremlinQueryPart(traversal, key, range.getHigh().getValue().toString(), range.getType(), range.getHigh().getBound(), GremlinQueryPreProcessor.Operator.LESSTHAN);
}
}
}
if (hashMap.get(key) instanceof EquatableValueSet) {
final EquatableValueSet valueSet = ((EquatableValueSet) hashMap.get(key));
if (valueSet.isWhiteList()) {
traversal = GremlinQueryPreProcessor.generateGremlinQueryPart(traversal, key, valueSet.getValue(0).toString(), valueSet.getType(), null, GremlinQueryPreProcessor.Operator.EQUALTO);
} else {
traversal = GremlinQueryPreProcessor.generateGremlinQueryPart(traversal, key, valueSet.getValue(0).toString(), valueSet.getType(), null, GremlinQueryPreProcessor.Operator.NOTEQUALTO);
}
}
}
return traversal;
}
use of com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet in project aws-athena-query-federation by awslabs.
the class SaphanaQueryStringBuilder method toPredicate.
private String toPredicate(String columnName, ValueSet valueSet, ArrowType type, List<SaphanaQueryStringBuilder.TypeAndValue> accumulator) {
List<String> disjuncts = new ArrayList<>();
List<Object> singleValues = new ArrayList<>();
if (valueSet instanceof SortedRangeSet) {
if (valueSet.isNone() && valueSet.isNullAllowed()) {
return String.format("(%s IS NULL)", quote(columnName));
}
if (valueSet.isNullAllowed()) {
disjuncts.add(String.format("(%s IS NULL)", quote(columnName)));
}
Range rangeSpan = ((SortedRangeSet) valueSet).getSpan();
if (!valueSet.isNullAllowed() && rangeSpan.getLow().isLowerUnbounded() && rangeSpan.getHigh().isUpperUnbounded()) {
return String.format("(%s IS NOT NULL)", quote(columnName));
}
for (Range range : valueSet.getRanges().getOrderedRanges()) {
if (range.isSingleValue()) {
singleValues.add(range.getLow().getValue());
} else {
List<String> rangeConjuncts = new ArrayList<>();
if (!range.getLow().isLowerUnbounded()) {
switch(range.getLow().getBound()) {
case ABOVE:
rangeConjuncts.add(toPredicate(columnName, ">", range.getLow().getValue(), type, accumulator));
break;
case EXACTLY:
rangeConjuncts.add(toPredicate(columnName, ">=", range.getLow().getValue(), type, accumulator));
break;
case BELOW:
throw new IllegalArgumentException("Low marker should never use BELOW bound");
default:
throw new AssertionError("Unhandled bound: " + range.getLow().getBound());
}
}
if (!range.getHigh().isUpperUnbounded()) {
switch(range.getHigh().getBound()) {
case ABOVE:
throw new IllegalArgumentException("High marker should never use ABOVE bound");
case EXACTLY:
rangeConjuncts.add(toPredicate(columnName, "<=", range.getHigh().getValue(), type, accumulator));
break;
case BELOW:
rangeConjuncts.add(toPredicate(columnName, "<", range.getHigh().getValue(), type, accumulator));
break;
default:
throw new AssertionError("Unhandled bound: " + range.getHigh().getBound());
}
}
// If rangeConjuncts is null, then the range was ALL, which should already have been checked for
Preconditions.checkState(!rangeConjuncts.isEmpty());
disjuncts.add("(" + Joiner.on(" AND ").join(rangeConjuncts) + ")");
}
}
// Add back all of the possible single values either as an equality or an IN predicate
if (singleValues.size() == 1) {
disjuncts.add(toPredicate(columnName, "=", Iterables.getOnlyElement(singleValues), type, accumulator));
} else if (singleValues.size() > 1) {
for (Object value : singleValues) {
accumulator.add(new SaphanaQueryStringBuilder.TypeAndValue(type, value));
}
String values = Joiner.on(",").join(Collections.nCopies(singleValues.size(), "?"));
disjuncts.add(quote(columnName) + " IN (" + values + ")");
}
}
return "(" + Joiner.on(" OR ").join(disjuncts) + ")";
}
use of com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet in project aws-athena-query-federation by awslabs.
the class CloudwatchRecordHandler method pushDownConstraints.
/**
* Attempts to push down predicates into Cloudwatch Logs by decorating the Cloudwatch Logs request.
*
* @param constraints The constraints for the read as provided by Athena based on the customer's query.
* @param request The Cloudwatch Logs request to inject predicates to.
* @return The decorated Cloudwatch Logs request.
* @note This impl currently only pushing down SortedRangeSet filters (>=, =<, between) on the log time column.
*/
private GetLogEventsRequest pushDownConstraints(Constraints constraints, GetLogEventsRequest request) {
ValueSet timeConstraint = constraints.getSummary().get(LOG_TIME_FIELD);
if (timeConstraint instanceof SortedRangeSet && !timeConstraint.isNullAllowed()) {
// SortedRangeSet is how >, <, between is represented which are easiest and most common when
// searching logs so we attempt to push that down here as an optimization. SQL can represent complex
// overlapping ranges which Cloudwatch can not support so this is not a replacement for applying
// constraints using the ConstraintEvaluator.
Range basicPredicate = ((SortedRangeSet) timeConstraint).getSpan();
if (!basicPredicate.getLow().isNullValue()) {
Long lowerBound = (Long) basicPredicate.getLow().getValue();
request.setStartTime(lowerBound);
}
if (!basicPredicate.getHigh().isNullValue()) {
Long upperBound = (Long) basicPredicate.getHigh().getValue();
request.setEndTime(upperBound);
}
}
return request;
}
use of com.amazonaws.athena.connector.lambda.domain.predicate.SortedRangeSet in project aws-athena-query-federation by awslabs.
the class DDBPredicateUtils method generateSingleColumnFilter.
/**
* Generates a filter expression for a single column given a {@link ValueSet} predicate for that column.
*
* @param originalColumnName the column name
* @param predicate the associated predicate
* @param accumulator the value accumulator to add values to
* @param valueNameProducer the value name producer to generate value aliases with
* @param recordMetadata object containing any necessary metadata from the glue table
* @return the generated filter expression
*/
public static String generateSingleColumnFilter(String originalColumnName, ValueSet predicate, List<AttributeValue> accumulator, IncrementingValueNameProducer valueNameProducer, DDBRecordMetadata recordMetadata) {
String columnName = aliasColumn(originalColumnName);
if (predicate.isNone()) {
return "(attribute_not_exists(" + columnName + ") OR " + toPredicate(originalColumnName, "=", null, accumulator, valueNameProducer.getNext(), recordMetadata) + ")";
}
if (predicate.isAll()) {
return "(attribute_exists(" + columnName + ") AND " + toPredicate(originalColumnName, "<>", null, accumulator, valueNameProducer.getNext(), recordMetadata) + ")";
}
List<String> disjuncts = new ArrayList<>();
List<Object> singleValues = new ArrayList<>();
boolean isWhitelist = true;
if (predicate instanceof SortedRangeSet) {
for (Range range : predicate.getRanges().getOrderedRanges()) {
// Already checked
checkState(!range.isAll());
if (range.isSingleValue()) {
singleValues.add(range.getLow().getValue());
} else {
List<String> rangeConjuncts = new ArrayList<>();
if (!range.getLow().isLowerUnbounded()) {
switch(range.getLow().getBound()) {
case ABOVE:
rangeConjuncts.add(toPredicate(originalColumnName, ">", range.getLow().getValue(), accumulator, valueNameProducer.getNext(), recordMetadata));
break;
case EXACTLY:
rangeConjuncts.add(toPredicate(originalColumnName, ">=", range.getLow().getValue(), accumulator, valueNameProducer.getNext(), recordMetadata));
break;
case BELOW:
throw new IllegalArgumentException("Low marker should never use BELOW bound");
default:
throw new AssertionError("Unhandled lower bound: " + range.getLow().getBound());
}
}
if (!range.getHigh().isUpperUnbounded()) {
switch(range.getHigh().getBound()) {
case ABOVE:
throw new IllegalArgumentException("High marker should never use ABOVE bound");
case EXACTLY:
rangeConjuncts.add(toPredicate(originalColumnName, "<=", range.getHigh().getValue(), accumulator, valueNameProducer.getNext(), recordMetadata));
break;
case BELOW:
rangeConjuncts.add(toPredicate(originalColumnName, "<", range.getHigh().getValue(), accumulator, valueNameProducer.getNext(), recordMetadata));
break;
default:
throw new AssertionError("Unhandled upper bound: " + range.getHigh().getBound());
}
}
// If rangeConjuncts is null, then the range was ALL, which should already have been checked for
checkState(!rangeConjuncts.isEmpty());
disjuncts.add("(" + AND_JOINER.join(rangeConjuncts) + ")");
}
}
} else {
EquatableValueSet equatablePredicate = (EquatableValueSet) predicate;
isWhitelist = equatablePredicate.isWhiteList();
long valueCount = equatablePredicate.getValueBlock().getRowCount();
for (int i = 0; i < valueCount; i++) {
singleValues.add(equatablePredicate.getValue(i));
}
}
// Add back all of the possible single values either as an equality or an IN predicate
if (singleValues.size() == 1) {
disjuncts.add(toPredicate(originalColumnName, isWhitelist ? "=" : "<>", getOnlyElement(singleValues), accumulator, valueNameProducer.getNext(), recordMetadata));
} else if (singleValues.size() > 1) {
for (Object value : singleValues) {
bindValue(originalColumnName, value, accumulator, recordMetadata);
}
String values = COMMA_JOINER.join(Stream.generate(valueNameProducer::getNext).limit(singleValues.size()).collect(toImmutableList()));
disjuncts.add((isWhitelist ? "" : "NOT ") + columnName + " IN (" + values + ")");
}
// at this point we should have some disjuncts
checkState(!disjuncts.isEmpty());
// add nullability disjuncts
if (predicate.isNullAllowed()) {
disjuncts.add("attribute_not_exists(" + columnName + ") OR " + toPredicate(originalColumnName, "=", null, accumulator, valueNameProducer.getNext(), recordMetadata));
}
// DDB doesn't like redundant parentheses
if (disjuncts.size() == 1) {
return disjuncts.get(0);
}
return "(" + OR_JOINER.join(disjuncts) + ")";
}
Aggregations