Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed 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 io.trino.json;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.google.common.collect.ImmutableList;
import io.airlift.slice.Slice;
import io.trino.json.CachingResolver.ResolvedOperatorAndCoercions;
import io.trino.json.JsonPathEvaluator.Invoker;
import io.trino.json.ir.IrComparisonPredicate;
import io.trino.json.ir.IrConjunctionPredicate;
import io.trino.json.ir.IrDisjunctionPredicate;
import io.trino.json.ir.IrExistsPredicate;
import io.trino.json.ir.IrIsUnknownPredicate;
import io.trino.json.ir.IrJsonPathVisitor;
import io.trino.json.ir.IrNegationPredicate;
import io.trino.json.ir.IrPathNode;
import io.trino.json.ir.IrPredicate;
import io.trino.json.ir.IrStartsWithPredicate;
import io.trino.json.ir.JsonLiteralConversionException;
import io.trino.json.ir.TypedValue;
import io.trino.operator.scalar.StringFunctions;
import io.trino.spi.function.OperatorType;
import io.trino.spi.type.CharType;
import io.trino.spi.type.Type;
import io.trino.sql.tree.ComparisonExpression;
import java.util.List;
import java.util.Optional;
import static com.google.common.collect.Iterables.getOnlyElement;
import static io.trino.json.CachingResolver.ResolvedOperatorAndCoercions.RESOLUTION_ERROR;
import static io.trino.json.PathEvaluationUtil.unwrapArrays;
import static io.trino.json.ir.IrComparisonPredicate.Operator.EQUAL;
import static io.trino.json.ir.IrComparisonPredicate.Operator.NOT_EQUAL;
import static io.trino.json.ir.SqlJsonLiteralConverter.getTextTypedValue;
import static io.trino.json.ir.SqlJsonLiteralConverter.getTypedValue;
import static io.trino.spi.type.Chars.padSpaces;
import static io.trino.sql.analyzer.ExpressionAnalyzer.isCharacterStringType;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Objects.requireNonNull;
/**
* This visitor evaluates the JSON path predicate in JSON filter expression.
* The returned value is true, false or unknown.
*
* Filter predicate never throws error, both in lax or strict mode, even if evaluation
* of the nested JSON path fails or the predicate itself cannot be successfully evaluated
* (e.g. because it tries to compare incompatible types).
*
* NOTE Even though errors are suppressed both in lax and strict mode, the mode affects
* the predicate result.
* For example, let `$array` be a JSON array of size 3: `["a", "b", "c"]`,
* and let predicate be `exists($array[5])`
* The nested accessor expression `$array[5]` is a structural error (array index out of bounds).
* In lax mode, the error is suppressed, and `$array[5]` results in an empty sequence.
* Hence, the `exists` predicate returns `false`.
* In strict mode, the error is not suppressed, and the `exists` predicate returns `unknown`.
*
* NOTE on the semantics of comparison:
* The following comparison operators are supported in JSON path predicate: EQUAL, NOT EQUAL, LESS THAN, GREATER THAN, LESS THAN OR EQUAL, GREATER THAN OR EQUAL.
* Both operands are JSON paths, and so they are evaluated to sequences of objects.
*
* Technically, each of the objects is either a JsonNode, or a TypedValue.
* Logically, they can be divided into three categories:
* 1. scalar values. These are all the TypedValues and certain subtypes of JsonNode, e.g. IntNode, BooleanNode,...
* 2. non-scalars. These are JSON arrays and objects
* 3. NULL values. They are represented by JsonNode subtype NullNode.
*
* When comparing two objects, the following rules apply:
* 1. NULL can be successfully compared with any object. NULL equals NULL, and is neither equal, less than or greater than any other object.
* 2. non-scalars can be only compared with a NULL (the result being false). Comparing a non-scalar with any other object (including itself) results in error.
* 3. scalars can be compared with a NULL (the result being false). They can be also compared with other scalars, provided that the types of the
* compared scalars are eligible for comparison. Otherwise, comparing two scalars results in error.
*
* As mentioned before, the operands to comparison predicate produce sequences of objects.
* Comparing the sequences requires comparing every pair of objects from the first and the second sequence.
* The overall result of the comparison predicate depends on two factors:
* - if any comparison resulted in error,
* - if any comparison returned true.
* In strict mode, any error makes the overall result unknown.
* In lax mode, the SQL specification allows to either ignore errors, or return unknown in case of error.
* Our implementation choice is to finish the predicate evaluation as early as possible, that is,
* to return unknown on the first error or return true on the first comparison returning true.
* The result is deterministic, because the input sequences are processed in order.
* In case of no errors, the comparison predicate result is whether any comparison returned true.
*
* NOTE The starts with predicate, similarly to the comparison predicate, is applied to sequences of input items.
* It applies the same policy of translating errors into unknown result, and the same policy of returning true
* on the first success.
*/
class PathPredicateEvaluationVisitor
extends IrJsonPathVisitor
{
private final boolean lax;
private final PathEvaluationVisitor pathVisitor;
private final Invoker invoker;
private final CachingResolver resolver;
public PathPredicateEvaluationVisitor(boolean lax, PathEvaluationVisitor pathVisitor, Invoker invoker, CachingResolver resolver)
{
this.lax = lax;
this.pathVisitor = requireNonNull(pathVisitor, "pathVisitor is null");
this.invoker = requireNonNull(invoker, "invoker is null");
this.resolver = requireNonNull(resolver, "resolver is null");
}
@Override
protected Boolean visitIrPathNode(IrPathNode node, PathEvaluationContext context)
{
throw new IllegalStateException("JSON predicate evaluating visitor applied to a non-predicate node " + node.getClass().getSimpleName());
}
@Override
protected Boolean visitIrPredicate(IrPredicate node, PathEvaluationContext context)
{
throw new UnsupportedOperationException("JSON predicate evaluating visitor not implemented for " + node.getClass().getSimpleName());
}
@Override
protected Boolean visitIrComparisonPredicate(IrComparisonPredicate node, PathEvaluationContext context)
{
List