Skip to content

Commit 163e4e1

Browse files
pdabre12Pratik Joseph Dabre
authored andcommitted
Introduce getSqlInvokedFunctions SPI and BuiltInPluginFunctionNamespaceManager for registering sql invoked functions
1 parent 84ae840 commit 163e4e1

File tree

14 files changed

+474
-79
lines changed

14 files changed

+474
-79
lines changed

presto-main-base/src/main/java/com/facebook/presto/metadata/BuiltInFunctionHandle.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ public class BuiltInFunctionHandle
3030
implements FunctionHandle
3131
{
3232
private final Signature signature;
33+
private final boolean isBuiltInPluginFunction;
3334

3435
@JsonCreator
35-
public BuiltInFunctionHandle(@JsonProperty("signature") Signature signature)
36+
public BuiltInFunctionHandle(
37+
@JsonProperty("signature") Signature signature,
38+
@JsonProperty("isBuiltInPluginFunction") boolean isBuiltInPluginFunction)
3639
{
3740
this.signature = requireNonNull(signature, "signature is null");
3841
checkArgument(signature.getTypeVariableConstraints().isEmpty(), "%s has unbound type parameters", signature);
42+
this.isBuiltInPluginFunction = isBuiltInPluginFunction;
3943
}
4044

4145
@JsonProperty
@@ -62,6 +66,13 @@ public List<TypeSignature> getArgumentTypes()
6266
return signature.getArgumentTypes();
6367
}
6468

69+
@JsonProperty
70+
@Override
71+
public boolean isBuiltInPluginFunction()
72+
{
73+
return isBuiltInPluginFunction;
74+
}
75+
6576
@Override
6677
public CatalogSchemaName getCatalogSchemaName()
6778
{
@@ -78,13 +89,14 @@ public boolean equals(Object o)
7889
return false;
7990
}
8091
BuiltInFunctionHandle that = (BuiltInFunctionHandle) o;
81-
return Objects.equals(signature, that.signature);
92+
return Objects.equals(signature, that.signature)
93+
&& Objects.equals(isBuiltInPluginFunction, that.isBuiltInPluginFunction);
8294
}
8395

8496
@Override
8597
public int hashCode()
8698
{
87-
return Objects.hash(signature);
99+
return Objects.hash(signature, isBuiltInPluginFunction);
88100
}
89101

