All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.trino.json.CachingResolver Maven / Gradle / Ivy

There is a newer version: 465
Show newest version
/*
 * 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.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import io.trino.cache.NonEvictableCache;
import io.trino.json.ir.IrPathNode;
import io.trino.metadata.Metadata;
import io.trino.metadata.OperatorNotFoundException;
import io.trino.metadata.ResolvedFunction;
import io.trino.spi.function.BoundSignature;
import io.trino.spi.function.OperatorType;
import io.trino.spi.type.Type;
import io.trino.spi.type.TypeManager;
import io.trino.type.TypeCoercion;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

import static com.google.common.base.Preconditions.checkState;
import static io.trino.cache.SafeCaches.buildNonEvictableCache;
import static io.trino.json.CachingResolver.ResolvedOperatorAndCoercions.RESOLUTION_ERROR;
import static io.trino.json.CachingResolver.ResolvedOperatorAndCoercions.operators;
import static java.util.Objects.requireNonNull;

/**
 * A resolver providing coercions and binary operators used for JSON path evaluation,
 * based on the operation type and the input types.
 * 

* It is instantiated per-driver, and caches the resolved operators and coercions. * Caching is applied to IrArithmeticBinary and IrComparisonPredicate path nodes. * Its purpose is to avoid resolving operators and coercions on a per-row basis, assuming * that the input types to the JSON path operations repeat across rows. *

* If an operator or a component coercion cannot be resolved for certain input types, * it is cached as RESOLUTION_ERROR. It depends on the caller to handle this condition. */ public class CachingResolver { private static final int MAX_CACHE_SIZE = 1000; private final Metadata metadata; private final TypeCoercion typeCoercion; private final NonEvictableCache operators = buildNonEvictableCache(CacheBuilder.newBuilder().maximumSize(MAX_CACHE_SIZE)); public CachingResolver(Metadata metadata, TypeManager typeManager) { requireNonNull(metadata, "metadata is null"); requireNonNull(typeManager, "typeManager is null"); this.metadata = metadata; this.typeCoercion = new TypeCoercion(typeManager::getType); } public ResolvedOperatorAndCoercions getOperators(IrPathNode node, OperatorType operatorType, Type leftType, Type rightType) { try { return operators .get(new NodeAndTypes(IrPathNodeRef.of(node), leftType, rightType), () -> resolveOperators(operatorType, leftType, rightType)); } catch (ExecutionException e) { throw new RuntimeException(e); } } private ResolvedOperatorAndCoercions resolveOperators(OperatorType operatorType, Type leftType, Type rightType) { ResolvedFunction operator; try { operator = metadata.resolveOperator(operatorType, ImmutableList.of(leftType, rightType)); } catch (OperatorNotFoundException e) { return RESOLUTION_ERROR; } BoundSignature signature = operator.getSignature(); Optional leftCast = Optional.empty(); if (!signature.getArgumentTypes().get(0).equals(leftType) && !typeCoercion.isTypeOnlyCoercion(leftType, signature.getArgumentTypes().get(0))) { try { leftCast = Optional.of(metadata.getCoercion(leftType, signature.getArgumentTypes().get(0))); } catch (OperatorNotFoundException e) { return RESOLUTION_ERROR; } } Optional rightCast = Optional.empty(); if (!signature.getArgumentTypes().get(1).equals(rightType) && !typeCoercion.isTypeOnlyCoercion(rightType, signature.getArgumentTypes().get(1))) { try { rightCast = Optional.of(metadata.getCoercion(rightType, signature.getArgumentTypes().get(1))); } catch (OperatorNotFoundException e) { return RESOLUTION_ERROR; } } return operators(operator, leftCast, rightCast); } private static class NodeAndTypes { private final IrPathNodeRef node; private final Type leftType; private final Type rightType; public NodeAndTypes(IrPathNodeRef node, Type leftType, Type rightType) { this.node = node; this.leftType = leftType; this.rightType = rightType; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } NodeAndTypes that = (NodeAndTypes) o; return Objects.equals(node, that.node) && Objects.equals(leftType, that.leftType) && Objects.equals(rightType, that.rightType); } @Override public int hashCode() { return Objects.hash(node, leftType, rightType); } } public static class ResolvedOperatorAndCoercions { public static final ResolvedOperatorAndCoercions RESOLUTION_ERROR = new ResolvedOperatorAndCoercions(null, Optional.empty(), Optional.empty()); private final ResolvedFunction operator; private final Optional leftCoercion; private final Optional rightCoercion; public static ResolvedOperatorAndCoercions operators(ResolvedFunction operator, Optional leftCoercion, Optional rightCoercion) { return new ResolvedOperatorAndCoercions(requireNonNull(operator, "operator is null"), leftCoercion, rightCoercion); } private ResolvedOperatorAndCoercions(ResolvedFunction operator, Optional leftCoercion, Optional rightCoercion) { this.operator = operator; this.leftCoercion = requireNonNull(leftCoercion, "leftCoercion is null"); this.rightCoercion = requireNonNull(rightCoercion, "rightCoercion is null"); } public ResolvedFunction getOperator() { checkState(this != RESOLUTION_ERROR, "accessing operator on RESOLUTION_ERROR"); return operator; } public Optional getLeftCoercion() { checkState(this != RESOLUTION_ERROR, "accessing coercion on RESOLUTION_ERROR"); return leftCoercion; } public Optional getRightCoercion() { checkState(this != RESOLUTION_ERROR, "accessing coercion on RESOLUTION_ERROR"); return rightCoercion; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy