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

com.google.zetasql.FunctionSignature Maven / Gradle / Ivy

There is a newer version: 2024.11.1
Show newest version
/*
 * Copyright 2019 ZetaSQL Authors
 *
 * 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 com.google.zetasql;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.zetasql.FunctionProtos.FunctionArgumentTypeProto;
import com.google.zetasql.FunctionProtos.FunctionSignatureOptionsProto;
import com.google.zetasql.FunctionProtos.FunctionSignatureProto;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * FunctionSignature identifies the argument Types and other properties
 * per overload of a Function.  A FunctionSignature is concrete if it
 * identifies the exact number and fixed Types of its arguments and results.
 * A FunctionSignature can be abstract, specifying templated types and
 * identifying arguments as repeated or optional.  Optional arguments must
 * appear at the end of the argument list.
 *
 * 

If multiple arguments are repeated, they must be consecutive and are * treated as if they repeat together. To illustrate, consider the expression: * 'CASE WHEN {@code } THEN {@code } * WHEN {@code } THEN {@code } * ... * ELSE {@code } END'. * *

This expression has the following signature {@code }: * arg1: {@code } repeated - WHEN * arg2: {@code } repeated - THEN * arg3: {@code } optional - ELSE * result: {@code } * *

The WHEN and THEN arguments (arg1 and arg2) repeat together and must * occur at least once, and the ELSE is optional. The THEN, ELSE, and * RESULT types can be any type, but must be the same type. * *

In order to avoid potential ambiguity, the number of optional arguments * must be less than the number of repeated arguments. * *

The FunctionSignature also includes {@code } for specifying * additional signature matching requirements, if any. */ public final class FunctionSignature implements Serializable { private final ImmutableList arguments; private final FunctionArgumentType resultType; private final long contextId; private final FunctionSignatureOptionsProto options; private final boolean isConcrete; private final ImmutableList concreteArguments; public FunctionSignature( FunctionArgumentType resultType, List arguments, long contextId) { this(resultType, arguments, contextId, FunctionSignatureOptionsProto.getDefaultInstance()); } public FunctionSignature( FunctionArgumentType resultType, List arguments, long contextId, FunctionSignatureOptionsProto options) { this.arguments = ImmutableList.copyOf(arguments); this.resultType = resultType; this.contextId = contextId; this.options = options; isConcrete = computeIsConcrete(); concreteArguments = ImmutableList.copyOf(computeConcreteArgumentTypes()); } public FunctionSignatureProto serialize(FileDescriptorSetsBuilder fileDescriptorSetsBuilder) { FunctionSignatureProto.Builder builder = FunctionSignatureProto.newBuilder(); builder.setOptions(options); builder.setReturnType(resultType.serialize(fileDescriptorSetsBuilder)); builder.setContextId(contextId); for (FunctionArgumentType argument : arguments) { builder.addArgument(argument.serialize(fileDescriptorSetsBuilder)); } return builder.build(); } public static FunctionSignature deserialize( FunctionSignatureProto proto, ImmutableList pools) { List arguments = new ArrayList<>(); for (FunctionArgumentTypeProto argument : proto.getArgumentList()) { arguments.add(FunctionArgumentType.deserialize(argument, pools)); } FunctionSignature signature = new FunctionSignature( FunctionArgumentType.deserialize(proto.getReturnType(), pools), arguments, proto.getContextId(), proto.getOptions()); return signature; } private List computeConcreteArgumentTypes() { if (!isConcrete) { return new ArrayList<>(); } // Count number of concrete args, and find the range of repeateds. int firstRepeatedIndex = -1; int lastRepeatedIndex = -1; for (int idx = 0; idx < arguments.size(); ++idx) { FunctionArgumentType argument = arguments.get(idx); if (argument.isRepeated()) { lastRepeatedIndex = idx; if (firstRepeatedIndex == -1) { firstRepeatedIndex = idx; } } } ArrayList result = new ArrayList<>(); if (firstRepeatedIndex == -1) { // If we have no repeateds, just loop through and copy present args. for (int idx = 0; idx < arguments.size(); ++idx) { FunctionArgumentType argument = arguments.get(idx); if (argument.getNumOccurrences() == 1) { result.add(argument); } } } else { // Add arguments that come before repeated arguments. for (int idx = 0; idx < firstRepeatedIndex; ++idx) { FunctionArgumentType argument = arguments.get(idx); if (argument.getNumOccurrences() == 1) { result.add(argument); } } // Add concrete repetitions of all repeated arguments. int numRepeatedOccurrences = arguments.get(firstRepeatedIndex).getNumOccurrences(); for (int c = 0; c < numRepeatedOccurrences; ++c) { for (int idx = firstRepeatedIndex; idx <= lastRepeatedIndex; ++idx) { result.add(arguments.get(idx)); } } // Add any arguments that come after the repeated arguments. for (int idx = lastRepeatedIndex + 1; idx < arguments.size(); ++idx) { FunctionArgumentType argument = arguments.get(idx); if (argument.getNumOccurrences() == 1) { result.add(argument); } } } return result; } public ImmutableList getFunctionArgumentList() { return arguments; } /** * @throws IllegalStateException if the signature is not concrete. */ public int getConcreteArgumentsCount() { Preconditions.checkState(isConcrete); return concreteArguments.size(); } public Type getConcreteArgumentType(int index) { Preconditions.checkState(isConcrete); return concreteArguments.get(index).getType(); } public FunctionArgumentType getResultType() { return resultType; } public long getContextId() { return contextId; } public boolean isConcrete() { return isConcrete; } public boolean isDeprecated() { return options.getIsDeprecated(); } public FunctionSignatureOptionsProto getOptions() { return options; } private boolean computeIsConcrete() { for (FunctionArgumentType argument : arguments) { if (argument.getNumOccurrences() > 0 && !argument.isConcrete()) { return false; } } return resultType.isConcrete(); } public String debugString(String functionName, boolean verbose) { StringBuilder result = new StringBuilder(functionName); result.append('('); if (verbose) { boolean first = true; for (FunctionArgumentType argument : arguments) { if (!first) { result.append(", "); } first = false; result.append(argument.debugString(verbose)); } } else { Joiner.on(", ").appendTo(result, arguments); } result.append(") -> ").append(resultType.debugString(verbose)); if (verbose) { int numWarnings = options.getAdditionalDeprecationWarningCount(); if (numWarnings > 0) { result.append(" (").append(numWarnings).append(" deprecation warning"); if (numWarnings > 1) { result.append("s"); } result.append(")"); } } return result.toString(); } public String debugString(String functionName) { return debugString(functionName, false); } @Override public String toString() { return debugString(""); } public static String signaturesToString(List signatures) { return " " + Joiner.on("\n ").join(signatures); } public boolean isDefaultValue() { return false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy