diff --git a/pom.xml b/pom.xml
index 0a395518b0438..ec53d04cf9b71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,6 +138,7 @@
presto-proxy
presto-kudu
presto-elasticsearch
+ presto-sql-function
@@ -424,6 +425,12 @@
${project.version}
+
+ com.facebook.presto
+ presto-sql-function
+ ${project.version}
+
+
com.fasterxml.jackson.module
jackson-module-afterburner
diff --git a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestBingTileFunctions.java b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestBingTileFunctions.java
index 8a3450460805e..6b10db2a6bf4a 100644
--- a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestBingTileFunctions.java
+++ b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestBingTileFunctions.java
@@ -60,8 +60,8 @@ protected void registerFunctions()
for (Type type : plugin.getTypes()) {
functionAssertions.getTypeRegistry().addType(type);
}
- functionAssertions.getMetadata().addFunctions(extractFunctions(plugin.getFunctions()));
- functionAssertions.getMetadata().addFunctions(ImmutableList.of(APPLY_FUNCTION));
+ functionAssertions.getMetadata().registerBuiltInFunctions(extractFunctions(plugin.getFunctions()));
+ functionAssertions.getMetadata().registerBuiltInFunctions(ImmutableList.of(APPLY_FUNCTION));
FunctionManager functionManager = functionAssertions.getMetadata().getFunctionManager();
approxDistinct = functionManager.getAggregateFunctionImplementation(
functionManager.lookupFunction("approx_distinct", fromTypes(BING_TILE)));
diff --git a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestSphericalGeoFunctions.java b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestSphericalGeoFunctions.java
index 4ea2936825d8f..7f8d2e5aa811a 100644
--- a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestSphericalGeoFunctions.java
+++ b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/TestSphericalGeoFunctions.java
@@ -47,7 +47,7 @@ protected void registerFunctions()
for (Type type : plugin.getTypes()) {
functionAssertions.getTypeRegistry().addType(type);
}
- functionAssertions.getMetadata().addFunctions(extractFunctions(plugin.getFunctions()));
+ functionAssertions.getMetadata().registerBuiltInFunctions(extractFunctions(plugin.getFunctions()));
}
@Test
diff --git a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/aggregation/AbstractTestGeoAggregationFunctions.java b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/aggregation/AbstractTestGeoAggregationFunctions.java
index 7dfaaf80c0be1..cb870e03ffc73 100644
--- a/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/aggregation/AbstractTestGeoAggregationFunctions.java
+++ b/presto-geospatial/src/test/java/com/facebook/presto/plugin/geospatial/aggregation/AbstractTestGeoAggregationFunctions.java
@@ -48,7 +48,7 @@ public void registerFunctions()
for (Type type : plugin.getTypes()) {
functionAssertions.getTypeRegistry().addType(type);
}
- functionAssertions.getMetadata().addFunctions(extractFunctions(plugin.getFunctions()));
+ functionAssertions.getMetadata().registerBuiltInFunctions(extractFunctions(plugin.getFunctions()));
FunctionManager functionManager = functionAssertions.getMetadata().getFunctionManager();
function = functionManager.getAggregateFunctionImplementation(
functionManager.lookupFunction(getFunctionName(), fromTypes(GEOMETRY)));
diff --git a/presto-main/pom.xml b/presto-main/pom.xml
index 51a190c05b569..3db93634f6d9c 100644
--- a/presto-main/pom.xml
+++ b/presto-main/pom.xml
@@ -71,6 +71,11 @@
presto-memory-context
+
+ com.facebook.presto
+ presto-sql-function
+
+
com.google.code.findbugs
jsr305
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunction.java b/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunction.java
new file mode 100644
index 0000000000000..da402d101d808
--- /dev/null
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunction.java
@@ -0,0 +1,26 @@
+/*
+ * 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.facebook.presto.metadata;
+
+import com.facebook.presto.spi.function.SqlFunction;
+
+public abstract class BuiltInFunction
+ implements SqlFunction
+{
+ @Override
+ public boolean isCalledOnNullInput()
+ {
+ return false;
+ }
+}
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunctionNamespaceManager.java b/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunctionNamespaceManager.java
index e7eace859da5c..235ee37a6e117 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunctionNamespaceManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/BuiltInFunctionNamespaceManager.java
@@ -151,12 +151,12 @@
import com.facebook.presto.operator.window.SqlWindowFunction;
import com.facebook.presto.operator.window.WindowFunctionSupplier;
import com.facebook.presto.spi.PrestoException;
-import com.facebook.presto.spi.QueryId;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.block.BlockEncodingSerde;
import com.facebook.presto.spi.function.FunctionHandle;
import com.facebook.presto.spi.function.FunctionMetadata;
import com.facebook.presto.spi.function.FunctionNamespaceManager;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
import com.facebook.presto.spi.function.OperatorType;
import com.facebook.presto.spi.function.Signature;
import com.facebook.presto.spi.function.SqlFunction;
@@ -349,9 +349,10 @@
@ThreadSafe
public class BuiltInFunctionNamespaceManager
- implements FunctionNamespaceManager
+ implements FunctionNamespaceManager
{
public static final FullyQualifiedName.Prefix DEFAULT_NAMESPACE = FullyQualifiedName.of("presto.default.foo").getPrefix();
+ public static final String NAME = "_builtin";
private final TypeManager typeManager;
private final LoadingCache specializedFunctionKeyCache;
@@ -664,11 +665,10 @@ public BuiltInFunctionNamespaceManager(
builder.scalar(LegacyLogFunction.class);
}
- addFunctions(builder.getFunctions());
+ registerBuiltInFunctions(builder.getFunctions());
}
- @Override
- public final synchronized void addFunctions(List extends SqlFunction> functions)
+ public synchronized void registerBuiltInFunctions(List extends BuiltInFunction> functions)
{
for (SqlFunction function : functions) {
for (SqlFunction existingFunction : this.functions.list()) {
@@ -679,19 +679,46 @@ public final synchronized void addFunctions(List extends SqlFunction> function
}
@Override
- public List listFunctions()
+ public void createFunction(BuiltInFunction function, boolean replace)
+ {
+ throw new UnsupportedOperationException("createFunction cannot be called on BuiltInFunctionNamespaceManager");
+ }
+
+ public String getName()
+ {
+ return NAME;
+ }
+
+ @Override
+ public FunctionNamespaceTransactionHandle beginTransaction()
+ {
+ return new EmptyTransactionHandle();
+ }
+
+ @Override
+ public void commit(FunctionNamespaceTransactionHandle transactionHandle)
+ {
+ }
+
+ @Override
+ public void rollback(FunctionNamespaceTransactionHandle transactionHandle)
+ {
+ }
+
+ @Override
+ public Collection listFunctions()
{
return functions.list();
}
@Override
- public Collection getCandidates(QueryId queryId, FullyQualifiedName name)
+ public Collection getFunctions(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, FullyQualifiedName functionName)
{
- return functions.get(name);
+ return functions.get(functionName);
}
@Override
- public FunctionHandle getFunctionHandle(QueryId queryId, Signature signature)
+ public FunctionHandle getFunctionHandle(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, Signature signature)
{
return new BuiltInFunctionHandle(signature);
}
@@ -709,7 +736,7 @@ public FunctionMetadata getFunctionMetadata(FunctionHandle functionHandle)
throwIfInstanceOf(e.getCause(), PrestoException.class);
throw e;
}
- SqlFunction function = functionKey.getFunction();
+ BuiltInFunction function = functionKey.getFunction();
Optional operatorType = tryGetOperatorType(signature.getName());
if (operatorType.isPresent()) {
return new FunctionMetadata(
@@ -796,11 +823,11 @@ private SpecializedFunctionKey getSpecializedFunctionKey(Signature signature)
private SpecializedFunctionKey doGetSpecializedFunctionKey(Signature signature)
{
- Iterable candidates = getCandidates(null, signature.getName());
+ Iterable candidates = getFunctions(null, signature.getName());
// search for exact match
Type returnType = typeManager.getType(signature.getReturnType());
List argumentTypeSignatureProviders = fromTypeSignatures(signature.getArgumentTypes());
- for (SqlFunction candidate : candidates) {
+ for (BuiltInFunction candidate : candidates) {
Optional boundVariables = new SignatureBinder(typeManager, candidate.getSignature(), false)
.bindVariables(argumentTypeSignatureProviders, returnType);
if (boundVariables.isPresent()) {
@@ -811,7 +838,7 @@ private SpecializedFunctionKey doGetSpecializedFunctionKey(Signature signature)
// TODO: hack because there could be "type only" coercions (which aren't necessarily included as implicit casts),
// so do a second pass allowing "type only" coercions
List argumentTypes = resolveTypes(signature.getArgumentTypes(), typeManager);
- for (SqlFunction candidate : candidates) {
+ for (BuiltInFunction candidate : candidates) {
SignatureBinder binder = new SignatureBinder(typeManager, candidate.getSignature(), true);
Optional boundVariables = binder.bindVariables(argumentTypeSignatureProviders, returnType);
if (!boundVariables.isPresent()) {
@@ -863,25 +890,30 @@ private SpecializedFunctionKey doGetSpecializedFunctionKey(Signature signature)
throw new PrestoException(FUNCTION_IMPLEMENTATION_MISSING, format("%s not found", signature));
}
+ private static class EmptyTransactionHandle
+ implements FunctionNamespaceTransactionHandle
+ {
+ }
+
private static class FunctionMap
{
- private final Multimap functions;
+ private final Multimap functions;
public FunctionMap()
{
functions = ImmutableListMultimap.of();
}
- public FunctionMap(FunctionMap map, Iterable extends SqlFunction> functions)
+ public FunctionMap(FunctionMap map, Iterable extends BuiltInFunction> functions)
{
- this.functions = ImmutableListMultimap.builder()
+ this.functions = ImmutableListMultimap.builder()
.putAll(map.functions)
.putAll(Multimaps.index(functions, function -> function.getSignature().getName()))
.build();
// Make sure all functions with the same name are aggregations or none of them are
- for (Map.Entry> entry : this.functions.asMap().entrySet()) {
- Collection values = entry.getValue();
+ for (Map.Entry> entry : this.functions.asMap().entrySet()) {
+ Collection values = entry.getValue();
long aggregations = values.stream()
.map(function -> function.getSignature().getKind())
.filter(kind -> kind == AGGREGATE)
@@ -890,12 +922,12 @@ public FunctionMap(FunctionMap map, Iterable extends SqlFunction> functions)
}
}
- public List list()
+ public List list()
{
return ImmutableList.copyOf(functions.values());
}
- public Collection get(FullyQualifiedName name)
+ public Collection get(FullyQualifiedName name)
{
return functions.get(name);
}
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionExtractor.java b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionExtractor.java
index 28bf03507942c..5c40e63704318 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionExtractor.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionExtractor.java
@@ -18,7 +18,6 @@
import com.facebook.presto.spi.function.AggregationFunction;
import com.facebook.presto.spi.function.ScalarFunction;
import com.facebook.presto.spi.function.ScalarOperator;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.function.WindowFunction;
import java.util.Collection;
@@ -30,7 +29,7 @@ public final class FunctionExtractor
{
private FunctionExtractor() {}
- public static List extends SqlFunction> extractFunctions(Collection> classes)
+ public static List extractFunctions(Collection> classes)
{
return classes.stream()
.map(FunctionExtractor::extractFunctions)
@@ -38,7 +37,7 @@ public static List extends SqlFunction> extractFunctions(Collection>
.collect(toImmutableList());
}
- public static List extends SqlFunction> extractFunctions(Class> clazz)
+ public static List extends BuiltInFunction> extractFunctions(Class> clazz)
{
if (WindowFunction.class.isAssignableFrom(clazz)) {
@SuppressWarnings("unchecked")
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionListBuilder.java b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionListBuilder.java
index 5dd73d711cd01..d250be11f33b0 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionListBuilder.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionListBuilder.java
@@ -15,7 +15,6 @@
import com.facebook.presto.operator.scalar.annotations.ScalarFromAnnotationsParser;
import com.facebook.presto.operator.window.WindowAnnotationsParser;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.function.WindowFunction;
import com.google.common.collect.ImmutableList;
@@ -26,7 +25,7 @@
public class FunctionListBuilder
{
- private final List functions = new ArrayList<>();
+ private final List functions = new ArrayList<>();
public FunctionListBuilder window(Class extends WindowFunction> clazz)
{
@@ -58,22 +57,22 @@ public FunctionListBuilder scalars(Class> clazz)
return this;
}
- public FunctionListBuilder functions(SqlFunction... sqlFunctions)
+ public FunctionListBuilder functions(BuiltInFunction... sqlFunctions)
{
- for (SqlFunction sqlFunction : sqlFunctions) {
+ for (BuiltInFunction sqlFunction : sqlFunctions) {
function(sqlFunction);
}
return this;
}
- public FunctionListBuilder function(SqlFunction sqlFunction)
+ public FunctionListBuilder function(BuiltInFunction sqlFunction)
{
requireNonNull(sqlFunction, "parametricFunction is null");
functions.add(sqlFunction);
return this;
}
- public List getFunctions()
+ public List getFunctions()
{
return ImmutableList.copyOf(functions);
}
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionManager.java b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionManager.java
index e2f153b1b861b..32c508c9039c7 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/FunctionManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/FunctionManager.java
@@ -18,7 +18,6 @@
import com.facebook.presto.operator.scalar.ScalarFunctionImplementation;
import com.facebook.presto.operator.window.WindowFunctionSupplier;
import com.facebook.presto.spi.PrestoException;
-import com.facebook.presto.spi.QueryId;
import com.facebook.presto.spi.block.BlockEncodingSerde;
import com.facebook.presto.spi.function.FunctionHandle;
import com.facebook.presto.spi.function.FunctionKind;
@@ -26,6 +25,7 @@
import com.facebook.presto.spi.function.FunctionMetadataManager;
import com.facebook.presto.spi.function.FunctionNamespaceManager;
import com.facebook.presto.spi.function.FunctionNamespaceManagerFactory;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
import com.facebook.presto.spi.function.OperatorType;
import com.facebook.presto.spi.function.Signature;
import com.facebook.presto.spi.function.SqlFunction;
@@ -36,6 +36,7 @@
import com.facebook.presto.sql.analyzer.FeaturesConfig;
import com.facebook.presto.sql.analyzer.TypeSignatureProvider;
import com.facebook.presto.sql.tree.QualifiedName;
+import com.facebook.presto.transaction.TransactionManager;
import com.facebook.presto.type.TypeRegistry;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
@@ -65,6 +66,7 @@
import static com.facebook.presto.sql.analyzer.TypeSignatureProvider.fromTypeSignatures;
import static com.facebook.presto.sql.planner.LiteralEncoder.MAGIC_LITERAL_FUNCTION_PREFIX;
import static com.facebook.presto.sql.planner.LiteralEncoder.getMagicLiteralFunctionSignature;
+import static com.facebook.presto.transaction.InMemoryTransactionManager.createTestTransactionManager;
import static com.facebook.presto.type.TypeUtils.resolveTypes;
import static com.facebook.presto.type.UnknownType.UNKNOWN;
import static com.google.common.base.MoreObjects.toStringHelper;
@@ -83,40 +85,51 @@ public class FunctionManager
implements FunctionMetadataManager
{
private final TypeManager typeManager;
- private final BuiltInFunctionNamespaceManager builtInFunctionNamespace;
+ private final TransactionManager transactionManager;
+ private final BuiltInFunctionNamespaceManager builtInFunctionNamespaceManager;
private final FunctionInvokerProvider functionInvokerProvider;
- private final Map functionNamespaceFactories = new ConcurrentHashMap<>();
+ private final Map functionNamespaceManagerFactories = new ConcurrentHashMap<>();
private final HandleResolver handleResolver;
- private final Map functionNamespaces = new ConcurrentHashMap<>();
+ private final Map> functionNamespaces = new ConcurrentHashMap<>();
@Inject
- public FunctionManager(TypeManager typeManager, BlockEncodingSerde blockEncodingSerde, FeaturesConfig featuresConfig, HandleResolver handleResolver)
+ public FunctionManager(
+ TypeManager typeManager,
+ TransactionManager transactionManager,
+ BlockEncodingSerde blockEncodingSerde,
+ FeaturesConfig featuresConfig,
+ HandleResolver handleResolver)
{
this.typeManager = requireNonNull(typeManager, "typeManager is null");
- this.builtInFunctionNamespace = new BuiltInFunctionNamespaceManager(typeManager, blockEncodingSerde, featuresConfig, this);
- this.functionNamespaces.put(DEFAULT_NAMESPACE, builtInFunctionNamespace);
+ this.transactionManager = requireNonNull(transactionManager, "transactionManager is null");
+ this.builtInFunctionNamespaceManager = new BuiltInFunctionNamespaceManager(typeManager, blockEncodingSerde, featuresConfig, this);
+ this.functionNamespaces.put(DEFAULT_NAMESPACE, builtInFunctionNamespaceManager);
this.functionInvokerProvider = new FunctionInvokerProvider(this);
this.handleResolver = handleResolver;
if (typeManager instanceof TypeRegistry) {
((TypeRegistry) typeManager).setFunctionManager(this);
}
+ // TODO: Provide a more encapsulated way for TransactionManager to register FunctionNamespaceManager
+ transactionManager.registerFunctionNamespaceManager(BuiltInFunctionNamespaceManager.NAME, builtInFunctionNamespaceManager);
}
@VisibleForTesting
public FunctionManager(TypeManager typeManager, BlockEncodingSerde blockEncodingSerde, FeaturesConfig featuresConfig)
{
- this(typeManager, blockEncodingSerde, featuresConfig, new HandleResolver());
+ // TODO: Convert this constructor to a function in the testing package
+ this(typeManager, createTestTransactionManager(), blockEncodingSerde, featuresConfig, new HandleResolver());
}
public void loadFunctionNamespaces(String functionNamespaceManagerName, List functionNamespacePrefixes, Map properties)
{
requireNonNull(functionNamespaceManagerName, "connectorName is null");
- FunctionNamespaceManagerFactory factory = functionNamespaceFactories.get(functionNamespaceManagerName);
+ FunctionNamespaceManagerFactory factory = functionNamespaceManagerFactories.get(functionNamespaceManagerName);
checkState(factory != null, "No function namespace manager for %s", functionNamespaceManagerName);
- FunctionNamespaceManager manager = factory.create(properties);
+ FunctionNamespaceManager> functionNamespaceManager = factory.create(properties);
+ transactionManager.registerFunctionNamespaceManager(functionNamespaceManagerName, functionNamespaceManager);
for (String functionNamespacePrefix : functionNamespacePrefixes) {
- if (functionNamespaces.putIfAbsent(FullyQualifiedName.Prefix.of(functionNamespacePrefix), manager) != null) {
+ if (functionNamespaces.putIfAbsent(FullyQualifiedName.Prefix.of(functionNamespacePrefix), functionNamespaceManager) != null) {
throw new IllegalArgumentException(format("Function namespace manager '%s' already registered to handle function namespace '%s'", factory.getName(), functionNamespacePrefix));
}
}
@@ -129,20 +142,20 @@ public FunctionInvokerProvider getFunctionInvokerProvider()
public void addFunctionNamespaceFactory(FunctionNamespaceManagerFactory factory)
{
- if (functionNamespaceFactories.putIfAbsent(factory.getName(), factory) != null) {
+ if (functionNamespaceManagerFactories.putIfAbsent(factory.getName(), factory) != null) {
throw new IllegalArgumentException(format("Resource group configuration manager '%s' is already registered", factory.getName()));
}
handleResolver.addFunctionNamespace(factory.getName(), factory.getHandleResolver());
}
- public void addFunctions(List extends SqlFunction> functions)
+ public void registerBuiltInFunctions(List extends BuiltInFunction> functions)
{
- builtInFunctionNamespace.addFunctions(functions);
+ builtInFunctionNamespaceManager.registerBuiltInFunctions(functions);
}
public List listFunctions()
{
- return builtInFunctionNamespace.listFunctions().stream()
+ return builtInFunctionNamespaceManager.listFunctions().stream()
.filter(function -> !function.isHidden())
.collect(toImmutableList());
}
@@ -157,24 +170,30 @@ public List listFunctions()
*/
public FunctionHandle resolveFunction(Session session, QualifiedName name, List parameterTypes)
{
- FullyQualifiedName fullyQualifiedName;
+ return resolveFunction(Optional.of(session), name, parameterTypes);
+ }
+
+ private FunctionHandle resolveFunction(Optional session, QualifiedName name, List parameterTypes)
+ {
+ FullyQualifiedName functionName;
if (!name.getPrefix().isPresent()) {
- fullyQualifiedName = FullyQualifiedName.of(DEFAULT_NAMESPACE, name.getSuffix());
+ functionName = FullyQualifiedName.of(DEFAULT_NAMESPACE, name.getSuffix());
}
else {
- fullyQualifiedName = FullyQualifiedName.of(name.getOriginalParts());
+ functionName = FullyQualifiedName.of(name.getOriginalParts());
}
- Optional servingNamespaceManager = getServingNamespaceManager(fullyQualifiedName);
- if (!servingNamespaceManager.isPresent()) {
+ Optional> functionNamespaceManager = getServingFunctionNamespaceManager(functionName);
+ if (!functionNamespaceManager.isPresent()) {
throw new PrestoException(FUNCTION_NOT_FOUND, format("Cannot find function namespace for function %s", name));
}
- QueryId queryId = session == null ? null : session.getQueryId();
- Collection allCandidates = servingNamespaceManager.get().getCandidates(queryId, fullyQualifiedName);
+ Optional transactionHandle = session.flatMap(Session::getTransactionId)
+ .map(transactionId -> transactionManager.getFunctionNamespaceTransaction(transactionId, functionNamespaceManager.get().getName()));
+ Collection extends SqlFunction> candidates = functionNamespaceManager.get().getFunctions(transactionHandle, functionName);
try {
- return lookupFunction(servingNamespaceManager.get(), queryId, fullyQualifiedName, parameterTypes, allCandidates);
+ return lookupFunction(functionNamespaceManager.get(), transactionHandle, functionName, parameterTypes, candidates);
}
catch (PrestoException e) {
if (e.getErrorCode().getCode() != FUNCTION_NOT_FOUND.toErrorCode().getCode()) {
@@ -182,9 +201,9 @@ public FunctionHandle resolveFunction(Session session, QualifiedName name, List<
}
}
- Optional match = matchFunctionWithCoercion(allCandidates, parameterTypes);
+ Optional match = matchFunctionWithCoercion(candidates, parameterTypes);
if (match.isPresent()) {
- return servingNamespaceManager.get().getFunctionHandle(queryId, match.get());
+ return functionNamespaceManager.get().getFunctionHandle(transactionHandle, match.get());
}
if (name.getSuffix().startsWith(MAGIC_LITERAL_FUNCTION_PREFIX)) {
@@ -200,7 +219,7 @@ public FunctionHandle resolveFunction(Session session, QualifiedName name, List<
return new BuiltInFunctionHandle(getMagicLiteralFunctionSignature(type));
}
- throw new PrestoException(FUNCTION_NOT_FOUND, constructFunctionNotFoundErrorMessage(name.toString(), parameterTypes, allCandidates));
+ throw new PrestoException(FUNCTION_NOT_FOUND, constructFunctionNotFoundErrorMessage(name.toString(), parameterTypes, candidates));
}
@Override
@@ -211,17 +230,17 @@ public FunctionMetadata getFunctionMetadata(FunctionHandle functionHandle)
public WindowFunctionSupplier getWindowFunctionImplementation(FunctionHandle functionHandle)
{
- return builtInFunctionNamespace.getWindowFunctionImplementation(functionHandle);
+ return builtInFunctionNamespaceManager.getWindowFunctionImplementation(functionHandle);
}
public InternalAggregationFunction getAggregateFunctionImplementation(FunctionHandle functionHandle)
{
- return builtInFunctionNamespace.getAggregateFunctionImplementation(functionHandle);
+ return builtInFunctionNamespaceManager.getAggregateFunctionImplementation(functionHandle);
}
public ScalarFunctionImplementation getScalarFunctionImplementation(FunctionHandle functionHandle)
{
- return builtInFunctionNamespace.getScalarFunctionImplementation(functionHandle);
+ return builtInFunctionNamespaceManager.getScalarFunctionImplementation(functionHandle);
}
@VisibleForTesting
@@ -231,7 +250,7 @@ public List listOperators()
.map(OperatorType::getFunctionName)
.collect(toImmutableSet());
- return builtInFunctionNamespace.listFunctions().stream()
+ return builtInFunctionNamespaceManager.listFunctions().stream()
.filter(function -> operatorNames.contains(function.getSignature().getName()))
.collect(toImmutableList());
}
@@ -239,7 +258,7 @@ public List listOperators()
public FunctionHandle resolveOperator(OperatorType operatorType, List argumentTypes)
{
try {
- return resolveFunction(null, QualifiedName.of(operatorType.getFunctionName().getParts()), argumentTypes);
+ return resolveFunction(Optional.empty(), QualifiedName.of(operatorType.getFunctionName().getParts()), argumentTypes);
}
catch (PrestoException e) {
if (e.getErrorCode().getCode() == FUNCTION_NOT_FOUND.toErrorCode().getCode()) {
@@ -263,9 +282,9 @@ public FunctionHandle resolveOperator(OperatorType operatorType, List parameterTypes)
{
- FullyQualifiedName fullyQualifiedName = FullyQualifiedName.of(DEFAULT_NAMESPACE, name);
- Collection allCandidates = builtInFunctionNamespace.getCandidates(null, fullyQualifiedName);
- return lookupFunction(builtInFunctionNamespace, null, fullyQualifiedName, parameterTypes, allCandidates);
+ FullyQualifiedName functionName = FullyQualifiedName.of(DEFAULT_NAMESPACE, name);
+ Collection extends SqlFunction> candidates = builtInFunctionNamespaceManager.getFunctions(Optional.empty(), functionName);
+ return lookupFunction(builtInFunctionNamespaceManager, Optional.empty(), functionName, parameterTypes, candidates);
}
public FunctionHandle lookupCast(CastType castType, TypeSignature fromType, TypeSignature toType)
@@ -273,7 +292,7 @@ public FunctionHandle lookupCast(CastType castType, TypeSignature fromType, Type
Signature signature = new Signature(castType.getCastName(), SCALAR, emptyList(), emptyList(), toType, singletonList(fromType), false);
try {
- builtInFunctionNamespace.getScalarFunctionImplementation(signature);
+ builtInFunctionNamespaceManager.getScalarFunctionImplementation(signature);
}
catch (PrestoException e) {
if (castType.isOperatorType() && e.getErrorCode().getCode() == FUNCTION_IMPLEMENTATION_MISSING.toErrorCode().getCode()) {
@@ -281,52 +300,57 @@ public FunctionHandle lookupCast(CastType castType, TypeSignature fromType, Type
}
throw e;
}
- return builtInFunctionNamespace.getFunctionHandle(null, signature);
+ return builtInFunctionNamespaceManager.getFunctionHandle(Optional.empty(), signature);
}
- private FunctionHandle lookupFunction(FunctionNamespaceManager functionNamespaceManager, QueryId queryId, FullyQualifiedName name, List parameterTypes, Collection allCandidates)
+ private FunctionHandle lookupFunction(
+ FunctionNamespaceManager> functionNamespaceManager,
+ Optional extends FunctionNamespaceTransactionHandle> transactionHandle,
+ FullyQualifiedName functionName,
+ List parameterTypes,
+ Collection extends SqlFunction> candidates)
{
- List exactCandidates = allCandidates.stream()
+ List exactCandidates = candidates.stream()
.filter(function -> function.getSignature().getTypeVariableConstraints().isEmpty())
.collect(Collectors.toList());
Optional match = matchFunctionExact(exactCandidates, parameterTypes);
if (match.isPresent()) {
- return functionNamespaceManager.getFunctionHandle(queryId, match.get());
+ return functionNamespaceManager.getFunctionHandle(transactionHandle, match.get());
}
- List genericCandidates = allCandidates.stream()
+ List genericCandidates = candidates.stream()
.filter(function -> !function.getSignature().getTypeVariableConstraints().isEmpty())
.collect(Collectors.toList());
match = matchFunctionExact(genericCandidates, parameterTypes);
if (match.isPresent()) {
- return functionNamespaceManager.getFunctionHandle(queryId, match.get());
+ return functionNamespaceManager.getFunctionHandle(transactionHandle, match.get());
}
- throw new PrestoException(FUNCTION_NOT_FOUND, constructFunctionNotFoundErrorMessage(name.toString(), parameterTypes, allCandidates));
+ throw new PrestoException(FUNCTION_NOT_FOUND, constructFunctionNotFoundErrorMessage(functionName.toString(), parameterTypes, candidates));
}
- private Optional getServingNamespaceManager(FullyQualifiedName name)
+ private Optional> getServingFunctionNamespaceManager(FullyQualifiedName functionName)
{
- FullyQualifiedName.Prefix functionPrefix = name.getPrefix();
+ FullyQualifiedName.Prefix functionPrefix = functionName.getPrefix();
if (functionPrefix.equals(DEFAULT_NAMESPACE)) {
- return Optional.of(builtInFunctionNamespace);
+ return Optional.of(builtInFunctionNamespaceManager);
}
FullyQualifiedName.Prefix bestMatchNamespace = null;
- FunctionNamespaceManager servingNamespaceManager = null;
+ FunctionNamespaceManager> servingFunctionNamespaceManager = null;
- for (Map.Entry functionNamespace : functionNamespaces.entrySet()) {
+ for (Map.Entry> functionNamespace : functionNamespaces.entrySet()) {
if (functionNamespace.getKey().contains(functionPrefix) && (bestMatchNamespace == null || bestMatchNamespace.contains(functionNamespace.getKey()))) {
bestMatchNamespace = functionNamespace.getKey();
- servingNamespaceManager = functionNamespace.getValue();
+ servingFunctionNamespaceManager = functionNamespace.getValue();
}
}
- return Optional.ofNullable(servingNamespaceManager);
+ return Optional.ofNullable(servingFunctionNamespaceManager);
}
- private String constructFunctionNotFoundErrorMessage(String name, List parameterTypes, Collection candidates)
+ private String constructFunctionNotFoundErrorMessage(String name, List parameterTypes, Collection extends SqlFunction> candidates)
{
List expectedParameters = new ArrayList<>();
for (SqlFunction function : candidates) {
@@ -349,12 +373,12 @@ private Optional matchFunctionExact(List candidates, Lis
return matchFunction(candidates, actualParameters, false);
}
- private Optional matchFunctionWithCoercion(Collection candidates, List actualParameters)
+ private Optional matchFunctionWithCoercion(Collection extends SqlFunction> candidates, List actualParameters)
{
return matchFunction(candidates, actualParameters, true);
}
- private Optional matchFunction(Collection candidates, List parameters, boolean coercionAllowed)
+ private Optional matchFunction(Collection extends SqlFunction> candidates, List parameters, boolean coercionAllowed)
{
List applicableFunctions = identifyApplicableFunctions(candidates, parameters, coercionAllowed);
if (applicableFunctions.isEmpty()) {
@@ -381,7 +405,7 @@ private Optional matchFunction(Collection candidates, Li
throw new PrestoException(AMBIGUOUS_FUNCTION_CALL, errorMessageBuilder.toString());
}
- private List identifyApplicableFunctions(Collection candidates, List actualParameters, boolean allowCoercion)
+ private List identifyApplicableFunctions(Collection extends SqlFunction> candidates, List actualParameters, boolean allowCoercion)
{
ImmutableList.Builder applicableFunctions = ImmutableList.builder();
for (SqlFunction function : candidates) {
@@ -551,13 +575,13 @@ private static class ApplicableFunction
{
private final Signature declaredSignature;
private final Signature boundSignature;
- private final boolean isCalledOnNullInput;
+ private final boolean calledOnNullInput;
- private ApplicableFunction(Signature declaredSignature, Signature boundSignature, boolean isCalledOnNullInput)
+ private ApplicableFunction(Signature declaredSignature, Signature boundSignature, boolean calledOnNullInput)
{
this.declaredSignature = declaredSignature;
this.boundSignature = boundSignature;
- this.isCalledOnNullInput = isCalledOnNullInput;
+ this.calledOnNullInput = calledOnNullInput;
}
public Signature getDeclaredSignature()
@@ -572,7 +596,7 @@ public Signature getBoundSignature()
public boolean isCalledOnNullInput()
{
- return isCalledOnNullInput;
+ return calledOnNullInput;
}
@Override
@@ -581,6 +605,7 @@ public String toString()
return toStringHelper(this)
.add("declaredSignature", declaredSignature)
.add("boundSignature", boundSignature)
+ .add("calledOnNullInput", calledOnNullInput)
.toString();
}
}
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/Metadata.java b/presto-main/src/main/java/com/facebook/presto/metadata/Metadata.java
index 2742dbdb7ba30..e9dd24fa64d67 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/Metadata.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/Metadata.java
@@ -60,7 +60,7 @@ public interface Metadata
List listFunctions();
- void addFunctions(List extends SqlFunction> functions);
+ void registerBuiltInFunctions(List extends BuiltInFunction> functions);
boolean schemaExists(Session session, CatalogSchemaName schema);
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/MetadataManager.java b/presto-main/src/main/java/com/facebook/presto/metadata/MetadataManager.java
index be1f836f8405b..f8fb5dedf1a47 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/MetadataManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/MetadataManager.java
@@ -155,7 +155,7 @@ public MetadataManager(
columnPropertyManager,
analyzePropertyManager,
transactionManager,
- new FunctionManager(typeManager, blockEncodingSerde, featuresConfig));
+ new FunctionManager(typeManager, transactionManager, blockEncodingSerde, featuresConfig, new HandleResolver()));
}
@Inject
@@ -271,10 +271,9 @@ public List listFunctions()
}
@Override
- public void addFunctions(List extends SqlFunction> functionInfos)
+ public void registerBuiltInFunctions(List extends BuiltInFunction> functionInfos)
{
- // TODO: transactional when FunctionManager is made transactional
- functions.addFunctions(functionInfos);
+ functions.registerBuiltInFunctions(functionInfos);
}
@Override
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/SpecializedFunctionKey.java b/presto-main/src/main/java/com/facebook/presto/metadata/SpecializedFunctionKey.java
index 6fc00fb7bd33f..17c506b4be101 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/SpecializedFunctionKey.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/SpecializedFunctionKey.java
@@ -13,26 +13,24 @@
*/
package com.facebook.presto.metadata;
-import com.facebook.presto.spi.function.SqlFunction;
-
import java.util.Objects;
import static java.util.Objects.requireNonNull;
public class SpecializedFunctionKey
{
- private final SqlFunction function;
+ private final BuiltInFunction function;
private final BoundVariables boundVariables;
private final int arity;
- public SpecializedFunctionKey(SqlFunction function, BoundVariables boundVariables, int arity)
+ public SpecializedFunctionKey(BuiltInFunction function, BoundVariables boundVariables, int arity)
{
this.function = requireNonNull(function, "function is null");
this.boundVariables = requireNonNull(boundVariables, "boundVariables is null");
this.arity = arity;
}
- public SqlFunction getFunction()
+ public BuiltInFunction getFunction()
{
return function;
}
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/SqlAggregationFunction.java b/presto-main/src/main/java/com/facebook/presto/metadata/SqlAggregationFunction.java
index bcb34163df113..cbe3a29b34f98 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/SqlAggregationFunction.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/SqlAggregationFunction.java
@@ -18,7 +18,6 @@
import com.facebook.presto.spi.function.FunctionKind;
import com.facebook.presto.spi.function.LongVariableConstraint;
import com.facebook.presto.spi.function.Signature;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.function.TypeVariableConstraint;
import com.facebook.presto.spi.relation.FullyQualifiedName;
import com.facebook.presto.spi.type.TypeManager;
@@ -34,7 +33,7 @@
import static java.util.Objects.requireNonNull;
public abstract class SqlAggregationFunction
- implements SqlFunction
+ extends BuiltInFunction
{
private final Signature signature;
private final boolean hidden;
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/SqlScalarFunction.java b/presto-main/src/main/java/com/facebook/presto/metadata/SqlScalarFunction.java
index 14f856fc8a322..7596cf08ed870 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/SqlScalarFunction.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/SqlScalarFunction.java
@@ -16,7 +16,6 @@
import com.facebook.presto.operator.scalar.ScalarFunctionImplementation;
import com.facebook.presto.spi.function.OperatorType;
import com.facebook.presto.spi.function.Signature;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.type.TypeManager;
import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
@@ -24,7 +23,7 @@
import static java.util.Objects.requireNonNull;
public abstract class SqlScalarFunction
- implements SqlFunction
+ extends BuiltInFunction
{
private final Signature signature;
diff --git a/presto-main/src/main/java/com/facebook/presto/operator/window/SqlWindowFunction.java b/presto-main/src/main/java/com/facebook/presto/operator/window/SqlWindowFunction.java
index 63fab1b98f3a1..4795c2e64674d 100644
--- a/presto-main/src/main/java/com/facebook/presto/operator/window/SqlWindowFunction.java
+++ b/presto-main/src/main/java/com/facebook/presto/operator/window/SqlWindowFunction.java
@@ -14,15 +14,15 @@
package com.facebook.presto.operator.window;
import com.facebook.presto.metadata.BoundVariables;
+import com.facebook.presto.metadata.BuiltInFunction;
import com.facebook.presto.metadata.FunctionManager;
import com.facebook.presto.spi.function.Signature;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.type.TypeManager;
import static java.util.Objects.requireNonNull;
public class SqlWindowFunction
- implements SqlFunction
+ extends BuiltInFunction
{
private final WindowFunctionSupplier supplier;
diff --git a/presto-main/src/main/java/com/facebook/presto/server/PluginManager.java b/presto-main/src/main/java/com/facebook/presto/server/PluginManager.java
index 01261d36ab3b5..d199b6e4fe46e 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/PluginManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/PluginManager.java
@@ -208,7 +208,7 @@ public void installPlugin(Plugin plugin)
for (Class> functionClass : plugin.getFunctions()) {
log.info("Registering functions from %s", functionClass.getName());
- metadata.addFunctions(extractFunctions(functionClass));
+ metadata.registerBuiltInFunctions(extractFunctions(functionClass));
}
for (FunctionNamespaceManagerFactory functionNamespaceManagerFactory : plugin.getFunctionNamespaceManagerFactories()) {
diff --git a/presto-main/src/main/java/com/facebook/presto/testing/InMemoryFunctionNamespaceManager.java b/presto-main/src/main/java/com/facebook/presto/testing/InMemoryFunctionNamespaceManager.java
new file mode 100644
index 0000000000000..e3b3e5d8ace6a
--- /dev/null
+++ b/presto-main/src/main/java/com/facebook/presto/testing/InMemoryFunctionNamespaceManager.java
@@ -0,0 +1,108 @@
+/*
+ * 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.facebook.presto.testing;
+
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.function.FunctionMetadata;
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.facebook.presto.sqlfunction.AbstractSqlInvokedFunctionNamespaceManager;
+import com.facebook.presto.sqlfunction.SqlFunctionId;
+import com.facebook.presto.sqlfunction.SqlInvokedFunctionNamespaceManagerConfig;
+import com.facebook.presto.sqlfunction.SqlInvokedRegularFunction;
+import com.facebook.presto.sqlfunction.SqlInvokedRegularFunctionHandle;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.facebook.presto.spi.StandardErrorCode.GENERIC_USER_ERROR;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.MoreCollectors.onlyElement;
+import static java.lang.String.format;
+
+@ThreadSafe
+public class InMemoryFunctionNamespaceManager
+ extends AbstractSqlInvokedFunctionNamespaceManager
+{
+ private static final String NAME = "_in_memory";
+ private final Map latestFunctions = new ConcurrentHashMap<>();
+
+ public InMemoryFunctionNamespaceManager(SqlInvokedFunctionNamespaceManagerConfig config)
+ {
+ super(config);
+ }
+
+ @Override
+ public String getName()
+ {
+ return NAME;
+ }
+
+ @Override
+ public synchronized void createFunction(SqlInvokedRegularFunction function, boolean replace)
+ {
+ SqlFunctionId functionId = new SqlFunctionId(function.getSignature().getName(), function.getSignature().getArgumentTypes());
+ if (!replace && latestFunctions.containsKey(functionId)) {
+ throw new PrestoException(GENERIC_USER_ERROR, format("Function '%s' already exists", functionId.getName()));
+ }
+
+ SqlInvokedRegularFunction replacedFunction = latestFunctions.get(functionId);
+ long version = 1;
+ if (replacedFunction != null) {
+ checkArgument(replacedFunction.getVersion().isPresent(), "missing version in replaced function");
+ version = replacedFunction.getVersion().get() + 1;
+ }
+ function = SqlInvokedRegularFunction.versioned(function, version);
+ latestFunctions.put(functionId, function);
+ }
+
+ @Override
+ public Collection listFunctions()
+ {
+ return latestFunctions.values();
+ }
+
+ @Override
+ public Collection fetchFunctionsDirect(FullyQualifiedName name)
+ {
+ return latestFunctions.values().stream()
+ .filter(function -> function.getSignature().getName().equals(name))
+ .map(InMemoryFunctionNamespaceManager::copyFunction)
+ .collect(toImmutableList());
+ }
+
+ @Override
+ public FunctionMetadata fetchFunctionMetadataDirect(SqlInvokedRegularFunctionHandle functionHandle)
+ {
+ return fetchFunctionsDirect(functionHandle.getName()).stream()
+ .filter(function -> function.getRequiredFunctionHandle().equals(functionHandle))
+ .map(AbstractSqlInvokedFunctionNamespaceManager::sqlInvokedFunctionToMetadata)
+ .collect(onlyElement());
+ }
+
+ private static SqlInvokedRegularFunction copyFunction(SqlInvokedRegularFunction function)
+ {
+ return new SqlInvokedRegularFunction(
+ function.getSignature().getName(),
+ function.getParameters(),
+ function.getSignature().getReturnType(),
+ function.getComment(),
+ function.getRoutineCharacteristics(),
+ function.getBody(),
+ function.getVersion());
+ }
+}
diff --git a/presto-main/src/main/java/com/facebook/presto/transaction/InMemoryTransactionManager.java b/presto-main/src/main/java/com/facebook/presto/transaction/InMemoryTransactionManager.java
index f41e40a0de863..74c24c9158afa 100644
--- a/presto-main/src/main/java/com/facebook/presto/transaction/InMemoryTransactionManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/transaction/InMemoryTransactionManager.java
@@ -21,6 +21,8 @@
import com.facebook.presto.spi.connector.Connector;
import com.facebook.presto.spi.connector.ConnectorMetadata;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
+import com.facebook.presto.spi.function.FunctionNamespaceManager;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
import com.facebook.presto.spi.transaction.IsolationLevel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -86,6 +88,8 @@ public class InMemoryTransactionManager
private final CatalogManager catalogManager;
private final Executor finishingExecutor;
+ private final Map> functionNamespaceManagers = new HashMap<>();
+
private InMemoryTransactionManager(Duration idleTimeout, int maxFinishingConcurrency, CatalogManager catalogManager, Executor finishingExecutor)
{
this.catalogManager = catalogManager;
@@ -176,7 +180,7 @@ public TransactionId beginTransaction(IsolationLevel isolationLevel, boolean rea
{
TransactionId transactionId = TransactionId.create();
BoundedExecutor executor = new BoundedExecutor(finishingExecutor, maxFinishingConcurrency);
- TransactionMetadata transactionMetadata = new TransactionMetadata(transactionId, isolationLevel, readOnly, autoCommitContext, catalogManager, executor);
+ TransactionMetadata transactionMetadata = new TransactionMetadata(transactionId, isolationLevel, readOnly, autoCommitContext, catalogManager, executor, functionNamespaceManagers);
checkState(transactions.put(transactionId, transactionMetadata) == null, "Duplicate transaction ID: %s", transactionId);
return transactionId;
}
@@ -227,6 +231,19 @@ public ConnectorTransactionHandle getConnectorTransaction(TransactionId transact
return getCatalogMetadata(transactionId, connectorId).getTransactionHandleFor(connectorId);
}
+ @Override
+ public synchronized void registerFunctionNamespaceManager(String functionNamespaceManagerName, FunctionNamespaceManager> functionNamespaceManager)
+ {
+ checkArgument(!functionNamespaceManagers.containsKey(functionNamespaceManagerName), "FunctionNamespaceManager %s is already registered", functionNamespaceManagerName);
+ functionNamespaceManagers.put(functionNamespaceManagerName, functionNamespaceManager);
+ }
+
+ @Override
+ public FunctionNamespaceTransactionHandle getFunctionNamespaceTransaction(TransactionId transactionId, String functionNamespaceManagerName)
+ {
+ return getTransactionMetadata(transactionId).getFunctionNamespaceTransaction(functionNamespaceManagerName);
+ }
+
private void checkConnectorWrite(TransactionId transactionId, ConnectorId connectorId)
{
getTransactionMetadata(transactionId).checkConnectorWrite(connectorId);
@@ -323,13 +340,18 @@ private static class TransactionMetadata
@GuardedBy("this")
private final Map catalogMetadata = new ConcurrentHashMap<>();
+ private final Map> functionNamespaceManagers;
+ @GuardedBy("this")
+ private final Map functionNamespaceTransactions = new ConcurrentHashMap<>();
+
public TransactionMetadata(
TransactionId transactionId,
IsolationLevel isolationLevel,
boolean readOnly,
boolean autoCommitContext,
CatalogManager catalogManager,
- Executor finishingExecutor)
+ Executor finishingExecutor,
+ Map> functionNamespaceManagers)
{
this.transactionId = requireNonNull(transactionId, "transactionId is null");
this.isolationLevel = requireNonNull(isolationLevel, "isolationLevel is null");
@@ -337,6 +359,7 @@ public TransactionMetadata(
this.autoCommitContext = autoCommitContext;
this.catalogManager = requireNonNull(catalogManager, "catalogManager is null");
this.finishingExecutor = listeningDecorator(ExecutorServiceAdapter.from(requireNonNull(finishingExecutor, "finishingExecutor is null")));
+ this.functionNamespaceManagers = requireNonNull(functionNamespaceManagers, "functionNamespaceManagers is null");
}
public void setActive()
@@ -437,6 +460,13 @@ private synchronized CatalogMetadata getTransactionCatalogMetadata(ConnectorId c
return catalogMetadata;
}
+ private synchronized FunctionNamespaceTransactionHandle getFunctionNamespaceTransaction(String functionNamespaceManagerName)
+ {
+ checkOpenTransaction();
+
+ return functionNamespaceTransactions.computeIfAbsent(functionNamespaceManagerName, name -> functionNamespaceManagers.get(name).beginTransaction());
+ }
+
public synchronized ConnectorTransactionMetadata createConnectorTransactionMetadata(ConnectorId connectorId, Catalog catalog)
{
Connector connector = catalog.getConnector(connectorId);
diff --git a/presto-main/src/main/java/com/facebook/presto/transaction/NoOpTransactionManager.java b/presto-main/src/main/java/com/facebook/presto/transaction/NoOpTransactionManager.java
index 89700104fe238..4d3d318cb83b6 100644
--- a/presto-main/src/main/java/com/facebook/presto/transaction/NoOpTransactionManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/transaction/NoOpTransactionManager.java
@@ -16,6 +16,8 @@
import com.facebook.presto.metadata.CatalogMetadata;
import com.facebook.presto.spi.ConnectorId;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
+import com.facebook.presto.spi.function.FunctionNamespaceManager;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
import com.facebook.presto.spi.transaction.IsolationLevel;
import com.google.common.util.concurrent.ListenableFuture;
@@ -95,6 +97,17 @@ public ConnectorTransactionHandle getConnectorTransaction(TransactionId transact
throw new UnsupportedOperationException();
}
+ @Override
+ public void registerFunctionNamespaceManager(String functionNamespaceManagerName, FunctionNamespaceManager> functionNamespaceManager)
+ {
+ }
+
+ @Override
+ public FunctionNamespaceTransactionHandle getFunctionNamespaceTransaction(TransactionId transactionId, String functionNamespaceManagerName)
+ {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void checkAndSetActive(TransactionId transactionId)
{
diff --git a/presto-main/src/main/java/com/facebook/presto/transaction/TransactionManager.java b/presto-main/src/main/java/com/facebook/presto/transaction/TransactionManager.java
index bc99b944d6789..6cc40c23eeb14 100644
--- a/presto-main/src/main/java/com/facebook/presto/transaction/TransactionManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/transaction/TransactionManager.java
@@ -18,6 +18,8 @@
import com.facebook.presto.security.AccessControl;
import com.facebook.presto.spi.ConnectorId;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
+import com.facebook.presto.spi.function.FunctionNamespaceManager;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
import com.facebook.presto.spi.transaction.IsolationLevel;
import com.google.common.util.concurrent.ListenableFuture;
@@ -57,6 +59,10 @@ default boolean isAutoCommit(TransactionId transactionId)
ConnectorTransactionHandle getConnectorTransaction(TransactionId transactionId, ConnectorId connectorId);
+ void registerFunctionNamespaceManager(String functionNamespaceManagerName, FunctionNamespaceManager> functionNamespaceManager);
+
+ FunctionNamespaceTransactionHandle getFunctionNamespaceTransaction(TransactionId transactionId, String functionNamespaceManagerName);
+
void checkAndSetActive(TransactionId transactionId);
void trySetActive(TransactionId transactionId);
diff --git a/presto-main/src/test/java/com/facebook/presto/metadata/AbstractMockMetadata.java b/presto-main/src/test/java/com/facebook/presto/metadata/AbstractMockMetadata.java
index a44d2023aff8e..4a380ca74cedf 100644
--- a/presto-main/src/test/java/com/facebook/presto/metadata/AbstractMockMetadata.java
+++ b/presto-main/src/test/java/com/facebook/presto/metadata/AbstractMockMetadata.java
@@ -75,7 +75,7 @@ public List listFunctions()
}
@Override
- public void addFunctions(List extends SqlFunction> functions)
+ public void registerBuiltInFunctions(List extends BuiltInFunction> functions)
{
throw new UnsupportedOperationException();
}
diff --git a/presto-main/src/test/java/com/facebook/presto/metadata/SqlInvokedRegularFunctionTestUtils.java b/presto-main/src/test/java/com/facebook/presto/metadata/SqlInvokedRegularFunctionTestUtils.java
new file mode 100644
index 0000000000000..8d017df4cbfe0
--- /dev/null
+++ b/presto-main/src/test/java/com/facebook/presto/metadata/SqlInvokedRegularFunctionTestUtils.java
@@ -0,0 +1,66 @@
+/*
+ * 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.facebook.presto.metadata;
+
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.facebook.presto.sqlfunction.RoutineCharacteristics;
+import com.facebook.presto.sqlfunction.SqlInvokedRegularFunction;
+import com.facebook.presto.sqlfunction.SqlParameter;
+import com.google.common.collect.ImmutableList;
+
+import java.util.Optional;
+
+import static com.facebook.presto.spi.type.StandardTypes.DOUBLE;
+import static com.facebook.presto.spi.type.StandardTypes.INTEGER;
+import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.Determinism.DETERMINISTIC;
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.Language.SQL;
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.NullCallClause.CALLED_ON_NULL_INPUT;
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.NullCallClause.RETURNS_NULL_ON_NULL_INPUT;
+
+public class SqlInvokedRegularFunctionTestUtils
+{
+ private SqlInvokedRegularFunctionTestUtils()
+ {
+ }
+
+ public static final FullyQualifiedName POWER_TOWER = FullyQualifiedName.of("unittest.memory.power_tower");
+
+ public static final SqlInvokedRegularFunction FUNCTION_POWER_TOWER_DOUBLE = new SqlInvokedRegularFunction(
+ POWER_TOWER,
+ ImmutableList.of(new SqlParameter("x", parseTypeSignature(DOUBLE))),
+ parseTypeSignature(DOUBLE),
+ Optional.of("power tower"),
+ new RoutineCharacteristics(SQL, DETERMINISTIC, CALLED_ON_NULL_INPUT),
+ "pow(x, x)",
+ Optional.empty());
+
+ public static final SqlInvokedRegularFunction FUNCTION_POWER_TOWER_DOUBLE_UPDATED = new SqlInvokedRegularFunction(
+ POWER_TOWER,
+ ImmutableList.of(new SqlParameter("x", parseTypeSignature(DOUBLE))),
+ parseTypeSignature(DOUBLE),
+ Optional.of("power tower"),
+ new RoutineCharacteristics(SQL, DETERMINISTIC, RETURNS_NULL_ON_NULL_INPUT),
+ "pow(x, x)",
+ Optional.empty());
+
+ public static final SqlInvokedRegularFunction FUNCTION_POWER_TOWER_INT = new SqlInvokedRegularFunction(
+ POWER_TOWER,
+ ImmutableList.of(new SqlParameter("x", parseTypeSignature(INTEGER))),
+ parseTypeSignature(INTEGER),
+ Optional.of("power tower"),
+ new RoutineCharacteristics(SQL, DETERMINISTIC, RETURNS_NULL_ON_NULL_INPUT),
+ "pow(x, x)",
+ Optional.empty());
+}
diff --git a/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionManager.java b/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionManager.java
index 23dbe18735e2a..87d73d60beafc 100644
--- a/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionManager.java
+++ b/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionManager.java
@@ -117,7 +117,7 @@ public void testMagicLiteralFunction()
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "\\QFunction already registered: presto.default.custom_add(bigint,bigint):bigint\\E")
public void testDuplicateFunctions()
{
- List functions = new FunctionListBuilder()
+ List functions = new FunctionListBuilder()
.scalars(CustomFunctions.class)
.getFunctions()
.stream()
@@ -126,20 +126,20 @@ public void testDuplicateFunctions()
TypeRegistry typeManager = new TypeRegistry();
FunctionManager functionManager = createFunctionManager(typeManager);
- functionManager.addFunctions(functions);
- functionManager.addFunctions(functions);
+ functionManager.registerBuiltInFunctions(functions);
+ functionManager.registerBuiltInFunctions(functions);
}
@Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "'presto.default.sum' is both an aggregation and a scalar function")
public void testConflictingScalarAggregation()
{
- List functions = new FunctionListBuilder()
+ List functions = new FunctionListBuilder()
.scalars(ScalarSum.class)
.getFunctions();
TypeRegistry typeManager = new TypeRegistry();
FunctionManager functionManager = createFunctionManager(typeManager);
- functionManager.addFunctions(functions);
+ functionManager.registerBuiltInFunctions(functions);
}
@Test
@@ -399,13 +399,13 @@ private FunctionHandle resolveFunctionHandle()
{
FeaturesConfig featuresConfig = new FeaturesConfig();
FunctionManager functionManager = new FunctionManager(typeRegistry, blockEncoding, featuresConfig);
- functionManager.addFunctions(createFunctionsFromSignatures());
+ functionManager.registerBuiltInFunctions(createFunctionsFromSignatures());
return functionManager.resolveFunction(TEST_SESSION, QualifiedName.of("presto", "default", TEST_FUNCTION_NAME), fromTypeSignatures(parameterTypes));
}
- private List createFunctionsFromSignatures()
+ private List createFunctionsFromSignatures()
{
- ImmutableList.Builder functions = ImmutableList.builder();
+ ImmutableList.Builder functions = ImmutableList.builder();
for (SignatureBuilder functionSignature : functionSignatures) {
Signature signature = functionSignature.name(TEST_FUNCTION_NAME).build();
functions.add(new SqlScalarFunction(signature)
diff --git a/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionNamespaceManager.java b/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionNamespaceManager.java
new file mode 100644
index 0000000000000..79fdca16728f3
--- /dev/null
+++ b/presto-main/src/test/java/com/facebook/presto/metadata/TestFunctionNamespaceManager.java
@@ -0,0 +1,166 @@
+/*
+ * 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.facebook.presto.metadata;
+
+import com.facebook.presto.spi.ErrorCodeSupplier;
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.function.FunctionMetadata;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
+import com.facebook.presto.sqlfunction.SqlInvokedFunctionNamespaceManagerConfig;
+import com.facebook.presto.sqlfunction.SqlInvokedRegularFunction;
+import com.facebook.presto.testing.InMemoryFunctionNamespaceManager;
+import com.google.common.collect.ImmutableSet;
+import io.airlift.units.Duration;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.Optional;
+
+import static com.facebook.presto.metadata.SqlInvokedRegularFunctionTestUtils.FUNCTION_POWER_TOWER_DOUBLE;
+import static com.facebook.presto.metadata.SqlInvokedRegularFunctionTestUtils.FUNCTION_POWER_TOWER_DOUBLE_UPDATED;
+import static com.facebook.presto.metadata.SqlInvokedRegularFunctionTestUtils.FUNCTION_POWER_TOWER_INT;
+import static com.facebook.presto.metadata.SqlInvokedRegularFunctionTestUtils.POWER_TOWER;
+import static com.facebook.presto.spi.StandardErrorCode.GENERIC_USER_ERROR;
+import static com.facebook.presto.sqlfunction.SqlInvokedRegularFunction.versioned;
+import static com.facebook.presto.testing.assertions.Assert.assertEquals;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static java.lang.String.format;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+public class TestFunctionNamespaceManager
+{
+ @Test
+ public void testCreateFunction()
+ {
+ InMemoryFunctionNamespaceManager functionNamespaceManager = createFunctionNamespaceManager();
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE, false);
+ assertEquals(functionNamespaceManager.listFunctions(), ImmutableSet.of(versioned(FUNCTION_POWER_TOWER_DOUBLE, 1)));
+
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_INT, false);
+ assertEquals(
+ ImmutableSet.copyOf(functionNamespaceManager.listFunctions()),
+ ImmutableSet.of(versioned(FUNCTION_POWER_TOWER_DOUBLE, 1), versioned(FUNCTION_POWER_TOWER_INT, 1)));
+
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE_UPDATED, true);
+ assertEquals(
+ ImmutableSet.copyOf(functionNamespaceManager.listFunctions()),
+ ImmutableSet.of(versioned(FUNCTION_POWER_TOWER_DOUBLE_UPDATED, 2), versioned(FUNCTION_POWER_TOWER_INT, 1)));
+
+ System.out.println(FUNCTION_POWER_TOWER_DOUBLE);
+ }
+
+ @Test
+ public void testCreateFunctionFailed()
+ {
+ InMemoryFunctionNamespaceManager functionNamespaceManager = createFunctionNamespaceManager();
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE, false);
+ assertPrestoException(
+ () -> functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE_UPDATED, false),
+ GENERIC_USER_ERROR,
+ ".*Function 'unittest.memory.power_tower' already exists");
+ }
+
+ @Test
+ public void testTransactionalGetFunction()
+ {
+ InMemoryFunctionNamespaceManager functionNamespaceManager = new InMemoryFunctionNamespaceManager(
+ new SqlInvokedFunctionNamespaceManagerConfig()
+ .setFunctionCacheExpiration(new Duration(0, MILLISECONDS))
+ .setMetadataCacheExpiration(new Duration(0, MILLISECONDS)));
+
+ // begin first transaction
+ FunctionNamespaceTransactionHandle transaction1 = functionNamespaceManager.beginTransaction();
+ assertEquals(functionNamespaceManager.getFunctions(Optional.of(transaction1), POWER_TOWER).size(), 0);
+
+ // create function, first transaction still sees no functions
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE, false);
+ assertEquals(functionNamespaceManager.getFunctions(Optional.of(transaction1), POWER_TOWER).size(), 0);
+
+ // second transaction sees newly created function
+ FunctionNamespaceTransactionHandle transaction2 = functionNamespaceManager.beginTransaction();
+ Collection functions2 = functionNamespaceManager.getFunctions(Optional.of(transaction2), POWER_TOWER);
+ assertEquals(functions2.size(), 1);
+ assertEquals(getOnlyElement(functions2), versioned(FUNCTION_POWER_TOWER_DOUBLE, 1));
+
+ // update the function, second transaction still sees the old functions
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE_UPDATED, true);
+ functions2 = functionNamespaceManager.getFunctions(Optional.of(transaction2), POWER_TOWER);
+ assertEquals(functions2.size(), 1);
+ assertEquals(getOnlyElement(functions2), versioned(FUNCTION_POWER_TOWER_DOUBLE, 1));
+
+ // third transaction sees the updated function
+ FunctionNamespaceTransactionHandle transaction3 = functionNamespaceManager.beginTransaction();
+ Collection functions3 = functionNamespaceManager.getFunctions(Optional.of(transaction3), POWER_TOWER);
+ assertEquals(functions3.size(), 1);
+ assertEquals(getOnlyElement(functions3), versioned(FUNCTION_POWER_TOWER_DOUBLE_UPDATED, 2));
+
+ functionNamespaceManager.commit(transaction1);
+ functionNamespaceManager.commit(transaction2);
+ functionNamespaceManager.commit(transaction3);
+ }
+
+ @Test
+ public void testCaching()
+ {
+ InMemoryFunctionNamespaceManager functionNamespaceManager = createFunctionNamespaceManager();
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_DOUBLE, false);
+
+ // fetchFunctionsDirect does not produce the same function reference
+ SqlInvokedRegularFunction function1 = getOnlyElement(functionNamespaceManager.fetchFunctionsDirect(POWER_TOWER));
+ SqlInvokedRegularFunction function2 = getOnlyElement(functionNamespaceManager.fetchFunctionsDirect(POWER_TOWER));
+ assertEquals(function1, function2);
+ assertNotSame(function1, function2);
+
+ // fetchFunctionMetadataDirect does not produce the same metdata reference
+ FunctionMetadata metadata1 = functionNamespaceManager.fetchFunctionMetadataDirect(function1.getRequiredFunctionHandle());
+ FunctionMetadata metadata2 = functionNamespaceManager.fetchFunctionMetadataDirect(function2.getRequiredFunctionHandle());
+ assertEquals(metadata1, metadata2);
+ assertNotSame(metadata1, metadata2);
+
+ // getFunctionMetadata produces the same metadata reference
+ metadata1 = functionNamespaceManager.getFunctionMetadata(function1.getRequiredFunctionHandle());
+ metadata2 = functionNamespaceManager.getFunctionMetadata(function2.getRequiredFunctionHandle());
+ assertSame(metadata1, metadata2);
+
+ // getFunctions produces the same function collection reference
+ functionNamespaceManager.createFunction(FUNCTION_POWER_TOWER_INT, false);
+ FunctionNamespaceTransactionHandle transaction1 = functionNamespaceManager.beginTransaction();
+ FunctionNamespaceTransactionHandle transaction2 = functionNamespaceManager.beginTransaction();
+ Collection functions1 = functionNamespaceManager.getFunctions(Optional.of(transaction1), POWER_TOWER);
+ Collection functions2 = functionNamespaceManager.getFunctions(Optional.of(transaction2), POWER_TOWER);
+ assertEquals(functions1.size(), 2);
+ assertSame(functions1, functions2);
+ }
+
+ private static InMemoryFunctionNamespaceManager createFunctionNamespaceManager()
+ {
+ return new InMemoryFunctionNamespaceManager(new SqlInvokedFunctionNamespaceManagerConfig());
+ }
+
+ private static void assertPrestoException(Runnable runnable, ErrorCodeSupplier expectedErrorCode, String expectedMessageRegex)
+ {
+ try {
+ runnable.run();
+ fail(format("Expected PrestoException with error code '%s', but not Exception is thrown", expectedErrorCode.toErrorCode().getName()));
+ }
+ catch (PrestoException e) {
+ assertEquals(e.getErrorCode(), expectedErrorCode.toErrorCode());
+ assertTrue(e.getMessage().matches(expectedMessageRegex));
+ }
+ }
+}
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/TestScanFilterAndProjectOperator.java b/presto-main/src/test/java/com/facebook/presto/operator/TestScanFilterAndProjectOperator.java
index ccc457d709b87..a67fd55fad441 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/TestScanFilterAndProjectOperator.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/TestScanFilterAndProjectOperator.java
@@ -274,7 +274,7 @@ public void testPageYield()
}
Metadata metadata = functionAssertions.getMetadata();
FunctionManager functionManager = metadata.getFunctionManager();
- functionManager.addFunctions(functions.build());
+ functionManager.registerBuiltInFunctions(functions.build());
// match each column with a projection
ExpressionCompiler expressionCompiler = new ExpressionCompiler(metadata, new PageFunctionCompiler(metadata, 0));
@@ -338,7 +338,7 @@ public void testRecordCursorYield()
// set up generic long function with a callback to force yield
Metadata metadata = functionAssertions.getMetadata();
FunctionManager functionManager = metadata.getFunctionManager();
- functionManager.addFunctions(ImmutableList.of(new GenericLongFunction("record_cursor", value -> {
+ functionManager.registerBuiltInFunctions(ImmutableList.of(new GenericLongFunction("record_cursor", value -> {
driverContext.getYieldSignal().forceYieldForTesting();
return value;
})));
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/aggregation/AbstractTestAggregationFunction.java b/presto-main/src/test/java/com/facebook/presto/operator/aggregation/AbstractTestAggregationFunction.java
index 1776ca116984c..47980932fdd0f 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/aggregation/AbstractTestAggregationFunction.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/aggregation/AbstractTestAggregationFunction.java
@@ -64,7 +64,7 @@ public final void destroyTestAggregationFunction()
protected void registerFunctions(Plugin plugin)
{
- functionManager.addFunctions(extractFunctions(plugin.getFunctions()));
+ functionManager.registerBuiltInFunctions(extractFunctions(plugin.getFunctions()));
}
protected void registerTypes(Plugin plugin)
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/aggregation/TestCountNullAggregation.java b/presto-main/src/test/java/com/facebook/presto/operator/aggregation/TestCountNullAggregation.java
index b6974ed793087..5da964cae6afc 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/aggregation/TestCountNullAggregation.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/aggregation/TestCountNullAggregation.java
@@ -39,7 +39,7 @@ public class TestCountNullAggregation
@BeforeClass
public void setup()
{
- functionManager.addFunctions(new FunctionListBuilder().aggregates(CountNull.class).getFunctions());
+ functionManager.registerBuiltInFunctions(new FunctionListBuilder().aggregates(CountNull.class).getFunctions());
}
@Override
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/AbstractTestFunctions.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/AbstractTestFunctions.java
index 9a7fc859a29c2..b522a8bc2215b 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/AbstractTestFunctions.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/AbstractTestFunctions.java
@@ -14,6 +14,7 @@
package com.facebook.presto.operator.scalar;
import com.facebook.presto.Session;
+import com.facebook.presto.metadata.BuiltInFunction;
import com.facebook.presto.metadata.FunctionListBuilder;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.metadata.SqlScalarFunction;
@@ -22,7 +23,6 @@
import com.facebook.presto.spi.PrestoException;
import com.facebook.presto.spi.StandardErrorCode;
import com.facebook.presto.spi.function.OperatorType;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.type.DecimalParseResult;
import com.facebook.presto.spi.type.Decimals;
import com.facebook.presto.spi.type.SqlDecimal;
@@ -186,30 +186,30 @@ protected void tryEvaluateWithAll(String projection, Type expectedType)
protected void registerScalarFunction(SqlScalarFunction sqlScalarFunction)
{
Metadata metadata = functionAssertions.getMetadata();
- metadata.getFunctionManager().addFunctions(ImmutableList.of(sqlScalarFunction));
+ metadata.getFunctionManager().registerBuiltInFunctions(ImmutableList.of(sqlScalarFunction));
}
protected void registerScalar(Class> clazz)
{
Metadata metadata = functionAssertions.getMetadata();
- List functions = new FunctionListBuilder()
+ List functions = new FunctionListBuilder()
.scalars(clazz)
.getFunctions();
- metadata.getFunctionManager().addFunctions(functions);
+ metadata.getFunctionManager().registerBuiltInFunctions(functions);
}
protected void registerParametricScalar(Class> clazz)
{
Metadata metadata = functionAssertions.getMetadata();
- List functions = new FunctionListBuilder()
+ List functions = new FunctionListBuilder()
.scalar(clazz)
.getFunctions();
- metadata.getFunctionManager().addFunctions(functions);
+ metadata.getFunctionManager().registerBuiltInFunctions(functions);
}
protected void registerFunctions(Plugin plugin)
{
- functionAssertions.getMetadata().addFunctions(extractFunctions(plugin.getFunctions()));
+ functionAssertions.getMetadata().registerBuiltInFunctions(extractFunctions(plugin.getFunctions()));
}
protected void registerTypes(Plugin plugin)
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayDistinct.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayDistinct.java
index 2fbe911217918..80797553cb785 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayDistinct.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayDistinct.java
@@ -107,7 +107,7 @@ public void setup()
{
MetadataManager metadata = MetadataManager.createTestMetadataManager();
FunctionManager functionManager = metadata.getFunctionManager();
- metadata.addFunctions(extractFunctions(BenchmarkArrayDistinct.class));
+ metadata.registerBuiltInFunctions(extractFunctions(BenchmarkArrayDistinct.class));
ExpressionCompiler compiler = new ExpressionCompiler(metadata, new PageFunctionCompiler(metadata, 0));
ImmutableList.Builder projectionsBuilder = ImmutableList.builder();
Block[] blocks = new Block[TYPES.size()];
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayFilter.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayFilter.java
index 1706d157c8ac2..7aa66b60e6cd8 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayFilter.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayFilter.java
@@ -126,7 +126,7 @@ public void setup()
{
MetadataManager metadata = MetadataManager.createTestMetadataManager();
FunctionManager functionManager = metadata.getFunctionManager();
- metadata.addFunctions(new FunctionListBuilder().function(EXACT_ARRAY_FILTER_FUNCTION).getFunctions());
+ metadata.registerBuiltInFunctions(new FunctionListBuilder().function(EXACT_ARRAY_FILTER_FUNCTION).getFunctions());
ExpressionCompiler compiler = new ExpressionCompiler(metadata, new PageFunctionCompiler(metadata, 0));
ImmutableList.Builder projectionsBuilder = ImmutableList.builder();
Block[] blocks = new Block[TYPES.size()];
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayHashCodeOperator.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayHashCodeOperator.java
index 6609734ba92a7..da4d41934e793 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayHashCodeOperator.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArrayHashCodeOperator.java
@@ -117,8 +117,8 @@ public void setup()
{
MetadataManager metadata = MetadataManager.createTestMetadataManager();
FunctionManager functionManager = metadata.getFunctionManager();
- metadata.addFunctions(new FunctionListBuilder().scalar(BenchmarkOldArrayHash.class).getFunctions());
- metadata.addFunctions(new FunctionListBuilder().scalar(BenchmarkAnotherArrayHash.class).getFunctions());
+ metadata.registerBuiltInFunctions(new FunctionListBuilder().scalar(BenchmarkOldArrayHash.class).getFunctions());
+ metadata.registerBuiltInFunctions(new FunctionListBuilder().scalar(BenchmarkAnotherArrayHash.class).getFunctions());
ExpressionCompiler compiler = new ExpressionCompiler(metadata, new PageFunctionCompiler(metadata, 0));
ImmutableList.Builder projectionsBuilder = ImmutableList.builder();
Block[] blocks = new Block[1];
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArraySort.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArraySort.java
index 43567151df376..47e8f93ebc776 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArraySort.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/BenchmarkArraySort.java
@@ -105,7 +105,7 @@ public static class BenchmarkData
public void setup()
{
MetadataManager metadata = MetadataManager.createTestMetadataManager();
- metadata.addFunctions(extractFunctions(BenchmarkArraySort.class));
+ metadata.registerBuiltInFunctions(extractFunctions(BenchmarkArraySort.class));
ExpressionCompiler compiler = new ExpressionCompiler(metadata, new PageFunctionCompiler(metadata, 0));
ImmutableList.Builder projectionsBuilder = ImmutableList.builder();
Block[] blocks = new Block[TYPES.size()];
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/FunctionAssertions.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/FunctionAssertions.java
index 310ef1efb665a..13385b3187758 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/FunctionAssertions.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/FunctionAssertions.java
@@ -15,6 +15,7 @@
import com.facebook.presto.Session;
import com.facebook.presto.execution.warnings.WarningCollector;
+import com.facebook.presto.metadata.BuiltInFunction;
import com.facebook.presto.metadata.FunctionListBuilder;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.metadata.Split;
@@ -47,7 +48,6 @@
import com.facebook.presto.spi.TableHandle;
import com.facebook.presto.spi.block.Block;
import com.facebook.presto.spi.connector.ConnectorTransactionHandle;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.plan.PlanNodeId;
import com.facebook.presto.spi.predicate.Utils;
import com.facebook.presto.spi.relation.RowExpression;
@@ -219,15 +219,15 @@ public Metadata getMetadata()
return metadata;
}
- public FunctionAssertions addFunctions(List extends SqlFunction> functionInfos)
+ public FunctionAssertions addFunctions(List extends BuiltInFunction> functionInfos)
{
- metadata.addFunctions(functionInfos);
+ metadata.registerBuiltInFunctions(functionInfos);
return this;
}
public FunctionAssertions addScalarFunctions(Class> clazz)
{
- metadata.addFunctions(new FunctionListBuilder().scalars(clazz).getFunctions());
+ metadata.registerBuiltInFunctions(new FunctionListBuilder().scalars(clazz).getFunctions());
return this;
}
diff --git a/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestLambdaExpression.java b/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestLambdaExpression.java
index 72ca397d55a87..a2e0fdd33bd11 100644
--- a/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestLambdaExpression.java
+++ b/presto-main/src/test/java/com/facebook/presto/operator/scalar/TestLambdaExpression.java
@@ -50,7 +50,7 @@ private TestLambdaExpression(Session session)
@BeforeClass
public void setUp()
{
- functionAssertions.getMetadata().addFunctions(ImmutableList.of(APPLY_FUNCTION, INVOKE_FUNCTION));
+ functionAssertions.getMetadata().registerBuiltInFunctions(ImmutableList.of(APPLY_FUNCTION, INVOKE_FUNCTION));
}
@Test
diff --git a/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java b/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
index b2a850d459382..98cdc672e4d2f 100644
--- a/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
+++ b/presto-main/src/test/java/com/facebook/presto/sql/TestExpressionInterpreter.java
@@ -144,7 +144,7 @@ public class TestExpressionInterpreter
@BeforeClass
public void setup()
{
- METADATA.getFunctionManager().addFunctions(ImmutableList.of(APPLY_FUNCTION));
+ METADATA.getFunctionManager().registerBuiltInFunctions(ImmutableList.of(APPLY_FUNCTION));
}
@Test
diff --git a/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestAnalyzer.java b/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestAnalyzer.java
index 5eb3079a85822..649c7c09ffa3f 100644
--- a/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestAnalyzer.java
+++ b/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestAnalyzer.java
@@ -1562,7 +1562,7 @@ public void setup()
new AnalyzePropertyManager(),
transactionManager);
- metadata.getFunctionManager().addFunctions(ImmutableList.of(APPLY_FUNCTION));
+ metadata.getFunctionManager().registerBuiltInFunctions(ImmutableList.of(APPLY_FUNCTION));
Catalog tpchTestCatalog = createTestingCatalog(TPCH_CATALOG, TPCH_CONNECTOR_ID);
catalogManager.registerCatalog(tpchTestCatalog);
diff --git a/presto-ml/src/test/java/com/facebook/presto/ml/AbstractTestMLFunctions.java b/presto-ml/src/test/java/com/facebook/presto/ml/AbstractTestMLFunctions.java
index 1206bd70f9da0..dffbefd9189aa 100644
--- a/presto-ml/src/test/java/com/facebook/presto/ml/AbstractTestMLFunctions.java
+++ b/presto-ml/src/test/java/com/facebook/presto/ml/AbstractTestMLFunctions.java
@@ -25,7 +25,7 @@ abstract class AbstractTestMLFunctions
@BeforeClass
protected void registerFunctions()
{
- functionAssertions.getMetadata().addFunctions(
+ functionAssertions.getMetadata().registerBuiltInFunctions(
extractFunctions(new MLPlugin().getFunctions()));
}
}
diff --git a/presto-ml/src/test/java/com/facebook/presto/ml/TestEvaluateClassifierPredictions.java b/presto-ml/src/test/java/com/facebook/presto/ml/TestEvaluateClassifierPredictions.java
index 4f8b007a901e6..cb59c7300ae4c 100644
--- a/presto-ml/src/test/java/com/facebook/presto/ml/TestEvaluateClassifierPredictions.java
+++ b/presto-ml/src/test/java/com/facebook/presto/ml/TestEvaluateClassifierPredictions.java
@@ -42,7 +42,7 @@ public class TestEvaluateClassifierPredictions
@Test
public void testEvaluateClassifierPredictions()
{
- metadata.addFunctions(extractFunctions(new MLPlugin().getFunctions()));
+ metadata.registerBuiltInFunctions(extractFunctions(new MLPlugin().getFunctions()));
InternalAggregationFunction aggregation = functionManager.getAggregateFunctionImplementation(
functionManager.lookupFunction("evaluate_classifier_predictions", fromTypes(BIGINT, BIGINT)));
Accumulator accumulator = aggregation.bind(ImmutableList.of(0, 1), Optional.empty()).createAccumulator();
diff --git a/presto-ml/src/test/java/com/facebook/presto/ml/TestMLQueries.java b/presto-ml/src/test/java/com/facebook/presto/ml/TestMLQueries.java
index 6162e9a981e35..6fa261f686a83 100644
--- a/presto-ml/src/test/java/com/facebook/presto/ml/TestMLQueries.java
+++ b/presto-ml/src/test/java/com/facebook/presto/ml/TestMLQueries.java
@@ -71,7 +71,7 @@ private static LocalQueryRunner createLocalQueryRunner()
for (ParametricType parametricType : plugin.getParametricTypes()) {
localQueryRunner.getTypeManager().addParametricType(parametricType);
}
- localQueryRunner.getMetadata().addFunctions(extractFunctions(new MLPlugin().getFunctions()));
+ localQueryRunner.getMetadata().registerBuiltInFunctions(extractFunctions(new MLPlugin().getFunctions()));
return localQueryRunner;
}
diff --git a/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4 b/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
index 795cbb85426c6..d5e8bccded73e 100644
--- a/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
+++ b/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
@@ -56,8 +56,10 @@ statement
| CREATE (OR REPLACE)? VIEW qualifiedName AS query #createView
| DROP VIEW (IF EXISTS)? qualifiedName #dropView
| CREATE (OR REPLACE)? FUNCTION functionName=qualifiedName
- '(' (sqlParameterDeclaration (',' sqlParameterDeclaration)*)? ')'
- RETURNS returnType=type routineCharacteristics routineBody #createFunction
+ '(' (sqlParameterDeclaration (',' sqlParameterDeclaration)*)? ')'
+ RETURNS returnType=type
+ (COMMENT string)?
+ routineCharacteristics routineBody #createFunction
| CALL qualifiedName '(' (callArgument (',' callArgument)*)? ')' #call
| CREATE ROLE name=identifier
(WITH ADMIN grantor)? #createRole
diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java
index 10421a12165ff..766791d26987f 100644
--- a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java
+++ b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java
@@ -561,8 +561,12 @@ protected Void visitCreateFunction(CreateFunction node, Integer indent)
.append(formatSqlParameterDeclarations(node.getParameters()))
.append("\nRETURNS ")
.append(node.getReturnType())
- .append("\n")
- .append(formatRoutineCharacteristics(node.getCharacteristics()))
+ .append("\n");
+ if (node.getComment().isPresent()) {
+ builder.append("\nCOMMENT ")
+ .append(formatStringLiteral(node.getComment().get()));
+ }
+ builder.append(formatRoutineCharacteristics(node.getCharacteristics()))
.append("\nRETURN ")
.append(formatExpression(node.getBody(), parameters));
diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java
index 013f01c54684c..1380a51327898 100644
--- a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java
+++ b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java
@@ -404,6 +404,11 @@ public Node visitCreateView(SqlBaseParser.CreateViewContext context)
@Override
public Node visitCreateFunction(SqlBaseParser.CreateFunctionContext context)
{
+ Optional comment = Optional.empty();
+ if (context.COMMENT() != null) {
+ comment = Optional.of(((StringLiteral) visit(context.string())).getValue());
+ }
+
return new CreateFunction(
getQualifiedName(context.functionName),
context.REPLACE() != null,
@@ -411,6 +416,7 @@ public Node visitCreateFunction(SqlBaseParser.CreateFunctionContext context)
.map(this::getParameterDeclarations)
.collect(toImmutableList()),
getType(context.returnType),
+ comment,
getRoutineCharacteristics(context.routineCharacteristics()),
(Expression) visit(context.routineBody()));
}
diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/tree/CreateFunction.java b/presto-parser/src/main/java/com/facebook/presto/sql/tree/CreateFunction.java
index 046b38234e5ad..2031da7b45db7 100644
--- a/presto-parser/src/main/java/com/facebook/presto/sql/tree/CreateFunction.java
+++ b/presto-parser/src/main/java/com/facebook/presto/sql/tree/CreateFunction.java
@@ -29,26 +29,28 @@ public class CreateFunction
private final boolean replace;
private final List parameters;
private final String returnType;
+ private final Optional comment;
private final RoutineCharacteristics characteristics;
private final Expression body;
- public CreateFunction(QualifiedName functionName, boolean replace, List parameters, String returnType, RoutineCharacteristics characteristics, Expression body)
+ public CreateFunction(QualifiedName functionName, boolean replace, List parameters, String returnType, Optional comment, RoutineCharacteristics characteristics, Expression body)
{
- this(Optional.empty(), replace, functionName, parameters, returnType, characteristics, body);
+ this(Optional.empty(), replace, functionName, parameters, returnType, comment, characteristics, body);
}
- public CreateFunction(NodeLocation location, boolean replace, QualifiedName functionName, List parameters, String returnType, RoutineCharacteristics characteristics, Expression body)
+ public CreateFunction(NodeLocation location, boolean replace, QualifiedName functionName, List parameters, String returnType, Optional comment, RoutineCharacteristics characteristics, Expression body)
{
- this(Optional.of(location), replace, functionName, parameters, returnType, characteristics, body);
+ this(Optional.of(location), replace, functionName, parameters, returnType, comment, characteristics, body);
}
- private CreateFunction(Optional location, boolean replace, QualifiedName functionName, List parameters, String returnType, RoutineCharacteristics characteristics, Expression body)
+ private CreateFunction(Optional location, boolean replace, QualifiedName functionName, List parameters, String returnType, Optional comment, RoutineCharacteristics characteristics, Expression body)
{
super(location);
this.functionName = requireNonNull(functionName, "functionName is null");
this.replace = replace;
this.parameters = ImmutableList.copyOf(requireNonNull(parameters, "parameters is null"));
this.returnType = requireNonNull(returnType, "returnType is null");
+ this.comment = requireNonNull(comment, "comment is null");
this.characteristics = requireNonNull(characteristics, "routineCharacteristics is null");
this.body = requireNonNull(body, "body is null");
}
@@ -73,6 +75,11 @@ public String getReturnType()
return returnType;
}
+ public Optional getComment()
+ {
+ return comment;
+ }
+
public RoutineCharacteristics getCharacteristics()
{
return characteristics;
@@ -100,7 +107,7 @@ public List getChildren()
@Override
public int hashCode()
{
- return Objects.hash(functionName, parameters, returnType, characteristics, body);
+ return Objects.hash(functionName, parameters, returnType, comment, characteristics, body);
}
@Override
@@ -116,6 +123,7 @@ public boolean equals(Object obj)
return Objects.equals(functionName, o.functionName) &&
Objects.equals(parameters, o.parameters) &&
Objects.equals(returnType, o.returnType) &&
+ Objects.equals(comment, o.comment) &&
Objects.equals(characteristics, o.characteristics) &&
Objects.equals(body, o.body);
}
@@ -127,6 +135,7 @@ public String toString()
.add("functionName", functionName)
.add("parameters", parameters)
.add("returnType", returnType)
+ .add("comment", comment)
.add("characteristics", characteristics)
.add("body", body)
.toString();
diff --git a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java
index aa836083fb3b3..9d4aaf0eefba8 100644
--- a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java
+++ b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java
@@ -1428,6 +1428,7 @@ public void testCreateFunction()
assertStatement(
"CREATE FUNCTION tan (x double)\n" +
"RETURNS double\n" +
+ "COMMENT 'tangent trigonometric function'\n" +
"LANGUAGE SQL\n" +
"DETERMINISTIC\n" +
"RETURNS NULL ON NULL INPUT\n" +
@@ -1437,6 +1438,7 @@ public void testCreateFunction()
false,
ImmutableList.of(new SqlParameterDeclaration(identifier("x"), "double")),
"double",
+ Optional.of("tangent trigonometric function"),
new RoutineCharacteristics(SQL, DETERMINISTIC, RETURNS_NULL_ON_NULL_INPUT),
new ArithmeticBinaryExpression(
DIVIDE,
@@ -1448,6 +1450,7 @@ public void testCreateFunction()
true,
ImmutableList.of(),
"double",
+ Optional.empty(),
new RoutineCharacteristics(SQL, NOT_DETERMINISTIC, CALLED_ON_NULL_INPUT),
new FunctionCall(QualifiedName.of("rand"), ImmutableList.of()));
assertStatement(
diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java
index bc50cb7e7d8d1..df723bbaf057d 100644
--- a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java
+++ b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManager.java
@@ -13,36 +13,49 @@
*/
package com.facebook.presto.spi.function;
-import com.facebook.presto.spi.QueryId;
import com.facebook.presto.spi.api.Experimental;
import com.facebook.presto.spi.relation.FullyQualifiedName;
import java.util.Collection;
-import java.util.List;
+import java.util.Optional;
@Experimental
-public interface FunctionNamespaceManager
+public interface FunctionNamespaceManager
{
- void addFunctions(List extends SqlFunction> functions);
+ String getName();
- List listFunctions();
+ /**
+ * Start a transaction.
+ */
+ FunctionNamespaceTransactionHandle beginTransaction();
+
+ /**
+ * Commit the transaction. Will be called at most once and will not be called if
+ * {@link #rollback(FunctionNamespaceTransactionHandle)} is called.
+ */
+ void commit(FunctionNamespaceTransactionHandle transactionHandle);
/**
- * Ideally function namespaces should support transactions like connectors do, and getCandidates should be transaction-aware.
- * queryId serves as a transaction ID before proper support for transaction is introduced.
- * TODO Support transaction in function namespaces
+ * Rollback the transaction. Will be called at most once and will not be called if
+ * {@link #commit(FunctionNamespaceTransactionHandle)} is called.
*/
- Collection getCandidates(QueryId queryId, FullyQualifiedName name);
+ void rollback(FunctionNamespaceTransactionHandle transactionHandle);
/**
- * If a SqlFunction for a given signature is returned from {@link #getCandidates(QueryId, FullyQualifiedName)}
- * for a given queryId, getFunctionHandle with the same queryId should return a valid FunctionHandle, even if the function
- * is deleted. Multiple calls of this function with the same parameters should return the same FunctionHandle.
- * queryId serves as a transaction ID before proper support for transaction is introduced.
- * TODO Support transaction in function namespaces
- * @return FunctionHandle or null if the namespace manager does not manage any function with the given signature.
+ * Create or replace the specified function.
+ * TODO: Support transaction
*/
- FunctionHandle getFunctionHandle(QueryId queryId, Signature signature);
+ void createFunction(F function, boolean replace);
+
+ /**
+ * List all functions managed by the {@link FunctionNamespaceManager}.
+ * TODO: Support transaction
+ */
+ Collection listFunctions();
+
+ Collection getFunctions(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, FullyQualifiedName functionName);
+
+ FunctionHandle getFunctionHandle(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, Signature signature);
FunctionMetadata getFunctionMetadata(FunctionHandle functionHandle);
}
diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManagerFactory.java b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManagerFactory.java
index 496cb6ebd0261..fb388ca9264ce 100644
--- a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManagerFactory.java
+++ b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceManagerFactory.java
@@ -21,5 +21,5 @@ public interface FunctionNamespaceManagerFactory
FunctionHandleResolver getHandleResolver();
- FunctionNamespaceManager create(Map config);
+ FunctionNamespaceManager> create(Map config);
}
diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceTransactionHandle.java b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceTransactionHandle.java
new file mode 100644
index 0000000000000..69df8227f8758
--- /dev/null
+++ b/presto-spi/src/main/java/com/facebook/presto/spi/function/FunctionNamespaceTransactionHandle.java
@@ -0,0 +1,18 @@
+/*
+ * 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.facebook.presto.spi.function;
+
+public interface FunctionNamespaceTransactionHandle
+{
+}
diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/function/SqlFunction.java b/presto-spi/src/main/java/com/facebook/presto/spi/function/SqlFunction.java
index 0e7676f56f6e1..a21c07a122623 100644
--- a/presto-spi/src/main/java/com/facebook/presto/spi/function/SqlFunction.java
+++ b/presto-spi/src/main/java/com/facebook/presto/spi/function/SqlFunction.java
@@ -21,10 +21,7 @@ public interface SqlFunction
boolean isDeterministic();
- default boolean isCalledOnNullInput()
- {
- return false;
- };
+ boolean isCalledOnNullInput();
String getDescription();
}
diff --git a/presto-sql-function/pom.xml b/presto-sql-function/pom.xml
new file mode 100644
index 0000000000000..04f922c7bf6da
--- /dev/null
+++ b/presto-sql-function/pom.xml
@@ -0,0 +1,57 @@
+
+
+
+ presto-root
+ com.facebook.presto
+ 0.228-SNAPSHOT
+
+ 4.0.0
+
+ presto-sql-function
+ presto-sql-function
+
+
+ ${project.parent.basedir}
+
+
+
+
+ com.facebook.presto
+ presto-spi
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
+ com.google.guava
+ guava
+
+
+
+ io.airlift
+ configuration
+
+
+
+ io.airlift
+ units
+
+
+
+
+ org.testng
+ testng
+ test
+
+
+
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/AbstractSqlInvokedFunctionNamespaceManager.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/AbstractSqlInvokedFunctionNamespaceManager.java
new file mode 100644
index 0000000000000..60b2650b71222
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/AbstractSqlInvokedFunctionNamespaceManager.java
@@ -0,0 +1,159 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.function.FunctionHandle;
+import com.facebook.presto.spi.function.FunctionMetadata;
+import com.facebook.presto.spi.function.FunctionNamespaceManager;
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
+import com.facebook.presto.spi.function.Signature;
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public abstract class AbstractSqlInvokedFunctionNamespaceManager
+ implements FunctionNamespaceManager
+{
+ private final ConcurrentMap transactions = new ConcurrentHashMap<>();
+
+ private final LoadingCache> functions;
+ private final LoadingCache metadataByHandle;
+
+ public AbstractSqlInvokedFunctionNamespaceManager(SqlInvokedFunctionNamespaceManagerConfig config)
+ {
+ this.functions = CacheBuilder.newBuilder()
+ .expireAfterWrite(config.getFunctionCacheExpiration().toMillis(), MILLISECONDS)
+ .build(new CacheLoader>()
+ {
+ @Override
+ public Collection load(FullyQualifiedName functionName)
+ {
+ Collection functions = fetchFunctionsDirect(functionName);
+ for (SqlInvokedRegularFunction function : functions) {
+ metadataByHandle.put(function.getRequiredFunctionHandle(), sqlInvokedFunctionToMetadata(function));
+ }
+ return functions;
+ }
+ });
+ this.metadataByHandle = CacheBuilder.newBuilder()
+ .expireAfterWrite(config.getMetadataCacheExpiration().toMillis(), MILLISECONDS)
+ .build(new CacheLoader()
+ {
+ @Override
+ public FunctionMetadata load(SqlInvokedRegularFunctionHandle functionHandle)
+ {
+ return fetchFunctionMetadataDirect(functionHandle);
+ }
+ });
+ }
+
+ protected abstract Collection fetchFunctionsDirect(FullyQualifiedName functionName);
+
+ protected abstract FunctionMetadata fetchFunctionMetadataDirect(SqlInvokedRegularFunctionHandle functionHandle);
+
+ @Override
+ public final FunctionNamespaceTransactionHandle beginTransaction()
+ {
+ UuidFunctionNamespaceTransactionHandle transactionHandle = UuidFunctionNamespaceTransactionHandle.create();
+ transactions.put(transactionHandle, new FunctionCollection());
+ return transactionHandle;
+ }
+
+ @Override
+ public final void commit(FunctionNamespaceTransactionHandle transactionHandle)
+ {
+ // Transactional commit is not supported yet.
+ transactions.remove(transactionHandle);
+ }
+
+ @Override
+ public final void rollback(FunctionNamespaceTransactionHandle transactionHandle)
+ {
+ // Transactional rollback is not supported yet.
+ transactions.remove(transactionHandle);
+ }
+
+ @Override
+ public final Collection getFunctions(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, FullyQualifiedName functionName)
+ {
+ checkArgument(transactionHandle.isPresent(), "missing transactionHandle");
+ return transactions.get(transactionHandle.get()).loadAndGetFunctionsTransactional(functionName);
+ }
+
+ @Override
+ public final FunctionHandle getFunctionHandle(Optional extends FunctionNamespaceTransactionHandle> transactionHandle, Signature signature)
+ {
+ checkArgument(transactionHandle.isPresent(), "missing transactionHandle");
+ SqlFunctionId functionId = new SqlFunctionId(signature.getName(), signature.getArgumentTypes());
+ return transactions.get(transactionHandle.get()).getFunctionHandle(functionId);
+ }
+
+ @Override
+ public final FunctionMetadata getFunctionMetadata(FunctionHandle functionHandle)
+ {
+ checkArgument(functionHandle instanceof SqlInvokedRegularFunctionHandle, "Unsupported FunctionHandle type '%s'", functionHandle.getClass().getSimpleName());
+ return metadataByHandle.getUnchecked((SqlInvokedRegularFunctionHandle) functionHandle);
+ }
+
+ protected static FunctionMetadata sqlInvokedFunctionToMetadata(SqlInvokedRegularFunction function)
+ {
+ return new FunctionMetadata(
+ function.getSignature().getName(),
+ function.getSignature().getArgumentTypes(),
+ function.getSignature().getReturnType(),
+ SCALAR,
+ function.isDeterministic(),
+ function.isCalledOnNullInput());
+ }
+
+ private Collection fetchFunctions(FullyQualifiedName functionName)
+ {
+ return functions.getUnchecked(functionName);
+ }
+
+ private class FunctionCollection
+ {
+ @GuardedBy("this")
+ private final Map> functions = new ConcurrentHashMap<>();
+
+ @GuardedBy("this")
+ private final Map functionHandles = new ConcurrentHashMap<>();
+
+ public synchronized Collection loadAndGetFunctionsTransactional(FullyQualifiedName functionName)
+ {
+ Collection functions = this.functions.computeIfAbsent(functionName, AbstractSqlInvokedFunctionNamespaceManager.this::fetchFunctions);
+ functionHandles.putAll(functions.stream().collect(toImmutableMap(SqlInvokedRegularFunction::getFunctionId, SqlInvokedRegularFunction::getRequiredFunctionHandle)));
+ return functions;
+ }
+
+ public synchronized FunctionHandle getFunctionHandle(SqlFunctionId functionId)
+ {
+ return functionHandles.get(functionId);
+ }
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/RoutineCharacteristics.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/RoutineCharacteristics.java
new file mode 100644
index 0000000000000..64a6540d1a3b3
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/RoutineCharacteristics.java
@@ -0,0 +1,97 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import java.util.Objects;
+
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.Determinism.DETERMINISTIC;
+import static com.facebook.presto.sqlfunction.RoutineCharacteristics.NullCallClause.CALLED_ON_NULL_INPUT;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+public class RoutineCharacteristics
+{
+ public enum Language
+ {
+ SQL;
+ }
+
+ public enum Determinism
+ {
+ DETERMINISTIC,
+ NOT_DETERMINISTIC;
+ }
+
+ public enum NullCallClause
+ {
+ RETURNS_NULL_ON_NULL_INPUT,
+ CALLED_ON_NULL_INPUT;
+ }
+
+ private final Language language;
+ private final Determinism determinism;
+ private final NullCallClause nullCallClause;
+
+ public RoutineCharacteristics(
+ Language language,
+ Determinism determinism,
+ NullCallClause nullCallClause)
+ {
+ this.language = requireNonNull(language, "language is null");
+ this.determinism = requireNonNull(determinism, "determinism is null");
+ this.nullCallClause = requireNonNull(nullCallClause, "nullCallClause is null");
+ }
+
+ public Language getLanguage()
+ {
+ return language;
+ }
+
+ public boolean isDeterministic()
+ {
+ return determinism == DETERMINISTIC;
+ }
+
+ public boolean isCalledOnNullInput()
+ {
+ return nullCallClause == CALLED_ON_NULL_INPUT;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RoutineCharacteristics that = (RoutineCharacteristics) o;
+ return language == that.language
+ && determinism == that.determinism
+ && nullCallClause == that.nullCallClause;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(language, determinism, nullCallClause);
+ }
+
+ @Override
+ public String toString()
+ {
+ return format("(%s, %s, %s)", language, determinism, nullCallClause);
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlFunctionId.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlFunctionId.java
new file mode 100644
index 0000000000000..5d03ec25e07ef
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlFunctionId.java
@@ -0,0 +1,77 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.facebook.presto.spi.type.TypeSignature;
+
+import java.util.List;
+import java.util.Objects;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
+public class SqlFunctionId
+{
+ private final FullyQualifiedName name;
+ private final List argumentTypes;
+
+ public SqlFunctionId(
+ FullyQualifiedName name,
+ List argumentTypes)
+ {
+ this.name = requireNonNull(name, "name is null");
+ this.argumentTypes = requireNonNull(argumentTypes, "argumentTypes is null");
+ }
+
+ public FullyQualifiedName getName()
+ {
+ return name;
+ }
+
+ public List getArgumentTypes()
+ {
+ return argumentTypes;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ SqlFunctionId o = (SqlFunctionId) obj;
+ return Objects.equals(name, o.name)
+ && Objects.equals(argumentTypes, o.argumentTypes);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name, argumentTypes);
+ }
+
+ @Override
+ public String toString()
+ {
+ String arguments = argumentTypes.stream()
+ .map(Object::toString)
+ .collect(joining(", "));
+ return format("%s(%s)", name, arguments);
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedFunctionNamespaceManagerConfig.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedFunctionNamespaceManagerConfig.java
new file mode 100644
index 0000000000000..c7d1f3d3deedd
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedFunctionNamespaceManagerConfig.java
@@ -0,0 +1,53 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import io.airlift.configuration.Config;
+import io.airlift.units.Duration;
+import io.airlift.units.MinDuration;
+
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+public class SqlInvokedFunctionNamespaceManagerConfig
+{
+ private Duration functionCacheExpiration = new Duration(5, MINUTES);
+ private Duration metadataCacheExpiration = new Duration(8, HOURS);
+
+ @MinDuration("0ns")
+ public Duration getFunctionCacheExpiration()
+ {
+ return functionCacheExpiration;
+ }
+
+ @Config("function-cache-expiration")
+ public SqlInvokedFunctionNamespaceManagerConfig setFunctionCacheExpiration(Duration functionCacheExpiration)
+ {
+ this.functionCacheExpiration = functionCacheExpiration;
+ return this;
+ }
+
+ @MinDuration("0ns")
+ public Duration getMetadataCacheExpiration()
+ {
+ return metadataCacheExpiration;
+ }
+
+ @Config("metadata-cache-expiration")
+ public SqlInvokedFunctionNamespaceManagerConfig setMetadataCacheExpiration(Duration metadataCacheExpiration)
+ {
+ this.metadataCacheExpiration = metadataCacheExpiration;
+ return this;
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunction.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunction.java
new file mode 100644
index 0000000000000..061de88e0bc39
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunction.java
@@ -0,0 +1,188 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.function.Signature;
+import com.facebook.presto.spi.function.SqlFunction;
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.facebook.presto.spi.type.TypeSignature;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+
+public class SqlInvokedRegularFunction
+ implements SqlFunction
+{
+ private final List parameters;
+ private final Optional comment;
+ private final RoutineCharacteristics routineCharacteristics;
+ private final String body;
+
+ private final Signature signature;
+ private final SqlFunctionId functionId;
+ private final Optional functionHandle;
+
+ public SqlInvokedRegularFunction(
+ FullyQualifiedName functionName,
+ List parameters,
+ TypeSignature returnType,
+ Optional comment,
+ RoutineCharacteristics routineCharacteristics,
+ String body,
+ Optional version)
+ {
+ this.parameters = requireNonNull(parameters, "parameters is null");
+ this.comment = requireNonNull(comment, "comment is null");
+ this.routineCharacteristics = requireNonNull(routineCharacteristics, "routineCharacteristics is null");
+ this.body = requireNonNull(body, "body is null");
+
+ List argumentTypes = parameters.stream()
+ .map(SqlParameter::getType)
+ .collect(collectingAndThen(toList(), Collections::unmodifiableList));
+ this.signature = new Signature(functionName, SCALAR, returnType, argumentTypes);
+ this.functionId = new SqlFunctionId(functionName, argumentTypes);
+ this.functionHandle = version.map(v -> new SqlInvokedRegularFunctionHandle(functionName, argumentTypes, v));
+ }
+
+ public static SqlInvokedRegularFunction versioned(SqlInvokedRegularFunction function, long version)
+ {
+ if (function.getVersion().isPresent()) {
+ throw new IllegalArgumentException(format("function %s is already versioned", function.getVersion().get()));
+ }
+ return new SqlInvokedRegularFunction(
+ function.getSignature().getName(),
+ function.getParameters(),
+ function.getSignature().getReturnType(),
+ function.comment,
+ function.getRoutineCharacteristics(),
+ function.getBody(),
+ Optional.of(version));
+ }
+
+ @Override
+ public Signature getSignature()
+ {
+ return signature;
+ }
+
+ @Override
+ public boolean isHidden()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isDeterministic()
+ {
+ return routineCharacteristics.isDeterministic();
+ }
+
+ @Override
+ public boolean isCalledOnNullInput()
+ {
+ return routineCharacteristics.isCalledOnNullInput();
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return comment.orElse("");
+ }
+
+ public List getParameters()
+ {
+ return parameters;
+ }
+
+ public Optional getComment()
+ {
+ return comment;
+ }
+
+ public RoutineCharacteristics getRoutineCharacteristics()
+ {
+ return routineCharacteristics;
+ }
+
+ public String getBody()
+ {
+ return body;
+ }
+
+ public SqlFunctionId getFunctionId()
+ {
+ return functionId;
+ }
+
+ public SqlInvokedRegularFunctionHandle getRequiredFunctionHandle()
+ {
+ checkState(functionHandle.isPresent(), "missing function handle");
+ return functionHandle.get();
+ }
+
+ public Optional getVersion()
+ {
+ return functionHandle.map(SqlInvokedRegularFunctionHandle::getVersion);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ SqlInvokedRegularFunction o = (SqlInvokedRegularFunction) obj;
+ return Objects.equals(parameters, o.parameters)
+ && Objects.equals(comment, o.comment)
+ && Objects.equals(routineCharacteristics, o.routineCharacteristics)
+ && Objects.equals(body, o.body)
+ && Objects.equals(signature, o.signature)
+ && Objects.equals(functionId, o.functionId)
+ && Objects.equals(functionHandle, o.functionHandle);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(parameters, comment, routineCharacteristics, body, signature, functionId, functionHandle);
+ }
+
+ @Override
+ public String toString()
+ {
+ return format(
+ "%s(%s):%s%s {%s} %s",
+ signature.getName(),
+ parameters.stream()
+ .map(Object::toString)
+ .collect(joining(",")),
+ signature.getReturnType(),
+ getVersion().map(version -> ":" + version).orElse(""),
+ body,
+ routineCharacteristics);
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunctionHandle.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunctionHandle.java
new file mode 100644
index 0000000000000..b505aa385c2f6
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlInvokedRegularFunctionHandle.java
@@ -0,0 +1,99 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.function.FunctionHandle;
+import com.facebook.presto.spi.relation.FullyQualifiedName;
+import com.facebook.presto.spi.type.TypeSignature;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+import java.util.Objects;
+
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
+public class SqlInvokedRegularFunctionHandle
+ implements FunctionHandle
+{
+ private final FullyQualifiedName name;
+ private final List argumentTypes;
+ private final long version;
+
+ @JsonCreator
+ public SqlInvokedRegularFunctionHandle(
+ @JsonProperty("name") FullyQualifiedName name,
+ @JsonProperty("argumentTypes") List argumentTypes,
+ @JsonProperty("version") long version)
+ {
+ this.name = requireNonNull(name, "name is null");
+ this.argumentTypes = requireNonNull(argumentTypes, "argumentTypes is null");
+ this.version = version;
+ }
+
+ @JsonProperty
+ public FullyQualifiedName getName()
+ {
+ return name;
+ }
+
+ @JsonProperty
+ public List getArgumentTypes()
+ {
+ return argumentTypes;
+ }
+
+ @JsonProperty
+ public long getVersion()
+ {
+ return version;
+ }
+
+ @Override
+ public FullyQualifiedName.Prefix getFunctionNamespace()
+ {
+ return name.getPrefix();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ SqlInvokedRegularFunctionHandle o = (SqlInvokedRegularFunctionHandle) obj;
+ return Objects.equals(name, o.name)
+ && Objects.equals(argumentTypes, o.argumentTypes)
+ && Objects.equals(version, o.version);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name, argumentTypes, version);
+ }
+
+ @Override
+ public String toString()
+ {
+ String arguments = argumentTypes.stream()
+ .map(Object::toString)
+ .collect(joining(", "));
+ return String.format("%s(%s):%s", name, arguments, version);
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlParameter.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlParameter.java
new file mode 100644
index 0000000000000..535ee31472b85
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/SqlParameter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.type.TypeSignature;
+
+import java.util.Objects;
+
+import static java.util.Objects.requireNonNull;
+
+public class SqlParameter
+{
+ private final String name;
+ private final TypeSignature type;
+
+ public SqlParameter(String name, TypeSignature type)
+ {
+ this.name = requireNonNull(name, "name is null");
+ this.type = requireNonNull(type, "type is null");
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public TypeSignature getType()
+ {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ SqlParameter o = (SqlParameter) obj;
+ return Objects.equals(name, o.name)
+ && Objects.equals(type, o.type);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name, type);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s %s", name, type);
+ }
+}
diff --git a/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/UuidFunctionNamespaceTransactionHandle.java b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/UuidFunctionNamespaceTransactionHandle.java
new file mode 100644
index 0000000000000..609b338b45ed6
--- /dev/null
+++ b/presto-sql-function/src/main/java/com/facebook/presto/sqlfunction/UuidFunctionNamespaceTransactionHandle.java
@@ -0,0 +1,71 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import static java.util.Objects.requireNonNull;
+
+public class UuidFunctionNamespaceTransactionHandle
+ implements FunctionNamespaceTransactionHandle
+{
+ private final UUID uuid;
+
+ private UuidFunctionNamespaceTransactionHandle(UUID uuid)
+ {
+ this.uuid = requireNonNull(uuid, "uuid is null");
+ }
+
+ public static UuidFunctionNamespaceTransactionHandle create()
+ {
+ return new UuidFunctionNamespaceTransactionHandle(UUID.randomUUID());
+ }
+
+ @JsonCreator
+ public static UuidFunctionNamespaceTransactionHandle valueOf(String value)
+ {
+ return new UuidFunctionNamespaceTransactionHandle(UUID.fromString(value));
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final UuidFunctionNamespaceTransactionHandle o = (UuidFunctionNamespaceTransactionHandle) obj;
+ return Objects.equals(uuid, o.uuid);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(uuid);
+ }
+
+ @Override
+ @JsonValue
+ public String toString()
+ {
+ return uuid.toString();
+ }
+}
diff --git a/presto-sql-function/src/test/java/com/facebook/presto/sqlfunction/TestSqlInvokedFunctionNamespaceManagerConfig.java b/presto-sql-function/src/test/java/com/facebook/presto/sqlfunction/TestSqlInvokedFunctionNamespaceManagerConfig.java
new file mode 100644
index 0000000000000..4edbb180b6e5f
--- /dev/null
+++ b/presto-sql-function/src/test/java/com/facebook/presto/sqlfunction/TestSqlInvokedFunctionNamespaceManagerConfig.java
@@ -0,0 +1,51 @@
+/*
+ * 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.facebook.presto.sqlfunction;
+
+import com.google.common.collect.ImmutableMap;
+import io.airlift.units.Duration;
+import org.testng.annotations.Test;
+
+import java.util.Map;
+
+import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping;
+import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults;
+import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+public class TestSqlInvokedFunctionNamespaceManagerConfig
+{
+ @Test
+ public void testDefault()
+ {
+ assertRecordedDefaults(recordDefaults(SqlInvokedFunctionNamespaceManagerConfig.class)
+ .setFunctionCacheExpiration(new Duration(5, MINUTES))
+ .setMetadataCacheExpiration(new Duration(8, HOURS)));
+ }
+
+ @Test
+ public void testExplicitPropertyMappings()
+ {
+ Map properties = new ImmutableMap.Builder()
+ .put("function-cache-expiration", "10m")
+ .put("metadata-cache-expiration", "4h")
+ .build();
+ SqlInvokedFunctionNamespaceManagerConfig expected = new SqlInvokedFunctionNamespaceManagerConfig()
+ .setFunctionCacheExpiration(new Duration(10, MINUTES))
+ .setMetadataCacheExpiration(new Duration(4, HOURS));
+
+ assertFullMapping(properties, expected);
+ }
+}
diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
index b68c99b9c4ba3..7d342a5b2d494 100644
--- a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
+++ b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java
@@ -15,9 +15,9 @@
import com.facebook.presto.Session;
import com.facebook.presto.SystemSessionProperties;
+import com.facebook.presto.metadata.BuiltInFunction;
import com.facebook.presto.metadata.FunctionListBuilder;
import com.facebook.presto.spi.PrestoException;
-import com.facebook.presto.spi.function.SqlFunction;
import com.facebook.presto.spi.session.PropertyMetadata;
import com.facebook.presto.spi.type.Decimals;
import com.facebook.presto.spi.type.SqlTimestampWithTimeZone;
@@ -103,7 +103,7 @@ public abstract class AbstractTestQueries
extends AbstractTestQueryFramework
{
// We can just use the default type registry, since we don't use any parametric types
- protected static final List CUSTOM_FUNCTIONS = new FunctionListBuilder()
+ protected static final List CUSTOM_FUNCTIONS = new FunctionListBuilder()
.aggregates(CustomSum.class)
.window(CustomRank.class)
.scalars(CustomAdd.class)
@@ -4107,7 +4107,7 @@ public void testWindowNoChannels()
public void testInvalidWindowFunction()
{
assertQueryFails("SELECT abs(x) OVER ()\n" +
- "FROM (VALUES (1), (2), (3)) t(x)",
+ "FROM (VALUES (1), (2), (3)) t(x)",
"line 1:1: Not a window function: abs");
}
diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java
index 1f9bc39929669..e8deca804c2e3 100644
--- a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java
+++ b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java
@@ -167,7 +167,7 @@ private DistributedQueryRunner(
start = System.nanoTime();
for (TestingPrestoServer server : servers) {
- server.getMetadata().addFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS);
+ server.getMetadata().registerBuiltInFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS);
}
log.info("Added functions in %s", nanosSince(start).convertToMostSuccinctTimeUnit());
diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/StandaloneQueryRunner.java b/presto-tests/src/main/java/com/facebook/presto/tests/StandaloneQueryRunner.java
index 876de3376e56a..3d6285e2ff614 100644
--- a/presto-tests/src/main/java/com/facebook/presto/tests/StandaloneQueryRunner.java
+++ b/presto-tests/src/main/java/com/facebook/presto/tests/StandaloneQueryRunner.java
@@ -75,7 +75,7 @@ public StandaloneQueryRunner(Session defaultSession)
refreshNodes();
- server.getMetadata().addFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS);
+ server.getMetadata().registerBuiltInFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS);
SessionPropertyManager sessionPropertyManager = server.getMetadata().getSessionPropertyManager();
sessionPropertyManager.addSystemSessionProperties(TEST_SYSTEM_PROPERTIES);
diff --git a/presto-tests/src/test/java/com/facebook/presto/tests/TestLocalQueries.java b/presto-tests/src/test/java/com/facebook/presto/tests/TestLocalQueries.java
index 6a0bb87757902..1a3d62158eb0f 100644
--- a/presto-tests/src/test/java/com/facebook/presto/tests/TestLocalQueries.java
+++ b/presto-tests/src/test/java/com/facebook/presto/tests/TestLocalQueries.java
@@ -70,7 +70,7 @@ public static LocalQueryRunner createLocalQueryRunner()
new TpchConnectorFactory(1),
ImmutableMap.of());
- localQueryRunner.getMetadata().addFunctions(CUSTOM_FUNCTIONS);
+ localQueryRunner.getMetadata().registerBuiltInFunctions(CUSTOM_FUNCTIONS);
SessionPropertyManager sessionPropertyManager = localQueryRunner.getMetadata().getSessionPropertyManager();
sessionPropertyManager.addSystemSessionProperties(TEST_SYSTEM_PROPERTIES);
diff --git a/presto-tests/src/test/java/com/facebook/presto/tests/TestQueryPlanDeterminism.java b/presto-tests/src/test/java/com/facebook/presto/tests/TestQueryPlanDeterminism.java
index 05fcd17b83d55..3c72675416d1a 100644
--- a/presto-tests/src/test/java/com/facebook/presto/tests/TestQueryPlanDeterminism.java
+++ b/presto-tests/src/test/java/com/facebook/presto/tests/TestQueryPlanDeterminism.java
@@ -71,7 +71,7 @@ private static LocalQueryRunner createLocalQueryRunner()
new TpchConnectorFactory(1),
ImmutableMap.of());
- localQueryRunner.getMetadata().addFunctions(CUSTOM_FUNCTIONS);
+ localQueryRunner.getMetadata().registerBuiltInFunctions(CUSTOM_FUNCTIONS);
SessionPropertyManager sessionPropertyManager = localQueryRunner.getMetadata().getSessionPropertyManager();
sessionPropertyManager.addSystemSessionProperties(TEST_SYSTEM_PROPERTIES);
diff --git a/presto-verifier/pom.xml b/presto-verifier/pom.xml
index 95fb05ba063b6..979619358ff0a 100644
--- a/presto-verifier/pom.xml
+++ b/presto-verifier/pom.xml
@@ -94,6 +94,11 @@
bootstrap
+
+ io.airlift
+ concurrent
+
+
io.airlift
configuration
diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/Column.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/Column.java
index d27aded5acac2..c00dd65f5540e 100644
--- a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/Column.java
+++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/Column.java
@@ -13,14 +13,10 @@
*/
package com.facebook.presto.verifier.framework;
-import com.facebook.presto.block.BlockEncodingManager;
-import com.facebook.presto.metadata.FunctionManager;
-import com.facebook.presto.metadata.HandleResolver;
import com.facebook.presto.spi.type.ArrayType;
import com.facebook.presto.spi.type.Type;
-import com.facebook.presto.sql.analyzer.FeaturesConfig;
+import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.sql.tree.Identifier;
-import com.facebook.presto.type.TypeRegistry;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
@@ -48,11 +44,6 @@ public enum Category
}
private static final Set FLOATING_POINT_TYPES = ImmutableSet.of(DOUBLE, REAL);
- private static final TypeRegistry typeRegistry = new TypeRegistry();
-
- static {
- new FunctionManager(typeRegistry, new BlockEncodingManager(typeRegistry), new FeaturesConfig(), new HandleResolver());
- }
private final String name;
private final Category category;
@@ -86,10 +77,10 @@ public Type getType()
return type;
}
- public static Column fromResultSet(ResultSet resultSet)
+ public static Column fromResultSet(TypeManager typeManager, ResultSet resultSet)
throws SQLException
{
- Type type = typeRegistry.getType(parseTypeSignature(resultSet.getString("Type")));
+ Type type = typeManager.getType(parseTypeSignature(resultSet.getString("Type")));
Category category;
if (FLOATING_POINT_TYPES.contains(type)) {
category = FLOATING_POINT;
diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/DataVerification.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/DataVerification.java
index 6279dcaa5afb9..3059bf28336a4 100644
--- a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/DataVerification.java
+++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/DataVerification.java
@@ -13,6 +13,7 @@
*/
package com.facebook.presto.verifier.framework;
+import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.sql.tree.QualifiedName;
import com.facebook.presto.sql.tree.Query;
import com.facebook.presto.sql.tree.ShowColumns;
@@ -52,6 +53,7 @@
public class DataVerification
extends AbstractVerification
{
+ private final TypeManager typeManager;
private final ChecksumValidator checksumValidator;
private final LimitQueryDeterminismAnalyzer limitQueryDeterminismAnalyzer;
@@ -63,10 +65,12 @@ public DataVerification(
FailureResolverManager failureResolverManager,
VerificationContext verificationContext,
VerifierConfig verifierConfig,
+ TypeManager typeManager,
ChecksumValidator checksumValidator,
LimitQueryDeterminismAnalyzer limitQueryDeterminismAnalyzer)
{
super(verificationResubmitter, prestoAction, sourceQuery, queryRewriter, failureResolverManager, verificationContext, verifierConfig);
+ this.typeManager = requireNonNull(typeManager, "typeManager is null");
this.checksumValidator = requireNonNull(checksumValidator, "checksumValidator is null");
this.limitQueryDeterminismAnalyzer = requireNonNull(limitQueryDeterminismAnalyzer, "limitQueryDeterminismAnalyzer is null");
}
@@ -192,7 +196,7 @@ private DeterminismAnalysis matchResultToDeterminism(MatchResult matchResult)
private List getColumns(QualifiedName tableName)
{
return getPrestoAction()
- .execute(new ShowColumns(tableName), DESCRIBE, Column::fromResultSet)
+ .execute(new ShowColumns(tableName), DESCRIBE, resultSet -> Column.fromResultSet(typeManager, resultSet))
.getResults();
}
diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerificationFactory.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerificationFactory.java
index b04a1839fdcf6..1b60d5f1cf17a 100644
--- a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerificationFactory.java
+++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerificationFactory.java
@@ -13,6 +13,7 @@
*/
package com.facebook.presto.verifier.framework;
+import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.verifier.annotation.ForTest;
import com.facebook.presto.verifier.checksum.ChecksumValidator;
@@ -41,6 +42,7 @@ public class VerificationFactory
private final PrestoResourceClient testResourceClient;
private final ChecksumValidator checksumValidator;
private final VerifierConfig verifierConfig;
+ private final TypeManager typeManager;
private final FailureResolverConfig failureResolverConfig;
@Inject
@@ -52,6 +54,7 @@ public VerificationFactory(
@ForTest PrestoResourceClient testResourceClient,
ChecksumValidator checksumValidator,
VerifierConfig verifierConfig,
+ TypeManager typeManager,
FailureResolverConfig failureResolverConfig)
{
this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
@@ -61,6 +64,7 @@ public VerificationFactory(
this.testResourceClient = requireNonNull(testResourceClient, "testResourceClient is null");
this.checksumValidator = requireNonNull(checksumValidator, "checksumValidator is null");
this.verifierConfig = requireNonNull(verifierConfig, "config is null");
+ this.typeManager = requireNonNull(typeManager, "typeManager is null");
this.failureResolverConfig = requireNonNull(failureResolverConfig, "failureResolverConfig is null");
}
@@ -86,6 +90,7 @@ public Verification get(VerificationResubmitter verificationResubmitter, SourceQ
failureResolverManager,
verificationContext,
verifierConfig,
+ typeManager,
checksumValidator,
limitQueryDeterminismAnalyzer);
default:
diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerifierModule.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerifierModule.java
index 195a7270b9f08..18444d5aa37d9 100644
--- a/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerifierModule.java
+++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/framework/VerifierModule.java
@@ -13,9 +13,23 @@
*/
package com.facebook.presto.verifier.framework;
+import com.facebook.presto.block.BlockEncodingManager;
+import com.facebook.presto.metadata.CatalogManager;
+import com.facebook.presto.metadata.FunctionManager;
+import com.facebook.presto.metadata.HandleJsonModule;
+import com.facebook.presto.spi.block.BlockEncoding;
+import com.facebook.presto.spi.block.BlockEncodingSerde;
+import com.facebook.presto.spi.type.Type;
+import com.facebook.presto.spi.type.TypeManager;
+import com.facebook.presto.sql.analyzer.FeaturesConfig;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.parser.SqlParserOptions;
import com.facebook.presto.sql.tree.Property;
+import com.facebook.presto.transaction.ForTransactionManager;
+import com.facebook.presto.transaction.InMemoryTransactionManager;
+import com.facebook.presto.transaction.TransactionManager;
+import com.facebook.presto.transaction.TransactionManagerConfig;
+import com.facebook.presto.type.TypeRegistry;
import com.facebook.presto.verifier.annotation.ForControl;
import com.facebook.presto.verifier.annotation.ForTest;
import com.facebook.presto.verifier.checksum.ChecksumValidator;
@@ -35,17 +49,26 @@
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.Provides;
+import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import io.airlift.configuration.AbstractConfigurationAwareModule;
import javax.inject.Provider;
+import javax.inject.Singleton;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;
import static com.google.inject.Scopes.SINGLETON;
+import static com.google.inject.multibindings.Multibinder.newSetBinder;
+import static io.airlift.concurrent.Threads.daemonThreadsNamed;
import static io.airlift.configuration.ConfigBinder.configBinder;
import static java.util.Objects.requireNonNull;
+import static java.util.concurrent.Executors.newCachedThreadPool;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
public class VerifierModule
extends AbstractConfigurationAwareModule
@@ -85,12 +108,35 @@ protected final void setup(Binder binder)
binder.bind(customQueryFilterClass).in(SINGLETON);
}
- install(new VerificationPrestoActionModule(exceptionClassifier));
- install(new VerificationQueryRewriterModule());
- install(new FailureResolverModule(failureResolverFactories));
+ // block encoding
+ binder.bind(BlockEncodingSerde.class).to(BlockEncodingManager.class).in(Scopes.SINGLETON);
+ newSetBinder(binder, BlockEncoding.class);
+
+ // catalog
+ binder.bind(CatalogManager.class).in(Scopes.SINGLETON);
+
+ // function
+ binder.bind(FunctionManager.class).in(SINGLETON);
+
+ // handle resolver
+ binder.install(new HandleJsonModule());
+ // parser
binder.bind(SqlParserOptions.class).toInstance(sqlParserOptions);
binder.bind(SqlParser.class).in(SINGLETON);
+
+ // transaction
+ configBinder(binder).bindConfig(TransactionManagerConfig.class);
+
+ // type
+ configBinder(binder).bindConfig(FeaturesConfig.class);
+ binder.bind(TypeManager.class).to(TypeRegistry.class).in(SINGLETON);
+ newSetBinder(binder, Type.class);
+
+ // verifier
+ install(new VerificationPrestoActionModule(exceptionClassifier));
+ install(new VerificationQueryRewriterModule());
+ install(new FailureResolverModule(failureResolverFactories));
binder.bind(VerificationManager.class).in(SINGLETON);
binder.bind(VerificationFactory.class).in(SINGLETON);
binder.bind(ChecksumValidator.class).in(SINGLETON);
@@ -128,4 +174,31 @@ public List> get()
return customVerificationFilters.build();
}
}
+
+ @Provides
+ @Singleton
+ @ForTransactionManager
+ public static ScheduledExecutorService createTransactionIdleCheckExecutor()
+ {
+ return newSingleThreadScheduledExecutor(daemonThreadsNamed("transaction-idle-check"));
+ }
+
+ @Provides
+ @Singleton
+ @ForTransactionManager
+ public static ExecutorService createTransactionFinishingExecutor()
+ {
+ return newCachedThreadPool(daemonThreadsNamed("transaction-finishing-%s"));
+ }
+
+ @Provides
+ @Singleton
+ public static TransactionManager createTransactionManager(
+ TransactionManagerConfig config,
+ CatalogManager catalogManager,
+ @ForTransactionManager ScheduledExecutorService idleCheckExecutor,
+ @ForTransactionManager ExecutorService finishingExecutor)
+ {
+ return InMemoryTransactionManager.create(config, idleCheckExecutor, catalogManager, finishingExecutor);
+ }
}
diff --git a/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestDataVerification.java b/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestDataVerification.java
index 089e60c2ccc58..d239a41c1b154 100644
--- a/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestDataVerification.java
+++ b/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestDataVerification.java
@@ -17,6 +17,7 @@
import com.facebook.presto.sql.parser.SqlParserOptions;
import com.facebook.presto.sql.tree.QualifiedName;
import com.facebook.presto.tests.StandaloneQueryRunner;
+import com.facebook.presto.type.TypeRegistry;
import com.facebook.presto.verifier.checksum.ChecksumValidator;
import com.facebook.presto.verifier.checksum.FloatingPointColumnValidator;
import com.facebook.presto.verifier.checksum.OrderableArrayColumnValidator;
@@ -109,6 +110,7 @@ private DataVerification createVerification(String controlQuery, String testQuer
new FailureResolverManager(ImmutableList.of()),
verificationContext,
verifierConfig,
+ new TypeRegistry(),
checksumValidator,
new LimitQueryDeterminismAnalyzer(prestoAction, verifierConfig));
}
diff --git a/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestVerificationManager.java b/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestVerificationManager.java
index 8487771f284de..9ca5f6fb495ea 100644
--- a/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestVerificationManager.java
+++ b/presto-verifier/src/test/java/com/facebook/presto/verifier/framework/TestVerificationManager.java
@@ -19,6 +19,7 @@
import com.facebook.presto.sql.parser.SqlParserOptions;
import com.facebook.presto.sql.tree.QualifiedName;
import com.facebook.presto.sql.tree.Statement;
+import com.facebook.presto.type.TypeRegistry;
import com.facebook.presto.verifier.checksum.ChecksumValidator;
import com.facebook.presto.verifier.checksum.FloatingPointColumnValidator;
import com.facebook.presto.verifier.checksum.OrderableArrayColumnValidator;
@@ -137,6 +138,7 @@ private static VerificationManager getVerificationManager(List sour
new MockPrestoResourceClient(),
new ChecksumValidator(new SimpleColumnValidator(), new FloatingPointColumnValidator(verifierConfig), new OrderableArrayColumnValidator()),
verifierConfig,
+ new TypeRegistry(),
new FailureResolverConfig().setEnabled(false)),
SQL_PARSER,
ImmutableSet.of(),