blob: 6ec514e30e00cb568c2a1458f24b2814faeb0ccf [file] [log] [blame]
/*
* 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.apache.calcite.rex;
/** Policy for whether a simplified expression may instead return another
* value.
*
* <p>In particular, it deals with converting three-valued logic (TRUE, FALSE,
* UNKNOWN) to two-valued logic (TRUE, FALSE) for callers that treat the UNKNOWN
* value the same as TRUE or FALSE.
*
* <p>Sometimes the three-valued version of the expression is simpler (has a
* smaller expression tree) than the two-valued version. In these cases,
* favor simplicity over reduction to two-valued logic.
*
* @see RexSimplify */
public enum RexUnknownAs {
/** Policy that indicates that the expression is being used in a context
* Where an UNKNOWN value is treated in the same way as FALSE. Therefore, when
* simplifying the expression, it is acceptable for the simplified expression
* to evaluate to FALSE in some situations where the original expression would
* evaluate to UNKNOWN.
*
* <p>SQL predicates ({@code WHERE}, {@code ON}, {@code HAVING} and
* {@code FILTER (WHERE)} clauses, a {@code WHEN} clause of a {@code CASE}
* expression, and in {@code CHECK} constraints) all treat UNKNOWN as FALSE.
*
* <p>If the simplified expression never returns UNKNOWN, the simplifier
* should make this clear to the caller, if possible, by marking its type as
* {@code BOOLEAN NOT NULL}. */
FALSE,
/** Policy that indicates that the expression is being used in a context
* Where an UNKNOWN value is treated in the same way as TRUE. Therefore, when
* simplifying the expression, it is acceptable for the simplified expression
* to evaluate to TRUE in some situations where the original expression would
* evaluate to UNKNOWN.
*
* <p>This does not occur commonly in SQL. However, it occurs internally
* during simplification. For example, "{@code WHERE NOT expression}"
* evaluates "{@code NOT expression}" in a context that treats UNKNOWN as
* FALSE; it is useful to consider that "{@code expression}" is evaluated in a
* context that treats UNKNOWN as TRUE.
*
* <p>If the simplified expression never returns UNKNOWN, the simplifier
* should make this clear to the caller, if possible, by marking its type as
* {@code BOOLEAN NOT NULL}. */
TRUE,
/** Policy that indicates that the expression is being used in a context
* Where an UNKNOWN value is treated as is. This occurs:
*
* <ul>
* <li>In any expression whose type is not {@code BOOLEAN}
* <li>In {@code BOOLEAN} expressions that are {@code NOT NULL}
* <li>In {@code BOOLEAN} expressions where {@code UNKNOWN} should be
* returned as is, for example in a {@code SELECT} clause, or within an
* expression such as an operand to {@code AND}, {@code OR} or
* {@code NOT}
* </ul>
*
* <p>If you are unsure, use UNKNOWN. It is the safest option. */
UNKNOWN;
/** Returns {@link #FALSE} if {@code unknownAsFalse} is true,
* {@link #UNKNOWN} otherwise. */
public static RexUnknownAs falseIf(boolean unknownAsFalse) {
return unknownAsFalse ? FALSE : UNKNOWN;
}
public boolean toBoolean() {
switch (this) {
case FALSE:
return false;
case TRUE:
return true;
default:
throw new IllegalArgumentException("unknown");
}
}
public RexUnknownAs negate() {
switch (this) {
case TRUE:
return FALSE;
case FALSE:
return TRUE;
default:
return UNKNOWN;
}
}
/** Combines this with another {@code RexUnknownAs} in the same way as the
* three-valued logic of OR.
*
* <p>For example, {@code TRUE or FALSE} returns {@code TRUE};
* {@code FALSE or UNKNOWN} returns {@code UNKNOWN}. */
public RexUnknownAs or(RexUnknownAs other) {
switch (this) {
case TRUE:
return this;
case UNKNOWN:
return other == TRUE ? other : this;
case FALSE:
default:
return other;
}
}
}