90102
@Override
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.facebook.presto.metadata;
15+
16+
import com.facebook.presto.common.Page;
17+
import com.facebook.presto.common.QualifiedObjectName;
18+
import com.facebook.presto.common.block.BlockEncodingSerde;
19+
import com.facebook.presto.common.function.SqlFunctionResult;
20+
import com.facebook.presto.common.type.TypeManager;
21+
import com.facebook.presto.common.type.UserDefinedType;
22+
import com.facebook.presto.spi.PrestoException;
23+
import com.facebook.presto.spi.function.AlterRoutineCharacteristics;
24+
import com.facebook.presto.spi.function.FunctionHandle;
25+
import com.facebook.presto.spi.function.FunctionMetadata;
26+
import com.facebook.presto.spi.function.FunctionNamespaceManager;
27+
import com.facebook.presto.spi.function.FunctionNamespaceTransactionHandle;
28+
import com.facebook.presto.spi.function.Parameter;
29+
import com.facebook.presto.spi.function.ScalarFunctionImplementation;
30+
import com.facebook.presto.spi.function.Signature;
31+
import com.facebook.presto.spi.function.SqlFunction;
32+
import com.facebook.presto.spi.function.SqlInvokedFunction;
33+
import com.facebook.presto.spi.function.SqlInvokedScalarFunctionImplementation;
34+
import com.google.common.base.Supplier;
35+
import com.google.common.base.Suppliers;
36+
import com.google.common.cache.CacheBuilder;
37+
import com.google.common.cache.CacheLoader;
38+
import com.google.common.cache.LoadingCache;
39+
import com.google.common.util.concurrent.UncheckedExecutionException;
40+
41+
import java.util.Collection;
42+
import java.util.List;
43+
import java.util.Optional;
44+
import java.util.concurrent.CompletableFuture;
45+
46+
import static com.facebook.presto.spi.function.FunctionImplementationType.SQL;
47+
import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
48+
import static com.google.common.base.Preconditions.checkArgument;
49+
import static com.google.common.base.Throwables.throwIfInstanceOf;
50+
import static com.google.common.collect.ImmutableList.toImmutableList;
51+
import static java.util.Collections.emptyList;
52+
import static java.util.Objects.requireNonNull;
53+
import static java.util.concurrent.TimeUnit.HOURS;
54+
55+
public class BuiltInPluginFunctionNamespaceManager
56+
implements FunctionNamespaceManager<SqlFunction>
57+
{
58+
private volatile FunctionMap functions = new FunctionMap();
59+
private final FunctionAndTypeManager functionAndTypeManager;
60+
private final Supplier<FunctionMap> cachedFunctions =
61+
Suppliers.memoize(this::checkForNamingConflicts);
62+
private final LoadingCache<Signature, SpecializedFunctionKey> specializedFunctionKeyCache;
63+
private final LoadingCache<SpecializedFunctionKey, ScalarFunctionImplementation> specializedScalarCache;
64+
65+
public BuiltInPluginFunctionNamespaceManager(FunctionAndTypeManager functionAndTypeManager)
66+
{
67+
this.functionAndTypeManager = requireNonNull(functionAndTypeManager, "functionAndTypeManager is null");
68+
specializedFunctionKeyCache = CacheBuilder.newBuilder()
69+
.maximumSize(1000)
70+
.expireAfterWrite(1, HOURS)
71+
.build(CacheLoader.from(this::doGetSpecializedFunctionKey));
72+
specializedScalarCache = CacheBuilder.newBuilder()
73+
.maximumSize(1000)
74+
.expireAfterWrite(1, HOURS)
75+
.build(CacheLoader.from(key -> {
76+
checkArgument(
77+
key.getFunction() instanceof SqlInvokedFunction,
78+
"Unsupported scalar function class: %s",
79+
key.getFunction().getClass());
80+
return new SqlInvokedScalarFunctionImplementation(((SqlInvokedFunction) key.getFunction()).getBody());
81+
}));
82+
}
83+
84+
public synchronized void registerPluginFunctions(List<? extends SqlFunction> functions)
85+
{
86+
checkForNamingConflicts(functions);
87+
this.functions = new FunctionMap(this.functions, functions);
88+
}
89+
90+
@Override
91+
public FunctionHandle getFunctionHandle(Optional<? extends FunctionNamespaceTransactionHandle> transactionHandle, Signature signature)
92+
{
93+
return new BuiltInFunctionHandle(signature, true);
94+
}
95+
96+
@Override
97+
public Collection<SqlFunction> getFunctions(Optional<? extends FunctionNamespaceTransactionHandle> transactionHandle, QualifiedObjectName functionName)
98+
{
99+
if (functions.list().isEmpty() ||
100+
(!functionName.getCatalogSchemaName().equals(functionAndTypeManager.getDefaultNamespace()))) {
101+
return emptyList();
102+
}
103+
return cachedFunctions.get().get(functionName);
104+
}
105+
106+
/**
107+
* likePattern / escape is not used for optimization, returning all functions.
108+
*/
109+
@Override
110+
public Collection<SqlFunction> listFunctions(Optional<String> likePattern, Optional<String> escape)
111+
{
112+
return cachedFunctions.get().list();
113+
}
114+
115+
public FunctionMetadata getFunctionMetadata(FunctionHandle functionHandle)
116+
{
117+
checkArgument(functionHandle instanceof BuiltInFunctionHandle, "Expect BuiltInFunctionHandle");
118+
Signature signature = ((BuiltInFunctionHandle) functionHandle).getSignature();
119+
SpecializedFunctionKey functionKey;
120+
try {
121+
functionKey = specializedFunctionKeyCache.getUnchecked(signature);
122+
}
123+
catch (UncheckedExecutionException e) {
124+
throwIfInstanceOf(e.getCause(), PrestoException.class);
125+
throw e;
126+
}
127+
SqlFunction function = functionKey.getFunction();
128+
checkArgument(function instanceof SqlInvokedFunction, "BuiltInPluginFunctionNamespaceManager only support SqlInvokedFunctions");
129+
SqlInvokedFunction sqlFunction = (SqlInvokedFunction) function;
130+
List<String> argumentNames = sqlFunction.getParameters().stream().map(Parameter::getName).collect(toImmutableList());
131+
return new FunctionMetadata(
132+
signature.getName(),
133+
signature.getArgumentTypes(),
134+
argumentNames,
135+
signature.getReturnType(),
136+
signature.getKind(),
137+
sqlFunction.getRoutineCharacteristics().getLanguage(),
138+
SQL,
139+
function.isDeterministic(),
140+
function.isCalledOnNullInput(),
141+
sqlFunction.getVersion(),
142+
sqlFunction.getComplexTypeFunctionDescriptor());
143+
}
144+
145+
public ScalarFunctionImplementation getScalarFunctionImplementation(FunctionHandle functionHandle)
146+
{
147+
checkArgument(functionHandle instanceof BuiltInFunctionHandle, "Expect BuiltInFunctionHandle");
148+
return getScalarFunctionImplementation(((BuiltInFunctionHandle) functionHandle).getSignature());
149+
}
150+
151+
@Override
152+
public void setBlockEncodingSerde(BlockEncodingSerde blockEncodingSerde)
153+
{
154+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support setting block encoding");
155+
}
156+
157+
@Override
158+
public FunctionNamespaceTransactionHandle beginTransaction()
159+
{
160+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support setting block encoding");
161+
}
162+
163+
@Override
164+
public void commit(FunctionNamespaceTransactionHandle transactionHandle)
165+
{
166+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support setting block encoding");
167+
}
168+
169+
@Override
170+
public void abort(FunctionNamespaceTransactionHandle transactionHandle)
171+
{
172+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support setting block encoding");
173+
}
174+
175+
@Override
176+
public void createFunction(SqlInvokedFunction function, boolean replace)
177+
{
178+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support setting block encoding");
179+
}
180+
181+
@Override
182+
public void dropFunction(QualifiedObjectName functionName, Optional parameterTypes, boolean exists)
183+
{
184+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support drop function");
185+
}
186+
187+
@Override
188+
public void alterFunction(QualifiedObjectName functionName, Optional parameterTypes, AlterRoutineCharacteristics alterRoutineCharacteristics)
189+
{
190+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not alter function");
191+
}
192+
193+
@Override
194+
public void addUserDefinedType(UserDefinedType userDefinedType)
195+
{
196+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support adding user defined types");
197+
}
198+
199+
@Override
200+
public Optional<UserDefinedType> getUserDefinedType(QualifiedObjectName typeName)
201+
{
202+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not support getting user defined types");
203+
}
204+
205+
@Override
206+
public CompletableFuture<SqlFunctionResult> executeFunction(String source, FunctionHandle functionHandle, Page input, List channels, TypeManager typeManager)
207+
{
208+
throw new UnsupportedOperationException("BuiltInPluginFunctionNamespaceManager does not execute function");
209+
}
210+
211+
private ScalarFunctionImplementation getScalarFunctionImplementation(Signature signature)
212+
{
213+
checkArgument(signature.getKind() == SCALAR, "%s is not a scalar function", signature);
214+
checkArgument(signature.getTypeVariableConstraints().isEmpty(), "%s has unbound type parameters", signature);
215+
216+
try {
217+
return specializedScalarCache.getUnchecked(getSpecializedFunctionKey(signature));
218+
}
219+
catch (UncheckedExecutionException e) {
220+
throwIfInstanceOf(e.getCause(), PrestoException.class);
221+
throw e;
222+
}
223+
}
224+
225+
private synchronized FunctionMap checkForNamingConflicts()
226+
{
227+
Optional<FunctionNamespaceManager<?>> functionNamespaceManager =
228+
functionAndTypeManager.getServingFunctionNamespaceManager(functionAndTypeManager.getDefaultNamespace());
229+
checkArgument(functionNamespaceManager.isPresent(), "Cannot find function namespace for catalog '%s'", functionAndTypeManager.getDefaultNamespace().getCatalogName());
230+
checkForNamingConflicts(functionNamespaceManager.get().listFunctions(Optional.empty(), Optional.empty()));
231+
return functions;
232+
}
233+
234+
private synchronized void checkForNamingConflicts(Collection<? extends SqlFunction> functions)
235+
{
236+
for (SqlFunction function : functions) {
237+
for (SqlFunction existingFunction : this.functions.list()) {
238+
checkArgument(!function.getSignature().equals(existingFunction.getSignature()), "Function already registered: %s", function.getSignature());
239+
}
240+
}
241+
}
242+
243+
private SpecializedFunctionKey doGetSpecializedFunctionKey(Signature signature)
244+
{
245+
return functionAndTypeManager.getSpecializedFunctionKey(signature, getFunctions(Optional.empty(), signature.getName()));
246+
}
247+
248+
private SpecializedFunctionKey getSpecializedFunctionKey(Signature signature)
249+
{
250+
try {
251+
return specializedFunctionKeyCache.getUnchecked(signature);
252+
}
253+
catch (UncheckedExecutionException e) {
254+
throwIfInstanceOf(e.getCause(), PrestoException.class);
255+
throw e;
256+
}
257+
}
258+
}

