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

io.trino.sql.planner.TranslationMap 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.sql.planner;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.slice.Slices;
import io.trino.Session;
import io.trino.json.ir.IrJsonPath;
import io.trino.metadata.ResolvedFunction;
import io.trino.operator.scalar.FormatFunction;
import io.trino.operator.scalar.TryFunction;
import io.trino.plugin.base.util.JsonTypeUtil;
import io.trino.spi.function.OperatorType;
import io.trino.spi.type.ArrayType;
import io.trino.spi.type.DecimalParseResult;
import io.trino.spi.type.DecimalType;
import io.trino.spi.type.Decimals;
import io.trino.spi.type.RowType;
import io.trino.spi.type.TimeType;
import io.trino.spi.type.TimeWithTimeZoneType;
import io.trino.spi.type.TimestampType;
import io.trino.spi.type.TimestampWithTimeZoneType;
import io.trino.spi.type.Type;
import io.trino.spi.type.TypeId;
import io.trino.sql.InterpretedFunctionInvoker;
import io.trino.sql.PlannerContext;
import io.trino.sql.analyzer.Analysis;
import io.trino.sql.analyzer.ResolvedField;
import io.trino.sql.analyzer.Scope;
import io.trino.sql.analyzer.TypeSignatureTranslator;
import io.trino.sql.ir.Between;
import io.trino.sql.ir.Call;
import io.trino.sql.ir.Case;
import io.trino.sql.ir.Coalesce;
import io.trino.sql.ir.Comparison;
import io.trino.sql.ir.Constant;
import io.trino.sql.ir.FieldReference;
import io.trino.sql.ir.In;
import io.trino.sql.ir.IsNull;
import io.trino.sql.ir.Lambda;
import io.trino.sql.ir.Logical;
import io.trino.sql.ir.NullIf;
import io.trino.sql.ir.Reference;
import io.trino.sql.ir.Switch;
import io.trino.sql.tree.ArithmeticBinaryExpression;
import io.trino.sql.tree.ArithmeticUnaryExpression;
import io.trino.sql.tree.Array;
import io.trino.sql.tree.AtTimeZone;
import io.trino.sql.tree.BetweenPredicate;
import io.trino.sql.tree.BinaryLiteral;
import io.trino.sql.tree.BooleanLiteral;
import io.trino.sql.tree.Cast;
import io.trino.sql.tree.CoalesceExpression;
import io.trino.sql.tree.ComparisonExpression;
import io.trino.sql.tree.CurrentCatalog;
import io.trino.sql.tree.CurrentDate;
import io.trino.sql.tree.CurrentPath;
import io.trino.sql.tree.CurrentSchema;
import io.trino.sql.tree.CurrentTime;
import io.trino.sql.tree.CurrentTimestamp;
import io.trino.sql.tree.CurrentUser;
import io.trino.sql.tree.DecimalLiteral;
import io.trino.sql.tree.DereferenceExpression;
import io.trino.sql.tree.DoubleLiteral;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Extract;
import io.trino.sql.tree.Format;
import io.trino.sql.tree.FunctionCall;
import io.trino.sql.tree.GenericLiteral;
import io.trino.sql.tree.Identifier;
import io.trino.sql.tree.IfExpression;
import io.trino.sql.tree.InListExpression;
import io.trino.sql.tree.InPredicate;
import io.trino.sql.tree.IntervalLiteral;
import io.trino.sql.tree.IsNotNullPredicate;
import io.trino.sql.tree.IsNullPredicate;
import io.trino.sql.tree.JsonArray;
import io.trino.sql.tree.JsonArrayElement;
import io.trino.sql.tree.JsonExists;
import io.trino.sql.tree.JsonObject;
import io.trino.sql.tree.JsonObjectMember;
import io.trino.sql.tree.JsonPathParameter;
import io.trino.sql.tree.JsonQuery;
import io.trino.sql.tree.JsonValue;
import io.trino.sql.tree.LambdaArgumentDeclaration;
import io.trino.sql.tree.LambdaExpression;
import io.trino.sql.tree.LikePredicate;
import io.trino.sql.tree.LocalTime;
import io.trino.sql.tree.LocalTimestamp;
import io.trino.sql.tree.LogicalExpression;
import io.trino.sql.tree.LongLiteral;
import io.trino.sql.tree.NodeRef;
import io.trino.sql.tree.NotExpression;
import io.trino.sql.tree.NullIfExpression;
import io.trino.sql.tree.NullLiteral;
import io.trino.sql.tree.Parameter;
import io.trino.sql.tree.Row;
import io.trino.sql.tree.SearchedCaseExpression;
import io.trino.sql.tree.SimpleCaseExpression;
import io.trino.sql.tree.StringLiteral;
import io.trino.sql.tree.SubscriptExpression;
import io.trino.sql.tree.Trim;
import io.trino.sql.tree.TryExpression;
import io.trino.type.FunctionType;
import io.trino.type.IntervalDayTimeType;
import io.trino.type.IntervalYearMonthType;
import io.trino.type.JsonPath2016Type;
import io.trino.type.UnknownType;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static io.airlift.slice.Slices.utf8Slice;
import static io.trino.metadata.GlobalFunctionCatalog.builtinFunctionName;
import static io.trino.spi.type.BooleanType.BOOLEAN;
import static io.trino.spi.type.DoubleType.DOUBLE;
import static io.trino.spi.type.TimeWithTimeZoneType.createTimeWithTimeZoneType;
import static io.trino.spi.type.TimestampWithTimeZoneType.createTimestampWithTimeZoneType;
import static io.trino.spi.type.TinyintType.TINYINT;
import static io.trino.spi.type.VarcharType.VARCHAR;
import static io.trino.sql.analyzer.ExpressionAnalyzer.JSON_NO_PARAMETERS_ROW_TYPE;
import static io.trino.sql.ir.Booleans.FALSE;
import static io.trino.sql.ir.Booleans.TRUE;
import static io.trino.sql.ir.Comparison.Operator.EQUAL;
import static io.trino.sql.ir.Comparison.Operator.GREATER_THAN;
import static io.trino.sql.ir.Comparison.Operator.GREATER_THAN_OR_EQUAL;
import static io.trino.sql.ir.Comparison.Operator.IDENTICAL;
import static io.trino.sql.ir.Comparison.Operator.LESS_THAN;
import static io.trino.sql.ir.Comparison.Operator.LESS_THAN_OR_EQUAL;
import static io.trino.sql.ir.Comparison.Operator.NOT_EQUAL;
import static io.trino.sql.ir.IrExpressions.ifExpression;
import static io.trino.sql.ir.IrExpressions.not;
import static io.trino.sql.planner.ScopeAware.scopeAwareKey;
import static io.trino.sql.tree.JsonQuery.EmptyOrErrorBehavior.ERROR;
import static io.trino.sql.tree.JsonQuery.QuotesBehavior.KEEP;
import static io.trino.sql.tree.JsonQuery.QuotesBehavior.OMIT;
import static io.trino.type.JsonType.JSON;
import static io.trino.type.LikeFunctions.LIKE_FUNCTION_NAME;
import static io.trino.type.LikeFunctions.LIKE_PATTERN_FUNCTION_NAME;
import static io.trino.type.LikePatternType.LIKE_PATTERN;
import static io.trino.util.DateTimeUtils.parseDayTimeInterval;
import static io.trino.util.DateTimeUtils.parseYearMonthInterval;
import static java.lang.Math.toIntExact;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
 * Keeps mappings of fields and AST expressions to symbols in the current plan within query boundary.
 * 

