/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to you under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eigenbase.relopt; import java.util.BitSet; import java.util.List; import org.eigenbase.rex.RexCall; import org.eigenbase.rex.RexInputRef; import org.eigenbase.rex.RexLiteral; import org.eigenbase.rex.RexNode; /** Utilities for strong predicates. * * <p>A predicate is strong (or null-rejecting) if it is UNKNOWN if any of its * inputs is UNKNOWN.</p> * * <p>By the way, UNKNOWN is just the boolean form of NULL.</p> * * <p>Examples:</p> * <ul> * <li>{@code UNKNOWN} is strong * <li>{@code c = 1} is strong * <li>{@code c IS NULL} is not strong. (It always returns TRUE or FALSE.) * <li>{@code p1 AND p2} is strong if p1 or p2 are strong * <li>{@code p1 OR p2} is strong if p1 and p2 are strong * <li>{@code c1 = 1 OR c2 IS NULL} is strong on c1 but not c2 * </ul> */ public class Strong { private final BitSet nullColumns; private Strong(BitSet nullColumns) { this.nullColumns = nullColumns; } public static Strong of(BitSet nullColumns) { return new Strong(nullColumns); } /** Returns whether the analyzed expression will return null if a given set * of input columns are null. */ public static boolean is(RexNode node, BitSet nullColumns) { return of(nullColumns).strong(node); } private boolean strong(RexNode node) { switch (node.getKind()) { case LITERAL: return ((RexLiteral) node).getValue() == null; case IS_TRUE: case IS_NOT_NULL: case AND: case EQUALS: case NOT_EQUALS: case LESS_THAN: case LESS_THAN_OR_EQUAL: case GREATER_THAN: case GREATER_THAN_OR_EQUAL: return anyStrong(((RexCall) node).getOperands()); case OR: return allStrong(((RexCall) node).getOperands()); case INPUT_REF: return nullColumns.get(((RexInputRef) node).getIndex()); default: return false; } } private boolean allStrong(List<RexNode> operands) { for (RexNode operand : operands) { if (!strong(operand)) { return false; } } return true; } private boolean anyStrong(List<RexNode> operands) { for (RexNode operand : operands) { if (strong(operand)) { return true; } } return false; } } // End Strong.java