private static Result extractMetadata()

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;
                }
            }
        }
    }