in modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/pruning/PartitionPruningMetadataExtractor.java [315:533]
private static Result extractMetadata(RexNode node, IntList keys, RexBuilder rexBuilder, boolean negate) {
if (isColocationKey(node, keys)) {
// a standalone <bool_col> ref.
if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
RexLocalRef ref = (RexLocalRef) node;
return new PruningColumnSet(ref.getIndex(), rexBuilder.makeLiteral(!negate));
}
} else if (node.isA(SqlKind.LOCAL_REF)) {
return Result.RESTRICT;
}
List<RexNode> operands;
if (node instanceof RexCall) {
operands = ((RexCall) node).getOperands();
} else {
return Result.UNKNOWN;
}
switch (node.getKind()) {
case IS_NOT_DISTINCT_FROM:
case EQUALS: {
// NOT (c1 = <val>) -> c1 != <val> and we can not use a value.
// But NOT (c1 != <val>) -> c1 = <val>, and it can be used.
RexNode lhs;
RexNode rhs;
if (operands.get(0).isA(SqlKind.LOCAL_REF)) {
lhs = operands.get(0);
rhs = operands.get(1);
} else {
lhs = operands.get(1);
rhs = operands.get(0);
}
if (isColocationKey(lhs, keys) && isValueExpr(rhs)) {
if (negate) {
return Result.UNKNOWN;
} else {
RexLocalRef column = (RexLocalRef) lhs;
return new PruningColumnSet(column.getIndex(), rhs);
}
} else if (lhs.isA(SqlKind.LOCAL_REF) && isValueExpr(rhs)) {
// some column = <val> - preserve, in case of AND it can be ignored.
return Result.RESTRICT;
} else {
// Not a simple expression.
return Result.UNKNOWN;
}
}
case NOT_EQUALS:
case IS_DISTINCT_FROM: {
RexNode lhs;
RexNode rhs;
if (operands.get(0).isA(SqlKind.LOCAL_REF)) {
lhs = operands.get(0);
rhs = operands.get(1);
} else {
lhs = operands.get(1);
rhs = operands.get(0);
}
if (isColocationKey(lhs, keys) && isValueExpr(rhs)) {
// NOT(colo_key != <val>) => colo_key = <val>
if (negate) {
RexLocalRef column = (RexLocalRef) lhs;
return new PruningColumnSet(column.getIndex(), rhs);
} else {
return Result.UNKNOWN;
}
} else if (lhs.isA(SqlKind.LOCAL_REF) && isValueExpr(rhs)) {
// some column != <val> - preserve, in case of AND it can be ignored.
return Result.RESTRICT;
} else {
// Not a simple expression.
return Result.UNKNOWN;
}
}
case OR: {
PruningColumnSets res = new PruningColumnSets();
for (RexNode operand : operands) {
Result child = extractMetadata(operand, keys, rexBuilder, negate);
// In case of OR: we can not ignore additional condition,
// because OR increases the search space.
if (child == Result.UNKNOWN || child == Result.RESTRICT) {
return Result.UNKNOWN;
}
res.add(child);
}
return res;
}
case AND: {
PruningColumnSets res = new PruningColumnSets();
for (RexNode operand : operands) {
Result child = extractMetadata(operand, keys, rexBuilder, negate);
if (child == Result.UNKNOWN) {
return Result.UNKNOWN;
}
// In case of AND: we can ignore additional condition, because
// such condition only narrows the search space.
if (child == Result.RESTRICT) {
continue;
}
res.combine(child);
if (res.conflict) {
return Result.UNKNOWN;
}
}
return res;
}
case SEARCH: {
RexNode expandedSearch = RexUtil.expandSearch(rexBuilder, null, node);
assert !expandedSearch.isA(SqlKind.SEARCH) : "Search operation is not expanded: " + node;
return extractMetadata(expandedSearch, keys, rexBuilder, false);
}
case NOT: {
if (isColocationKey(operands.get(0), keys)) {
RexLocalRef column = (RexLocalRef) operands.get(0);
return new PruningColumnSet(column.getIndex(), rexBuilder.makeLiteral(negate));
} else {
return extractMetadata(operands.get(0), keys, rexBuilder, !negate);
}
}
case IS_NULL:
case IS_NOT_NULL: {
RexNode operand = operands.get(0);
if (operand.isA(SqlKind.LOCAL_REF)) {
return Result.RESTRICT;
} else {
// If we reach this branch with a colocated key which is never null,
// then IS_NOT_NULL is always true / IS_NULL is always false so there is something wrong here.
return Result.UNKNOWN;
}
}
case IS_FALSE:
case IS_TRUE: {
RexNode operand = operands.get(0);
if (isColocationKey(operand, keys)) {
RexLocalRef ref = (RexLocalRef) operand;
boolean value;
if (negate) {
// NOT (col IS FALSE) => col IS TRUE => col = true
value = node.getKind() == SqlKind.IS_FALSE;
} else {
// NOT (col IS TRUE) => col IS FALSE => col = false
value = node.getKind() == SqlKind.IS_TRUE;
}
return new PruningColumnSet(ref.getIndex(), rexBuilder.makeLiteral(value));
} else if (operand.isA(SqlKind.LOCAL_REF)) {
return Result.RESTRICT;
} else {
return Result.UNKNOWN;
}
}
case IS_NOT_FALSE:
case IS_NOT_TRUE: {
// IS_NOT_TRUE is used by case/when expression rewriter.
// IS_NOT_FALSE is added for symmetry.
boolean value;
if (negate) {
value = node.getKind() != SqlKind.IS_NOT_FALSE;
} else {
value = node.getKind() != SqlKind.IS_NOT_TRUE;
}
if (isColocationKey(operands.get(0), keys)) {
RexLocalRef column = (RexLocalRef) operands.get(0);
return new PruningColumnSet(column.getIndex(), rexBuilder.makeLiteral(value));
} else {
return extractMetadata(operands.get(0), keys, rexBuilder, !negate);
}
}
default: {
if (node.isA(SqlKind.BINARY_COMPARISON)) {
// Convert binary comparision operations to Result::RESTRICT
RexNode lhs;
RexNode rhs;
if (operands.get(0).isA(SqlKind.LOCAL_REF)) {
lhs = operands.get(0);
rhs = operands.get(1);
} else {
lhs = operands.get(1);
rhs = operands.get(0);
}
if (isColocationKey(lhs, keys) && isValueExpr(rhs)) {
// We can not extract values from expressions such as colo_key > 10
return Result.UNKNOWN;
} else if (lhs.isA(SqlKind.LOCAL_REF) && isValueExpr(rhs)) {
// We can use non_colo_key > 10 to narrow the search space.
return Result.RESTRICT;
} else {
return Result.UNKNOWN;
}
} else {
return Result.UNKNOWN;
}
}
}
}