presto-main-base/src/main/java/com/facebook/presto/metadata/BuiltInTypeAndFunctionNamespaceManager.java

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,6 @@
292292
import com.google.common.cache.CacheLoader;
293293
import com.google.common.cache.LoadingCache;
294294
import com.google.common.collect.ImmutableList;
295-
import com.google.common.collect.ImmutableListMultimap;
296-
import com.google.common.collect.Multimap;
297-
import com.google.common.collect.Multimaps;
298295
import com.google.common.util.concurrent.UncheckedExecutionException;
299296
import io.airlift.slice.Slice;
300297

@@ -1133,7 +1130,7 @@ public Collection<SqlFunction> getFunctions(Optional<? extends FunctionNamespace
11331130
@Override
11341131
public FunctionHandle getFunctionHandle(Optional<? extends FunctionNamespaceTransactionHandle> transactionHandle, Signature signature)
11351132
{
1136-
return new BuiltInFunctionHandle(signature);
1133+
return new BuiltInFunctionHandle(signature, false);
11371134
}
11381135

11391136
@Override
@@ -1396,44 +1393,6 @@ private static class EmptyTransactionHandle
13961393
{
13971394
}
13981395

1399-
private static class FunctionMap
1400-
{
1401-
private final Multimap<QualifiedObjectName, SqlFunction> functions;
1402-
1403-
public FunctionMap()
1404-
{
1405-
functions = ImmutableListMultimap.of();
1406-
}
1407-
1408-
public FunctionMap(FunctionMap map, Iterable<? extends SqlFunction> functions)
1409-
{
1410-
this.functions = ImmutableListMultimap.<QualifiedObjectName, SqlFunction>builder()
1411-
.putAll(map.functions)
1412-
.putAll(Multimaps.index(functions, function -> function.getSignature().getName()))
1413-
.build();
1414-
1415-
// Make sure all functions with the same name are aggregations or none of them are
1416-
for (Map.Entry<QualifiedObjectName, Collection<SqlFunction>> entry : this.functions.asMap().entrySet()) {
1417-
Collection<SqlFunction> values = entry.getValue();
1418-
long aggregations = values.stream()
1419-
.map(function -> function.getSignature().getKind())
1420-
.filter(kind -> kind == AGGREGATE)
1421-
.count();
1422-
checkState(aggregations == 0 || aggregations == values.size(), "'%s' is both an aggregation and a scalar function", entry.getKey());
1423-
}
1424-
}
1425-
1426-
public List<SqlFunction> list()
1427-
{
1428-
return ImmutableList.copyOf(functions.values());
1429-
}
1430-
1431-
public Collection<SqlFunction> get(QualifiedObjectName name)
1432-
{
1433-
return functions.get(name);
1434-
}
1435-
}
1436-
14371396
/**
14381397
* TypeSignature but has overridden equals(). Here, we compare exact signature of any underlying distinct
14391398
* types. Some distinct types may have extra information on their lazily loaded parents, and same parent

0 commit comments

Comments
 (0)