* AST and IR expressions use the same class hierarchy ({@link Expression}, * but differ in the following ways: *

    *
  • AST expressions contain Identifiers, while IR expressions contain SymbolReferences
  • *
  • FunctionCalls in AST expressions are SQL function names. In IR expressions, they contain an encoded name representing a resolved function
  • *
*/ public class TranslationMap { // all expressions are rewritten in terms of fields declared by this relation plan private final Scope scope; private final Analysis analysis; private final Map, Symbol> lambdaArguments; private final Optional outerContext; private final Session session; private final PlannerContext plannerContext; // current mappings of underlying field -> symbol for translating direct field references private final Symbol[] fieldSymbols; // current mappings of sub-expressions -> symbol private final Map, Symbol> astToSymbols; private final Map, Symbol> substitutions; public TranslationMap(Optional outerContext, Scope scope, Analysis analysis, Map, Symbol> lambdaArguments, List fieldSymbols, Session session, PlannerContext plannerContext) { this(outerContext, scope, analysis, lambdaArguments, fieldSymbols.toArray(new Symbol[0]).clone(), ImmutableMap.of(), ImmutableMap.of(), session, plannerContext); } public TranslationMap(Optional outerContext, Scope scope, Analysis analysis, Map, Symbol> lambdaArguments, List fieldSymbols, Map, Symbol> astToSymbols, Session session, PlannerContext plannerContext) { this(outerContext, scope, analysis, lambdaArguments, fieldSymbols.toArray(new Symbol[0]), astToSymbols, ImmutableMap.of(), session, plannerContext); } public TranslationMap( Optional outerContext, Scope scope, Analysis analysis, Map, Symbol> lambdaArguments, Symbol[] fieldSymbols, Map, Symbol> astToSymbols, Map, Symbol> substitutions, Session session, PlannerContext plannerContext) { this.outerContext = requireNonNull(outerContext, "outerContext is null"); this.scope = requireNonNull(scope, "scope is null"); this.analysis = requireNonNull(analysis, "analysis is null"); this.lambdaArguments = requireNonNull(lambdaArguments, "lambdaArguments is null"); this.session = requireNonNull(session, "session is null"); this.plannerContext = requireNonNull(plannerContext, "plannerContext is null"); this.substitutions = ImmutableMap.copyOf(substitutions); requireNonNull(fieldSymbols, "fieldSymbols is null"); this.fieldSymbols = fieldSymbols.clone(); requireNonNull(astToSymbols, "astToSymbols is null"); this.astToSymbols = ImmutableMap.copyOf(astToSymbols); checkArgument(scope.getLocalScopeFieldCount() == fieldSymbols.length, "scope: %s, fields mappings: %s", scope.getRelationType().getAllFieldCount(), fieldSymbols.length); } public TranslationMap withScope(Scope scope, List fields) { return new TranslationMap(outerContext, scope, analysis, lambdaArguments, fields.toArray(new Symbol[0]), astToSymbols, substitutions, session, plannerContext); } public TranslationMap withNewMappings(Map, Symbol> mappings, List fields) { return new TranslationMap(outerContext, scope, analysis, lambdaArguments, fields, mappings, session, plannerContext); } public TranslationMap withAdditionalMappings(Map, Symbol> mappings) { Map, Symbol> newMappings = new HashMap<>(); newMappings.putAll(this.astToSymbols); newMappings.putAll(mappings); return new TranslationMap(outerContext, scope, analysis, lambdaArguments, fieldSymbols, newMappings, substitutions, session, plannerContext); } public TranslationMap withAdditionalIdentityMappings(Map, Symbol> mappings) { Map, Symbol> newMappings = new HashMap<>(); newMappings.putAll(this.substitutions); newMappings.putAll(mappings); return new TranslationMap(outerContext, scope, analysis, lambdaArguments, fieldSymbols, astToSymbols, newMappings, session, plannerContext); } public List getFieldSymbols() { return Collections.unmodifiableList(Arrays.asList(fieldSymbols)); } public Map, Symbol> getMappings() { return astToSymbols; } public Analysis getAnalysis() { return analysis; } public boolean canTranslate(Expression expression) { if (astToSymbols.containsKey(scopeAwareKey(expression, analysis, scope)) || substitutions.containsKey(NodeRef.of(expression)) || expression instanceof io.trino.sql.tree.FieldReference) { return true; } if (analysis.isColumnReference(expression)) { ResolvedField field = analysis.getColumnReferenceFields().get(NodeRef.of(expression)); return scope.isLocalScope(field.getScope()); } return false; } public io.trino.sql.ir.Expression rewrite(Expression root) { verify(analysis.isAnalyzed(root), "Expression is not analyzed (%s): %s", root.getClass().getName(), root); return translate(root, true); } private io.trino.sql.ir.Expression translateExpression(Expression expression) { return translate(expression, false); } private io.trino.sql.ir.Expression translate(Expression expr, boolean isRoot) { Optional mapped = tryGetMapping(expr); io.trino.sql.ir.Expression result; if (mapped.isPresent()) { result = mapped.get(); } else { result = switch (expr) { case io.trino.sql.tree.FieldReference expression -> translate(expression); case Identifier expression -> translate(expression); case FunctionCall expression -> translate(expression); case DereferenceExpression expression -> translate(expression); case Array expression -> translate(expression); case CurrentCatalog expression -> translate(expression); case CurrentSchema expression -> translate(expression); case CurrentPath expression -> translate(expression); case CurrentUser expression -> translate(expression); case CurrentDate expression -> translate(expression); case CurrentTime expression -> translate(expression); case CurrentTimestamp expression -> translate(expression); case LocalTime expression -> translate(expression); case LocalTimestamp expression -> translate(expression); case Extract expression -> translate(expression); case AtTimeZone expression -> translate(expression); case Format expression -> translate(expression); case TryExpression expression -> translate(expression); case LikePredicate expression -> translate(expression); case Trim expression -> translate(expression); case SubscriptExpression expression -> translate(expression); case LambdaExpression expression -> translate(expression); case Parameter expression -> translate(expression); case JsonExists expression -> translate(expression); case JsonValue expression -> translate(expression); case JsonQuery expression -> translate(expression); case JsonObject expression -> translate(expression); case JsonArray expression -> translate(expression); case LongLiteral expression -> translate(expression); case DoubleLiteral expression -> translate(expression); case StringLiteral expression -> translate(expression); case BooleanLiteral expression -> translate(expression); case DecimalLiteral expression -> translate(expression); case GenericLiteral expression -> translate(expression); case BinaryLiteral expression -> translate(expression); case IntervalLiteral expression -> translate(expression); case ArithmeticBinaryExpression expression -> translate(expression); case ArithmeticUnaryExpression expression -> translate(expression); case ComparisonExpression expression -> translate(expression); case Cast expression -> translate(expression); case Row expression -> translate(expression); case NotExpression expression -> translate(expression); case LogicalExpression expression -> translate(expression); case NullLiteral expression -> new Constant(UnknownType.UNKNOWN, null); case CoalesceExpression expression -> translate(expression); case IsNullPredicate expression -> translate(expression); case IsNotNullPredicate expression -> translate(expression); case BetweenPredicate expression -> translate(expression); case IfExpression expression -> translate(expression); case InPredicate expression -> translate(expression); case SimpleCaseExpression expression -> translate(expression); case SearchedCaseExpression expression -> translate(expression); case NullIfExpression expression -> translate(expression); default -> throw new IllegalArgumentException("Unsupported expression (%s): %s".formatted(expr.getClass().getName(), expr)); }; } // Don't add a coercion for the top-level expression. That depends on the context // the expression is used and it's the responsibility of the caller. return isRoot ? result : QueryPlanner.coerceIfNecessary(analysis, expr, result); } private io.trino.sql.ir.Expression translate(NullIfExpression expression) { return new NullIf( translateExpression(expression.getFirst()), translateExpression(expression.getSecond())); } private io.trino.sql.ir.Expression translate(ArithmeticUnaryExpression expression) { return switch (expression.getSign()) { case PLUS -> translateExpression(expression.getValue()); case MINUS -> new io.trino.sql.ir.Call( plannerContext.getMetadata().resolveOperator(OperatorType.NEGATION, ImmutableList.of(analysis.getType(expression.getValue()))), ImmutableList.of(translateExpression(expression.getValue()))); }; } private io.trino.sql.ir.Expression translate(IntervalLiteral expression) { Type type = analysis.getType(expression); return new Constant( type, switch (type) { case IntervalYearMonthType t -> expression.getSign().multiplier() * parseYearMonthInterval(expression.getValue(), expression.getStartField(), expression.getEndField()); case IntervalDayTimeType t -> expression.getSign().multiplier() * parseDayTimeInterval(expression.getValue(), expression.getStartField(), expression.getEndField()); default -> throw new IllegalArgumentException("Unexpected type for IntervalLiteral: %s" + type); }); } private io.trino.sql.ir.Expression translate(SearchedCaseExpression expression) { return new Case( expression.getWhenClauses().stream() .map(clause -> new io.trino.sql.ir.WhenClause( translateExpression(clause.getOperand()), translateExpression(clause.getResult()))) .collect(toImmutableList()), expression.getDefaultValue() .map(this::translateExpression) .orElse(new Constant(analysis.getType(expression), null))); } private io.trino.sql.ir.Expression translate(SimpleCaseExpression expression) { return new Switch( translateExpression(expression.getOperand()), expression.getWhenClauses().stream() .map(clause -> new io.trino.sql.ir.WhenClause( translateExpression(clause.getOperand()), translateExpression(clause.getResult()))) .collect(toImmutableList()), expression.getDefaultValue() .map(this::translateExpression) .orElse(new Constant(analysis.getType(expression), null))); } private io.trino.sql.ir.Expression translate(InPredicate expression) { return new In( translateExpression(expression.getValue()), ((InListExpression) expression.getValueList()).getValues().stream() .map(this::translateExpression) .collect(toImmutableList())); } private io.trino.sql.ir.Expression translate(IfExpression expression) { if (expression.getFalseValue().isPresent()) { return ifExpression( translateExpression(expression.getCondition()), translateExpression(expression.getTrueValue()), translateExpression(expression.getFalseValue().get())); } return ifExpression( translateExpression(expression.getCondition()), translateExpression(expression.getTrueValue())); } private io.trino.sql.ir.Expression translate(BinaryLiteral expression) { return new Constant(analysis.getType(expression), Slices.wrappedBuffer(expression.getValue())); } private io.trino.sql.ir.Expression translate(BetweenPredicate expression) { return new Between( translateExpression(expression.getValue()), translateExpression(expression.getMin()), translateExpression(expression.getMax())); } private io.trino.sql.ir.Expression translate(IsNullPredicate expression) { return new IsNull(translateExpression(expression.getValue())); } private io.trino.sql.ir.Expression translate(IsNotNullPredicate expression) { return not( plannerContext.getMetadata(), new IsNull( translateExpression(expression.getValue()))); } private io.trino.sql.ir.Expression translate(CoalesceExpression expression) { return new Coalesce(expression.getOperands().stream() .map(this::translateExpression) .collect(toImmutableList())); } private io.trino.sql.ir.Expression translate(GenericLiteral expression) { // TODO: record the parsed values in the analyzer and pull them out here Type type = analysis.getType(expression); if (type.equals(JSON)) { return new Constant(type, JsonTypeUtil.jsonParse(utf8Slice(expression.getValue()))); } InterpretedFunctionInvoker functionInvoker = new InterpretedFunctionInvoker(plannerContext.getFunctionManager()); ResolvedFunction resolvedFunction = plannerContext.getMetadata().getCoercion(VARCHAR, type); Object value = functionInvoker.invoke(resolvedFunction, session.toConnectorSession(), ImmutableList.of(utf8Slice(expression.getValue()))); return new Constant(type, value); } private io.trino.sql.ir.Expression translate(DecimalLiteral expression) { DecimalType type = (DecimalType) analysis.getType(expression); // TODO: record the parsed values in the analyzer and pull them out here DecimalParseResult parsed = Decimals.parse(expression.getValue()); checkState(parsed.getType().equals(type)); return new Constant(type, parsed.getObject()); } private io.trino.sql.ir.Expression translate(LogicalExpression expression) { return new Logical( switch (expression.getOperator()) { case AND -> Logical.Operator.AND; case OR -> Logical.Operator.OR; }, expression.getTerms().stream() .map(this::translateExpression) .collect(toImmutableList())); } private io.trino.sql.ir.Expression translate(BooleanLiteral expression) { if (expression.equals(BooleanLiteral.TRUE_LITERAL)) { return TRUE; } if (expression.equals(BooleanLiteral.FALSE_LITERAL)) { return FALSE; } throw new IllegalArgumentException("Unknown boolean literal: " + expression); } private io.trino.sql.ir.Expression translate(NotExpression expression) { return not(plannerContext.getMetadata(), translateExpression(expression.getValue())); } private io.trino.sql.ir.Expression translate(Row expression) { return new io.trino.sql.ir.Row(expression.getItems().stream() .map(this::translateExpression) .collect(toImmutableList())); } private io.trino.sql.ir.Expression translate(ComparisonExpression expression) { io.trino.sql.ir.Expression left = translateExpression(expression.getLeft()); io.trino.sql.ir.Expression right = translateExpression(expression.getRight()); return switch (expression.getOperator()) { case EQUAL -> new Comparison(EQUAL, left, right); case NOT_EQUAL -> new Comparison(NOT_EQUAL, left, right); case LESS_THAN -> new Comparison(LESS_THAN, left, right); case LESS_THAN_OR_EQUAL -> new Comparison(LESS_THAN_OR_EQUAL, left, right); case GREATER_THAN -> new Comparison(GREATER_THAN, left, right); case GREATER_THAN_OR_EQUAL -> new Comparison(GREATER_THAN_OR_EQUAL, left, right); case IS_DISTINCT_FROM -> not(plannerContext.getMetadata(), new Comparison(IDENTICAL, left, right)); }; } private io.trino.sql.ir.Expression translate(Cast expression) { if (expression.isSafe()) { return new Call( plannerContext.getMetadata().getCoercion( builtinFunctionName("$try_cast"), analysis.getType(expression.getExpression()), analysis.getType(expression)), ImmutableList.of(translateExpression(expression.getExpression()))); } return new io.trino.sql.ir.Cast( translateExpression(expression.getExpression()), analysis.getType(expression)); } private io.trino.sql.ir.Expression translate(DoubleLiteral expression) { return new Constant(DOUBLE, expression.getValue()); } private io.trino.sql.ir.Expression translate(ArithmeticBinaryExpression expression) { OperatorType operatorType = switch (expression.getOperator()) { case ADD -> OperatorType.ADD; case SUBTRACT -> OperatorType.SUBTRACT; case MULTIPLY -> OperatorType.MULTIPLY; case DIVIDE -> OperatorType.DIVIDE; case MODULUS -> OperatorType.MODULUS; }; return new Call( plannerContext.getMetadata().resolveOperator(operatorType, ImmutableList.of(getCoercedType(expression.getLeft()), getCoercedType(expression.getRight()))), ImmutableList.of( translateExpression(expression.getLeft()), translateExpression(expression.getRight()))); } private Type getCoercedType(Expression left) { Type leftType = analysis.getCoercion(left); if (leftType == null) { leftType = analysis.getType(left); } return leftType; } private io.trino.sql.ir.Expression translate(StringLiteral expression) { return new Constant(analysis.getType(expression), utf8Slice(expression.getValue())); } private io.trino.sql.ir.Expression translate(LongLiteral expression) { return new Constant(analysis.getType(expression), expression.getParsedValue()); } private io.trino.sql.ir.Expression translate(io.trino.sql.tree.FieldReference expression) { return getSymbolForColumn(expression) .map(Symbol::toSymbolReference) .orElseThrow(() -> new IllegalStateException(format("No symbol mapping for node '%s' (%s)", expression, expression.getFieldIndex()))); } private io.trino.sql.ir.Expression translate(Identifier expression) { LambdaArgumentDeclaration referencedLambdaArgumentDeclaration = analysis.getLambdaArgumentReference(expression); if (referencedLambdaArgumentDeclaration != null) { Symbol symbol = lambdaArguments.get(NodeRef.of(referencedLambdaArgumentDeclaration)); return symbol.toSymbolReference(); } return getSymbolForColumn(expression) .map(Symbol::toSymbolReference) .get(); } private io.trino.sql.ir.Expression translate(FunctionCall expression) { if (analysis.isPatternNavigationFunction(expression)) { return translate(expression.getArguments().getFirst(), false); } Optional resolvedFunction = analysis.getResolvedFunction(expression); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", expression); return new Call( resolvedFunction.get(), expression.getArguments().stream() .map(this::translateExpression) .collect(toImmutableList())); } private io.trino.sql.ir.Expression translate(DereferenceExpression expression) { if (analysis.isColumnReference(expression)) { return getSymbolForColumn(expression) .map(Symbol::toSymbolReference) .orElseThrow(() -> new IllegalStateException(format("No mapping for %s", expression))); } RowType rowType = (RowType) analysis.getType(expression.getBase()); String fieldName = expression.getField().orElseThrow().getValue(); List fields = rowType.getFields(); int index = -1; for (int i = 0; i < fields.size(); i++) { RowType.Field field = fields.get(i); if (field.getName().isPresent() && field.getName().get().equalsIgnoreCase(fieldName)) { checkArgument(index < 0, "Ambiguous field %s in type %s", field, rowType.getDisplayName()); index = i; } } checkState(index >= 0, "could not find field name: %s", fieldName); return new FieldReference(translateExpression(expression.getBase()), index); } private io.trino.sql.ir.Expression translate(Array expression) { List values = expression.getValues().stream() .map(this::translateExpression) .collect(toImmutableList()); Type type = analysis.getType(expression); return new io.trino.sql.ir.Array(((ArrayType) type).getElementType(), values); } private io.trino.sql.ir.Expression translate(CurrentCatalog unused) { return new Call( plannerContext.getMetadata() .resolveBuiltinFunction("$current_catalog", ImmutableList.of()), ImmutableList.of()); } private io.trino.sql.ir.Expression translate(CurrentSchema unused) { return new Call( plannerContext.getMetadata() .resolveBuiltinFunction("$current_schema", ImmutableList.of()), ImmutableList.of()); } private io.trino.sql.ir.Expression translate(CurrentPath unused) { return new Call( plannerContext.getMetadata() .resolveBuiltinFunction("$current_path", ImmutableList.of()), ImmutableList.of()); } private io.trino.sql.ir.Expression translate(CurrentUser unused) { return new Call( plannerContext.getMetadata() .resolveBuiltinFunction("$current_user", ImmutableList.of()), ImmutableList.of()); } private io.trino.sql.ir.Expression translate(CurrentDate unused) { return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("current_date") .build(); } private io.trino.sql.ir.Expression translate(CurrentTime node) { return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$current_time") .setArguments( ImmutableList.of(analysis.getType(node)), ImmutableList.of(new Constant(analysis.getType(node), null))) .build(); } private io.trino.sql.ir.Expression translate(CurrentTimestamp node) { return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$current_timestamp") .setArguments( ImmutableList.of(analysis.getType(node)), ImmutableList.of(new Constant(analysis.getType(node), null))) .build(); } private io.trino.sql.ir.Expression translate(LocalTime node) { return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$localtime") .setArguments( ImmutableList.of(analysis.getType(node)), ImmutableList.of(new Constant(analysis.getType(node), null))) .build(); } private io.trino.sql.ir.Expression translate(LocalTimestamp node) { return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$localtimestamp") .setArguments( ImmutableList.of(analysis.getType(node)), ImmutableList.of(new Constant(analysis.getType(node), null))) .build(); } private io.trino.sql.ir.Expression translate(Extract node) { io.trino.sql.ir.Expression value = translateExpression(node.getExpression()); Type type = analysis.getType(node.getExpression()); return switch (node.getField()) { case YEAR -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("year") .addArgument(type, value) .build(); case QUARTER -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("quarter") .addArgument(type, value) .build(); case MONTH -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("month") .addArgument(type, value) .build(); case WEEK -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("week") .addArgument(type, value) .build(); case DAY, DAY_OF_MONTH -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("day") .addArgument(type, value) .build(); case DAY_OF_WEEK, DOW -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("day_of_week") .addArgument(type, value) .build(); case DAY_OF_YEAR, DOY -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("day_of_year") .addArgument(type, value) .build(); case YEAR_OF_WEEK, YOW -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("year_of_week") .addArgument(type, value) .build(); case HOUR -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("hour") .addArgument(type, value) .build(); case MINUTE -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("minute") .addArgument(type, value) .build(); case SECOND -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("second") .addArgument(type, value) .build(); case TIMEZONE_MINUTE -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("timezone_minute") .addArgument(type, value) .build(); case TIMEZONE_HOUR -> BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("timezone_hour") .addArgument(type, value) .build(); }; } private io.trino.sql.ir.Expression translate(AtTimeZone node) { Type valueType = analysis.getType(node.getValue()); io.trino.sql.ir.Expression value = translateExpression(node.getValue()); Type timeZoneType = analysis.getType(node.getTimeZone()); io.trino.sql.ir.Expression timeZone = translateExpression(node.getTimeZone()); Call call; if (valueType instanceof TimeType type) { call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$at_timezone") .addArgument(createTimeWithTimeZoneType(type.getPrecision()), new io.trino.sql.ir.Cast(value, createTimeWithTimeZoneType(type.getPrecision()))) .addArgument(timeZoneType, timeZone) .build(); } else if (valueType instanceof TimeWithTimeZoneType) { call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("$at_timezone") .addArgument(valueType, value) .addArgument(timeZoneType, timeZone) .build(); } else if (valueType instanceof TimestampType type) { call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("at_timezone") .addArgument(createTimestampWithTimeZoneType(type.getPrecision()), new io.trino.sql.ir.Cast(value, createTimestampWithTimeZoneType(type.getPrecision()))) .addArgument(timeZoneType, timeZone) .build(); } else if (valueType instanceof TimestampWithTimeZoneType) { call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName("at_timezone") .addArgument(valueType, value) .addArgument(timeZoneType, timeZone) .build(); } else { throw new IllegalArgumentException("Unexpected type: " + valueType); } return call; } private io.trino.sql.ir.Expression translate(Format node) { List arguments = node.getArguments().stream() .map(this::translateExpression) .collect(toImmutableList()); List argumentTypes = node.getArguments().stream() .map(analysis::getType) .collect(toImmutableList()); Call call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName(FormatFunction.NAME) .addArgument(VARCHAR, new io.trino.sql.ir.Cast(arguments.get(0), VARCHAR)) .addArgument(RowType.anonymous(argumentTypes.subList(1, arguments.size())), new io.trino.sql.ir.Row(arguments.subList(1, arguments.size()))) .build(); return call; } private io.trino.sql.ir.Expression translate(TryExpression node) { Type type = analysis.getType(node); io.trino.sql.ir.Expression expression = translateExpression(node.getInnerExpression()); return BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName(TryFunction.NAME) .addArgument(new FunctionType(ImmutableList.of(), type), new Lambda(ImmutableList.of(), expression)) .build(); } private io.trino.sql.ir.Expression translate(LikePredicate node) { io.trino.sql.ir.Expression value = translateExpression(node.getValue()); io.trino.sql.ir.Expression pattern = translateExpression(node.getPattern()); Optional escape = node.getEscape().map(this::translateExpression); Call patternCall; if (escape.isPresent()) { patternCall = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName(LIKE_PATTERN_FUNCTION_NAME) .addArgument(VARCHAR, new io.trino.sql.ir.Cast(pattern, VARCHAR)) .addArgument(VARCHAR, new io.trino.sql.ir.Cast(escape.get(), VARCHAR)) .build(); } else { patternCall = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName(LIKE_PATTERN_FUNCTION_NAME) .addArgument(VARCHAR, new io.trino.sql.ir.Cast(pattern, VARCHAR)) .build(); } Call call = BuiltinFunctionCallBuilder.resolve(plannerContext.getMetadata()) .setName(LIKE_FUNCTION_NAME) .addArgument(value.type(), value) .addArgument(LIKE_PATTERN, patternCall) .build(); return call; } private io.trino.sql.ir.Expression translate(Trim node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); ImmutableList.Builder arguments = ImmutableList.builder(); arguments.add(translateExpression(node.getTrimSource())); node.getTrimCharacter() .map(this::translateExpression) .ifPresent(arguments::add); return new Call(resolvedFunction.get(), arguments.build()); } private io.trino.sql.ir.Expression translate(SubscriptExpression node) { Type baseType = analysis.getType(node.getBase()); if (baseType instanceof RowType rowType) { // Do not rewrite subscript index into symbol. Row subscript index is required to be a literal. io.trino.sql.ir.Expression rewrittenBase = translateExpression(node.getBase()); LongLiteral index = (LongLiteral) node.getIndex(); return new FieldReference( rewrittenBase, toIntExact(index.getParsedValue() - 1)); } ResolvedFunction operator = plannerContext.getMetadata() .resolveOperator(OperatorType.SUBSCRIPT, ImmutableList.of(getCoercedType(node.getBase()), getCoercedType(node.getIndex()))); return new Call( operator, ImmutableList.of( new io.trino.sql.ir.Cast(translateExpression(node.getBase()), operator.signature().getArgumentType(0)), new io.trino.sql.ir.Cast(translateExpression(node.getIndex()), operator.signature().getArgumentType(1)))); } private io.trino.sql.ir.Expression translate(LambdaExpression node) { checkState(analysis.getCoercion(node) == null, "cannot coerce a lambda expression"); ImmutableList.Builder newArguments = ImmutableList.builder(); for (LambdaArgumentDeclaration argument : node.getArguments()) { newArguments.add(lambdaArguments.get(NodeRef.of(argument))); } io.trino.sql.ir.Expression rewrittenBody = translateExpression(node.getBody()); return new Lambda(newArguments.build(), rewrittenBody); } private io.trino.sql.ir.Expression translate(Parameter node) { checkState(analysis.getParameters().size() > node.getId(), "Too few parameter values"); return translateExpression(analysis.getParameters().get(NodeRef.of(node))); } private io.trino.sql.ir.Expression translate(JsonExists node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); // apply the input function to the input expression Constant failOnError = new Constant(BOOLEAN, node.getErrorBehavior() == JsonExists.ErrorBehavior.ERROR); ResolvedFunction inputToJson = analysis.getJsonInputFunction(node.getJsonPathInvocation().getInputExpression()); io.trino.sql.ir.Expression input = new Call(inputToJson, ImmutableList.of( translateExpression(node.getJsonPathInvocation().getInputExpression()), failOnError)); // apply the input functions to the JSON path parameters having FORMAT, // and collect all JSON path parameters in a Row ParametersRow orderedParameters = getParametersRow( node.getJsonPathInvocation().getPathParameters(), node.getJsonPathInvocation().getPathParameters().stream() .map(parameter -> translateExpression(parameter.getParameter())) .toList(), resolvedFunction.get().signature().getArgumentType(2), failOnError); IrJsonPath path = new JsonPathTranslator(session, plannerContext).rewriteToIr(analysis.getJsonPathAnalysis(node), orderedParameters.getParametersOrder()); io.trino.sql.ir.Expression pathExpression = new Constant(plannerContext.getTypeManager().getType(TypeId.of(JsonPath2016Type.NAME)), path); ImmutableList.Builder arguments = ImmutableList.builder() .add(input) .add(pathExpression) .add(orderedParameters.getParametersRow()) .add(new Constant(TINYINT, (long) node.getErrorBehavior().ordinal())); return new Call(resolvedFunction.get(), arguments.build()); } private io.trino.sql.ir.Expression translate(JsonValue node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); // apply the input function to the input expression Constant failOnError = new Constant(BOOLEAN, node.getErrorBehavior() == JsonValue.EmptyOrErrorBehavior.ERROR); ResolvedFunction inputToJson = analysis.getJsonInputFunction(node.getJsonPathInvocation().getInputExpression()); io.trino.sql.ir.Expression input = new Call(inputToJson, ImmutableList.of( translateExpression(node.getJsonPathInvocation().getInputExpression()), failOnError)); // apply the input functions to the JSON path parameters having FORMAT, // and collect all JSON path parameters in a Row ParametersRow orderedParameters = getParametersRow( node.getJsonPathInvocation().getPathParameters(), node.getJsonPathInvocation().getPathParameters().stream() .map(parameter -> translateExpression(parameter.getParameter())) .toList(), resolvedFunction.get().signature().getArgumentType(2), failOnError); IrJsonPath path = new JsonPathTranslator(session, plannerContext).rewriteToIr(analysis.getJsonPathAnalysis(node), orderedParameters.getParametersOrder()); io.trino.sql.ir.Expression pathExpression = new Constant(plannerContext.getTypeManager().getType(TypeId.of(JsonPath2016Type.NAME)), path); ImmutableList.Builder arguments = ImmutableList.builder() .add(input) .add(pathExpression) .add(orderedParameters.getParametersRow()) .add(new Constant(TINYINT, (long) node.getEmptyBehavior().ordinal())) .add(node.getEmptyDefault() .map(this::translateExpression) .orElseGet(() -> new Constant(resolvedFunction.get().signature().getReturnType(), null))) .add(new Constant(TINYINT, (long) node.getErrorBehavior().ordinal())) .add(node.getErrorDefault() .map(this::translateExpression) .orElseGet(() -> new Constant(resolvedFunction.get().signature().getReturnType(), null))); return new Call(resolvedFunction.get(), arguments.build()); } private io.trino.sql.ir.Expression translate(JsonQuery node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); // apply the input function to the input expression Constant failOnError = new Constant(BOOLEAN, node.getErrorBehavior() == ERROR); ResolvedFunction inputToJson = analysis.getJsonInputFunction(node.getJsonPathInvocation().getInputExpression()); io.trino.sql.ir.Expression input = new Call(inputToJson, ImmutableList.of( translateExpression(node.getJsonPathInvocation().getInputExpression()), failOnError)); // apply the input functions to the JSON path parameters having FORMAT, // and collect all JSON path parameters in a Row ParametersRow orderedParameters = getParametersRow( node.getJsonPathInvocation().getPathParameters(), node.getJsonPathInvocation().getPathParameters().stream() .map(parameter -> translateExpression(parameter.getParameter())) .toList(), resolvedFunction.get().signature().getArgumentType(2), failOnError); IrJsonPath path = new JsonPathTranslator(session, plannerContext).rewriteToIr(analysis.getJsonPathAnalysis(node), orderedParameters.getParametersOrder()); io.trino.sql.ir.Expression pathExpression = new Constant(plannerContext.getTypeManager().getType(TypeId.of(JsonPath2016Type.NAME)), path); ImmutableList.Builder arguments = ImmutableList.builder() .add(input) .add(pathExpression) .add(orderedParameters.getParametersRow()) .add(new Constant(TINYINT, (long) node.getWrapperBehavior().ordinal())) .add(new Constant(TINYINT, (long) node.getEmptyBehavior().ordinal())) .add(new Constant(TINYINT, (long) node.getErrorBehavior().ordinal())); io.trino.sql.ir.Expression function = new Call(resolvedFunction.get(), arguments.build()); // apply function to format output Constant errorBehavior = new Constant(TINYINT, (long) node.getErrorBehavior().ordinal()); Constant omitQuotes = new Constant(BOOLEAN, node.getQuotesBehavior().orElse(KEEP) == OMIT); ResolvedFunction outputFunction = analysis.getJsonOutputFunction(node); io.trino.sql.ir.Expression result = new Call(outputFunction, ImmutableList.of(function, errorBehavior, omitQuotes)); // cast to requested returned type Type returnedType = node.getReturnedType() .map(TypeSignatureTranslator::toTypeSignature) .map(plannerContext.getTypeManager()::getType) .orElse(VARCHAR); Type resultType = outputFunction.signature().getReturnType(); if (!resultType.equals(returnedType)) { result = new io.trino.sql.ir.Cast(result, returnedType); } return result; } private io.trino.sql.ir.Expression translate(JsonObject node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); io.trino.sql.ir.Expression keysRow; io.trino.sql.ir.Expression valuesRow; // prepare keys and values as rows if (node.getMembers().isEmpty()) { checkState(JSON_NO_PARAMETERS_ROW_TYPE.equals(resolvedFunction.get().signature().getArgumentType(0))); checkState(JSON_NO_PARAMETERS_ROW_TYPE.equals(resolvedFunction.get().signature().getArgumentType(1))); keysRow = new Constant(JSON_NO_PARAMETERS_ROW_TYPE, null); valuesRow = new Constant(JSON_NO_PARAMETERS_ROW_TYPE, null); } else { ImmutableList.Builder keys = ImmutableList.builder(); ImmutableList.Builder values = ImmutableList.builder(); for (JsonObjectMember member : node.getMembers()) { Expression value = member.getValue(); io.trino.sql.ir.Expression rewrittenKey = translateExpression(member.getKey()); keys.add(rewrittenKey); io.trino.sql.ir.Expression rewrittenValue = translateExpression(value); ResolvedFunction valueToJson = analysis.getJsonInputFunction(value); if (valueToJson != null) { values.add(new Call(valueToJson, ImmutableList.of(rewrittenValue, TRUE))); } else { values.add(rewrittenValue); } } keysRow = new io.trino.sql.ir.Row(keys.build()); valuesRow = new io.trino.sql.ir.Row(values.build()); } List arguments = ImmutableList.builder() .add(keysRow) .add(valuesRow) .add(node.isNullOnNull() ? TRUE : FALSE) .add(node.isUniqueKeys() ? TRUE : FALSE) .build(); io.trino.sql.ir.Expression function = new Call(resolvedFunction.get(), arguments); // apply function to format output ResolvedFunction outputFunction = analysis.getJsonOutputFunction(node); io.trino.sql.ir.Expression result = new Call(outputFunction, ImmutableList.of( function, new Constant(TINYINT, (long) ERROR.ordinal()), FALSE)); // cast to requested returned type Type returnedType = node.getReturnedType() .map(TypeSignatureTranslator::toTypeSignature) .map(plannerContext.getTypeManager()::getType) .orElse(VARCHAR); Type resultType = outputFunction.signature().getReturnType(); if (!resultType.equals(returnedType)) { result = new io.trino.sql.ir.Cast(result, returnedType); } return result; } private io.trino.sql.ir.Expression translate(JsonArray node) { Optional resolvedFunction = analysis.getResolvedFunction(node); checkArgument(resolvedFunction.isPresent(), "Function has not been analyzed: %s", node); io.trino.sql.ir.Expression elementsRow; // prepare elements as row if (node.getElements().isEmpty()) { checkState(JSON_NO_PARAMETERS_ROW_TYPE.equals(resolvedFunction.get().signature().getArgumentType(0))); elementsRow = new Constant(JSON_NO_PARAMETERS_ROW_TYPE, null); } else { ImmutableList.Builder elements = ImmutableList.builder(); for (JsonArrayElement arrayElement : node.getElements()) { Expression element = arrayElement.getValue(); io.trino.sql.ir.Expression rewrittenElement = translateExpression(element); ResolvedFunction elementToJson = analysis.getJsonInputFunction(element); if (elementToJson != null) { elements.add(new Call(elementToJson, ImmutableList.of(rewrittenElement, TRUE))); } else { elements.add(rewrittenElement); } } elementsRow = new io.trino.sql.ir.Row(elements.build()); } List arguments = ImmutableList.builder() .add(elementsRow) .add(node.isNullOnNull() ? TRUE : FALSE) .build(); io.trino.sql.ir.Expression function = new Call(resolvedFunction.get(), arguments); // apply function to format output ResolvedFunction outputFunction = analysis.getJsonOutputFunction(node); io.trino.sql.ir.Expression result = new Call(outputFunction, ImmutableList.of( function, new Constant(TINYINT, (long) ERROR.ordinal()), FALSE)); // cast to requested returned type Type returnedType = node.getReturnedType() .map(TypeSignatureTranslator::toTypeSignature) .map(plannerContext.getTypeManager()::getType) .orElse(VARCHAR); Type resultType = outputFunction.signature().getReturnType(); if (!resultType.equals(returnedType)) { result = new io.trino.sql.ir.Cast(result, returnedType); } return result; } private Optional tryGetMapping(Expression expression) { Symbol symbol = substitutions.get(NodeRef.of(expression)); if (symbol == null) { symbol = astToSymbols.get(scopeAwareKey(expression, analysis, scope)); } return Optional.ofNullable(symbol) .map(Symbol::toSymbolReference); } private Optional getSymbolForColumn(Expression expression) { if (!analysis.isColumnReference(expression)) { // Expression can be a reference to lambda argument (or DereferenceExpression based on lambda argument reference). // In such case, the expression might still be resolvable with plan.getScope() but we should not resolve it. return Optional.empty(); } ResolvedField field = analysis.getColumnReferenceFields().get(NodeRef.of(expression)); if (scope.isLocalScope(field.getScope())) { return Optional.of(fieldSymbols[field.getHierarchyFieldIndex()]); } if (outerContext.isPresent()) { return Optional.of(Symbol.from(outerContext.get().rewrite(expression))); } return Optional.empty(); } public Scope getScope() { return scope; } public ParametersRow getParametersRow( List pathParameters, List rewrittenPathParameters, Type parameterRowType, Constant failOnError) { io.trino.sql.ir.Expression parametersRow; List parametersOrder; if (!pathParameters.isEmpty()) { ImmutableList.Builder parameters = ImmutableList.builder(); for (int i = 0; i < pathParameters.size(); i++) { ResolvedFunction parameterToJson = analysis.getJsonInputFunction(pathParameters.get(i).getParameter()); io.trino.sql.ir.Expression rewrittenParameter = rewrittenPathParameters.get(i); if (parameterToJson != null) { parameters.add(new Call(parameterToJson, ImmutableList.of(rewrittenParameter, failOnError))); } else { parameters.add(rewrittenParameter); } } parametersRow = new io.trino.sql.ir.Cast(new io.trino.sql.ir.Row(parameters.build()), parameterRowType); parametersOrder = pathParameters.stream() .map(parameter -> parameter.getName().getCanonicalValue()) .collect(toImmutableList()); } else { checkState(JSON_NO_PARAMETERS_ROW_TYPE.equals(parameterRowType), "invalid type of parameters row when no parameters are passed"); parametersRow = new Constant(JSON_NO_PARAMETERS_ROW_TYPE, null); parametersOrder = ImmutableList.of(); } return new ParametersRow(parametersRow, parametersOrder); } public static class ParametersRow { private final io.trino.sql.ir.Expression parametersRow; private final List parametersOrder; public ParametersRow(io.trino.sql.ir.Expression parametersRow, List parametersOrder) { this.parametersRow = requireNonNull(parametersRow, "parametersRow is null"); this.parametersOrder = requireNonNull(parametersOrder, "parametersOrder is null"); } public io.trino.sql.ir.Expression getParametersRow() { return parametersRow; } public List getParametersOrder() { return parametersOrder; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy