Skip to content

Commit 3c4b4ae

Browse files
committed
Always evaluate built-in functions using the presto.default namespace
If the user has no specified a custom expression optimizer, expressions should be presumed to be in the presto.default namespace (which consists exclusively of Java functions).
1 parent 197d984 commit 3c4b4ae

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

presto-main-base/src/main/java/com/facebook/presto/sql/relational/RowExpressionOptimizer.java

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,34 @@
1313
*/
1414
package com.facebook.presto.sql.relational;
1515

16+
import com.facebook.presto.common.CatalogSchemaName;
17+
import com.facebook.presto.common.QualifiedObjectName;
1618
import com.facebook.presto.metadata.FunctionAndTypeManager;
1719
import com.facebook.presto.metadata.Metadata;
1820
import com.facebook.presto.spi.ConnectorSession;
21+
import com.facebook.presto.spi.relation.CallExpression;
1922
import com.facebook.presto.spi.relation.ExpressionOptimizer;
2023
import com.facebook.presto.spi.relation.RowExpression;
24+
import com.facebook.presto.spi.relation.RowExpressionVisitor;
2125
import com.facebook.presto.spi.relation.VariableReferenceExpression;
26+
import com.facebook.presto.sql.analyzer.TypeSignatureProvider;
2227
import com.facebook.presto.sql.planner.RowExpressionInterpreter;
2328

2429
import java.util.function.Function;
2530

31+
import static com.facebook.presto.metadata.BuiltInTypeAndFunctionNamespaceManager.JAVA_BUILTIN_NAMESPACE;
2632
import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.OPTIMIZED;
2733
import static com.facebook.presto.sql.planner.LiteralEncoder.toRowExpression;
34+
import static com.google.common.collect.ImmutableList.toImmutableList;
2835
import static java.util.Objects.requireNonNull;
36+
import static java.util.function.UnaryOperator.identity;
2937

3038
public final class RowExpressionOptimizer
3139
implements ExpressionOptimizer
3240
{
3341
private final FunctionAndTypeManager functionAndTypeManager;
42+
private final CatalogSchemaName defaultNamespace;
43+
private final Function<RowExpression, RowExpression> normalizeRowExpression;
3444

3545
public RowExpressionOptimizer(Metadata metadata)
3646
{
@@ -39,22 +49,73 @@ public RowExpressionOptimizer(Metadata metadata)
3949

4050
public RowExpressionOptimizer(FunctionAndTypeManager functionAndTypeManager)
4151
{
52+
this.defaultNamespace = requireNonNull(functionAndTypeManager, "functionMetadataManager is null").getDefaultNamespace();
4253
this.functionAndTypeManager = requireNonNull(functionAndTypeManager, "functionMetadataManager is null");
54+
if (!defaultNamespace.equals(JAVA_BUILTIN_NAMESPACE)) {
55+
this.normalizeRowExpression = rowExpression -> rowExpression.accept(new BuiltInFunctionNamespaceOverride(), null);
56+
}
57+
else {
58+
this.normalizeRowExpression = identity();
59+
}
4360
}
4461

4562
@Override
4663
public RowExpression optimize(RowExpression rowExpression, Level level, ConnectorSession session)
4764
{
4865
if (level.ordinal() <= OPTIMIZED.ordinal()) {
49-
return toRowExpression(rowExpression.getSourceLocation(), new RowExpressionInterpreter(rowExpression, functionAndTypeManager, session, level).optimize(), rowExpression.getType());
66+
RowExpressionInterpreter rowExpressionInterpreter = new RowExpressionInterpreter(
67+
normalizeRowExpression.apply(rowExpression),
68+
functionAndTypeManager,
69+
session,
70+
level);
71+
return toRowExpression(rowExpression.getSourceLocation(), rowExpressionInterpreter.optimize(), rowExpression.getType());
5072
}
5173
throw new IllegalArgumentException("Not supported optimization level: " + level);
5274
}
5375

5476
@Override
5577
public RowExpression optimize(RowExpression expression, Level level, ConnectorSession session, Function<VariableReferenceExpression, Object> variableResolver)
5678
{
57-
RowExpressionInterpreter interpreter = new RowExpressionInterpreter(expression, functionAndTypeManager, session, level);
79+
RowExpressionInterpreter interpreter = new RowExpressionInterpreter(
80+
normalizeRowExpression.apply(expression),
81+
functionAndTypeManager,
82+
session,
83+
level);
5884
return toRowExpression(expression.getSourceLocation(), interpreter.optimize(variableResolver::apply), expression.getType());
5985
}
86+
87+
/**
88+
* TODO: GIANT HACK
89+
* This class is a hack and should eventually be removed. It is used to ensure consistent constant folding behavior when the built-in
90+
* function namespace has been switched (for example, to native.default. in the case of native functions). This will no longer be needed
91+
* when the native sidecar is capable of providing its own expression optimizer.
92+
*/
93+
private class BuiltInFunctionNamespaceOverride
94+
implements RowExpressionVisitor<RowExpression, Void>
95+
{
96+
@Override
97+
public RowExpression visitExpression(RowExpression expression, Void context)
98+
{
99+
return expression;
100+
}
101+
102+
@Override
103+
public RowExpression visitCall(CallExpression call, Void context)
104+
{
105+
if (call.getFunctionHandle().getCatalogSchemaName().equals(defaultNamespace)) {
106+
call = new CallExpression(
107+
call.getSourceLocation(),
108+
call.getDisplayName(),
109+
functionAndTypeManager.lookupFunction(
110+
QualifiedObjectName.valueOf(JAVA_BUILTIN_NAMESPACE, call.getDisplayName()),
111+
call.getArguments().stream()
112+
.map(RowExpression::getType)
113+
.map(x -> new TypeSignatureProvider(x.getTypeSignature()))
114+
.collect(toImmutableList())),
115+
call.getType(),
116+
call.getArguments());
117+
}
118+
return call;
119+
}
120+
}
60121
}

presto-main-base/src/test/java/com/facebook/presto/sql/relational/TestRowExpressionOptimizer.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@
1313
*/
1414
package com.facebook.presto.sql.relational;
1515

16+
import com.facebook.presto.common.QualifiedObjectName;
1617
import com.facebook.presto.common.block.IntArrayBlock;
1718
import com.facebook.presto.common.type.ArrayType;
1819
import com.facebook.presto.common.type.RowType;
20+
import com.facebook.presto.metadata.BuiltInFunctionHandle;
1921
import com.facebook.presto.metadata.FunctionAndTypeManager;
2022
import com.facebook.presto.metadata.MetadataManager;
2123
import com.facebook.presto.spi.function.FunctionHandle;
24+
import com.facebook.presto.spi.function.Signature;
2225
import com.facebook.presto.spi.relation.CallExpression;
2326
import com.facebook.presto.spi.relation.ConstantExpression;
2427
import com.facebook.presto.spi.relation.RowExpression;
2528
import com.facebook.presto.spi.relation.SpecialFormExpression;
29+
import com.facebook.presto.sql.analyzer.FunctionsConfig;
2630
import com.google.common.collect.ImmutableList;
2731
import org.testng.annotations.AfterClass;
2832
import org.testng.annotations.BeforeClass;
@@ -34,6 +38,7 @@
3438
import static com.facebook.presto.common.function.OperatorType.EQUAL;
3539
import static com.facebook.presto.common.type.BigintType.BIGINT;
3640
import static com.facebook.presto.common.type.BooleanType.BOOLEAN;
41+
import static com.facebook.presto.common.type.DoubleType.DOUBLE;
3742
import static com.facebook.presto.common.type.IntegerType.INTEGER;
3843
import static com.facebook.presto.common.type.JsonType.JSON;
3944
import static com.facebook.presto.common.type.TypeSignature.parseTypeSignature;
@@ -43,6 +48,7 @@
4348
import static com.facebook.presto.metadata.CastType.JSON_TO_MAP_CAST;
4449
import static com.facebook.presto.metadata.CastType.JSON_TO_ROW_CAST;
4550
import static com.facebook.presto.metadata.FunctionAndTypeManager.createTestFunctionAndTypeManager;
51+
import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
4652
import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.OPTIMIZED;
4753
import static com.facebook.presto.spi.relation.SpecialFormExpression.Form.IF;
4854
import static com.facebook.presto.sql.analyzer.TypeSignatureProvider.fromTypes;
@@ -52,7 +58,9 @@
5258
import static com.facebook.presto.testing.TestingConnectorSession.SESSION;
5359
import static com.facebook.presto.util.StructuralTestUtil.mapType;
5460
import static io.airlift.slice.Slices.utf8Slice;
61+
import static java.lang.String.format;
5562
import static org.testng.Assert.assertEquals;
63+
import static org.testng.Assert.assertThrows;
5664

5765
public class TestRowExpressionOptimizer
5866
{
@@ -134,6 +142,27 @@ public void testCastWithJsonParseOptimization()
134142
call(JSON_TO_ROW_CAST.name(), functionAndTypeManager.lookupCast(JSON_TO_ROW_CAST, VARCHAR, functionAndTypeManager.getType(parseTypeSignature("row(varchar,bigint)"))), RowType.anonymous(ImmutableList.of(VARCHAR, BIGINT)), field(1, VARCHAR)));
135143
}
136144

145+
@Test
146+
public void testDefaultExpressionOptimizerUsesJavaNamespaceForBuiltInFunctions()
147+
{
148+
String nativePrefix = "native.default";
149+
MetadataManager metadata = MetadataManager.createTestMetadataManager(new FunctionsConfig().setDefaultNamespacePrefix(nativePrefix));
150+
RowExpressionOptimizer nativeOptimizer = new RowExpressionOptimizer(metadata);
151+
RowExpression simpleAddition = call(
152+
"sqrt",
153+
new BuiltInFunctionHandle(
154+
new Signature(
155+
QualifiedObjectName.valueOf(format("%s.sqrt", nativePrefix)),
156+
SCALAR,
157+
BIGINT.getTypeSignature(),
158+
ImmutableList.of(BIGINT.getTypeSignature()))),
159+
DOUBLE,
160+
ImmutableList.of(
161+
constant(4L, BIGINT)));
162+
assertEquals(nativeOptimizer.optimize(simpleAddition, OPTIMIZED, SESSION), constant(2.0, DOUBLE));
163+
assertThrows(IllegalArgumentException.class, () -> optimizer.optimize(simpleAddition, OPTIMIZED, SESSION));
164+
}
165+
137166
private static RowExpression ifExpression(RowExpression condition, long trueValue, long falseValue)
138167
{
139168
return new SpecialFormExpression(IF, BIGINT, ImmutableList.of(condition, constant(trueValue, BIGINT), constant(falseValue, BIGINT)));

0 commit comments

Comments
 (0)