From 197d984e66f71bd398a6881ca21c11ea5ee752a4 Mon Sep 17 00:00:00 2001 From: Tim Meehan Date: Fri, 16 May 2025 13:26:51 -0400 Subject: [PATCH 1/2] Migrate evaluateConstantRowExpression to ExpressionOptimizer This is needed to have consistent constant folding behavior across the codebase. --- .../presto/cost/StatsCalculatorModule.java | 11 ++++--- .../facebook/presto/cost/ValuesStatsRule.java | 18 +++++++++--- .../presto/sql/planner/PlanOptimizers.java | 2 +- .../sql/planner/RowExpressionInterpreter.java | 10 ------- .../optimizations/MetadataQueryOptimizer.java | 29 ++++++++++++------- .../presto/testing/LocalQueryRunner.java | 2 +- .../PrestoSparkStatsCalculatorModule.java | 6 ++-- 7 files changed, 45 insertions(+), 33 deletions(-) diff --git a/presto-main-base/src/main/java/com/facebook/presto/cost/StatsCalculatorModule.java b/presto-main-base/src/main/java/com/facebook/presto/cost/StatsCalculatorModule.java index 41716b3d1e687..ca6ac9d357016 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/cost/StatsCalculatorModule.java +++ b/presto-main-base/src/main/java/com/facebook/presto/cost/StatsCalculatorModule.java @@ -14,6 +14,7 @@ package com.facebook.presto.cost; import com.facebook.presto.metadata.Metadata; +import com.facebook.presto.sql.expressions.ExpressionOptimizerManager; import com.google.common.collect.ImmutableList; import com.google.inject.Binder; import com.google.inject.Module; @@ -46,9 +47,10 @@ public static StatsCalculator createNewStatsCalculator( StatsNormalizer normalizer, FilterStatsCalculator filterStatsCalculator, HistoryBasedPlanStatisticsManager historyBasedPlanStatisticsManager, - FragmentStatsProvider fragmentStatsProvider) + FragmentStatsProvider fragmentStatsProvider, + ExpressionOptimizerManager expressionOptimizerManager) { - StatsCalculator delegate = createComposableStatsCalculator(metadata, scalarStatsCalculator, normalizer, filterStatsCalculator, fragmentStatsProvider); + StatsCalculator delegate = createComposableStatsCalculator(metadata, scalarStatsCalculator, normalizer, filterStatsCalculator, fragmentStatsProvider, expressionOptimizerManager); return historyBasedPlanStatisticsManager.getHistoryBasedPlanStatisticsCalculator(delegate); } @@ -57,14 +59,15 @@ public static ComposableStatsCalculator createComposableStatsCalculator( ScalarStatsCalculator scalarStatsCalculator, StatsNormalizer normalizer, FilterStatsCalculator filterStatsCalculator, - FragmentStatsProvider fragmentStatsProvider) + FragmentStatsProvider fragmentStatsProvider, + ExpressionOptimizerManager expressionOptimizerManager) { ImmutableList.Builder> rules = ImmutableList.builder(); rules.add(new OutputStatsRule()); rules.add(new TableScanStatsRule(metadata, normalizer)); rules.add(new SimpleFilterProjectSemiJoinStatsRule(normalizer, filterStatsCalculator, metadata.getFunctionAndTypeManager())); // this must be before FilterStatsRule rules.add(new FilterStatsRule(normalizer, filterStatsCalculator)); - rules.add(new ValuesStatsRule(metadata)); + rules.add(new ValuesStatsRule(metadata, expressionOptimizerManager)); rules.add(new LimitStatsRule(normalizer)); rules.add(new EnforceSingleRowStatsRule(normalizer)); rules.add(new ProjectStatsRule(scalarStatsCalculator, normalizer)); diff --git a/presto-main-base/src/main/java/com/facebook/presto/cost/ValuesStatsRule.java b/presto-main-base/src/main/java/com/facebook/presto/cost/ValuesStatsRule.java index a7c67756c4622..5effe5901e24e 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/cost/ValuesStatsRule.java +++ b/presto-main-base/src/main/java/com/facebook/presto/cost/ValuesStatsRule.java @@ -19,7 +19,9 @@ import com.facebook.presto.matching.Pattern; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.spi.plan.ValuesNode; +import com.facebook.presto.spi.relation.ConstantExpression; import com.facebook.presto.spi.relation.VariableReferenceExpression; +import com.facebook.presto.sql.expressions.ExpressionOptimizerManager; import com.facebook.presto.sql.planner.TypeProvider; import com.facebook.presto.sql.planner.iterative.Lookup; @@ -32,10 +34,12 @@ import static com.facebook.presto.common.type.UnknownType.UNKNOWN; import static com.facebook.presto.cost.StatsUtil.toStatsRepresentation; +import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.EVALUATED; import static com.facebook.presto.spi.statistics.SourceInfo.ConfidenceLevel.FACT; -import static com.facebook.presto.sql.planner.RowExpressionInterpreter.evaluateConstantRowExpression; import static com.facebook.presto.sql.planner.plan.Patterns.values; +import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; public class ValuesStatsRule @@ -44,10 +48,12 @@ public class ValuesStatsRule private static final Pattern PATTERN = values(); private final Metadata metadata; + private final ExpressionOptimizerManager expressionOptimizerManager; - public ValuesStatsRule(Metadata metadata) + public ValuesStatsRule(Metadata metadata, ExpressionOptimizerManager expressionOptimizerManager) { - this.metadata = metadata; + this.metadata = requireNonNull(metadata, "metadata is null"); + this.expressionOptimizerManager = requireNonNull(expressionOptimizerManager, "expressionOptimizerManager is null"); } @Override @@ -82,7 +88,11 @@ private List getVariableValues(ValuesNode valuesNode, int symbolId, Sess } return valuesNode.getRows().stream() .map(row -> row.get(symbolId)) - .map(rowExpression -> evaluateConstantRowExpression(rowExpression, metadata.getFunctionAndTypeManager(), session.toConnectorSession())) + .map(rowExpression -> expressionOptimizerManager.getExpressionOptimizer(session.toConnectorSession()) + .optimize(rowExpression, EVALUATED, session.toConnectorSession(), i -> i)) + .peek(rowExpression -> verify(rowExpression instanceof ConstantExpression, "Expected constant expression, but got: %s", rowExpression)) + .map(rowExpression -> (ConstantExpression) rowExpression) + .map(ConstantExpression::getValue) .collect(toList()); } diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/PlanOptimizers.java b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/PlanOptimizers.java index d00dcd18d2c5b..b6a5ed06bf652 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/PlanOptimizers.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/PlanOptimizers.java @@ -744,7 +744,7 @@ public PlanOptimizers( builder.add(predicatePushDown); // Run predicate push down one more time in case we can leverage new information from layouts' effective predicate builder.add(simplifyRowExpressionOptimizer); // Should be always run after PredicatePushDown - builder.add(new MetadataQueryOptimizer(metadata)); + builder.add(new MetadataQueryOptimizer(metadata, expressionOptimizerManager)); // This can pull up Filter and Project nodes from between Joins, so we need to push them down again builder.add( diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/RowExpressionInterpreter.java b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/RowExpressionInterpreter.java index fe2c124c5b54e..5a30eb17d4067 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/RowExpressionInterpreter.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/RowExpressionInterpreter.java @@ -109,7 +109,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.instanceOf; -import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Iterables.getOnlyElement; import static io.airlift.slice.Slices.utf8Slice; @@ -130,15 +129,6 @@ public class RowExpressionInterpreter private final FunctionResolution resolution; private final Visitor visitor; - - public static Object evaluateConstantRowExpression(RowExpression expression, FunctionAndTypeManager functionAndTypeManager, ConnectorSession session) - { - // evaluate the expression - Object result = new RowExpressionInterpreter(expression, functionAndTypeManager, session, EVALUATED).evaluate(); - verify(!(result instanceof RowExpression), "RowExpression interpreter returned an unresolved expression"); - return result; - } - public static RowExpressionInterpreter rowExpressionInterpreter(RowExpression expression, FunctionAndTypeManager functionAndTypeManager, ConnectorSession session) { return new RowExpressionInterpreter(expression, functionAndTypeManager, session, EVALUATED); diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataQueryOptimizer.java b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataQueryOptimizer.java index d3737dd73be2a..52890f8a31d89 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataQueryOptimizer.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataQueryOptimizer.java @@ -46,6 +46,7 @@ import com.facebook.presto.spi.relation.RowExpression; import com.facebook.presto.spi.relation.VariableReferenceExpression; import com.facebook.presto.spi.statistics.TableStatistics; +import com.facebook.presto.sql.expressions.ExpressionOptimizerManager; import com.facebook.presto.sql.planner.TypeProvider; import com.facebook.presto.sql.planner.VariablesExtractor; import com.facebook.presto.sql.planner.plan.SimplePlanRewriter; @@ -64,9 +65,10 @@ import java.util.Set; import static com.facebook.presto.spi.plan.ProjectNode.Locality.LOCAL; -import static com.facebook.presto.sql.planner.RowExpressionInterpreter.evaluateConstantRowExpression; +import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.EVALUATED; import static com.facebook.presto.sql.relational.Expressions.call; import static com.facebook.presto.sql.relational.Expressions.constant; +import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Iterables.getOnlyElement; import static java.util.Objects.requireNonNull; @@ -81,12 +83,13 @@ public class MetadataQueryOptimizer private final Set allowedFunctions; private final Map aggregationScalarMapping; private final Metadata metadata; + private final ExpressionOptimizerManager expressionOptimizerManager; - public MetadataQueryOptimizer(Metadata metadata) + public MetadataQueryOptimizer(Metadata metadata, ExpressionOptimizerManager expressionOptimizerManager) { - requireNonNull(metadata, "metadata is null"); + this.metadata = requireNonNull(metadata, "metadata is null"); + this.expressionOptimizerManager = requireNonNull(expressionOptimizerManager, "expressionOptimizerManager is null"); - this.metadata = metadata; CatalogSchemaName defaultNamespace = metadata.getFunctionAndTypeManager().getDefaultNamespace(); this.allowedFunctions = ImmutableSet.of( QualifiedObjectName.valueOf(defaultNamespace, "max"), @@ -104,7 +107,7 @@ public PlanOptimizerResult optimize(PlanNode plan, Session session, TypeProvider if (!SystemSessionProperties.isOptimizeMetadataQueries(session) && !SystemSessionProperties.isOptimizeMetadataQueriesIgnoreStats(session)) { return PlanOptimizerResult.optimizerResult(plan, false); } - Optimizer optimizer = new Optimizer(session, metadata, idAllocator); + Optimizer optimizer = new Optimizer(session, metadata, idAllocator, expressionOptimizerManager); PlanNode rewrittenPlan = SimplePlanRewriter.rewriteWith(optimizer, plan, null); return PlanOptimizerResult.optimizerResult(rewrittenPlan, optimizer.isPlanChanged()); } @@ -130,8 +133,9 @@ private static class Optimizer private final int metastoreCallNumThreshold; private boolean planChanged; private final MetadataQueryOptimizer metadataQueryOptimizer; + private final ExpressionOptimizerManager expressionOptimizerManager; - private Optimizer(Session session, Metadata metadata, PlanNodeIdAllocator idAllocator) + private Optimizer(Session session, Metadata metadata, PlanNodeIdAllocator idAllocator, ExpressionOptimizerManager expressionOptimizerManager) { this.session = session; this.metadata = metadata; @@ -139,7 +143,8 @@ private Optimizer(Session session, Metadata metadata, PlanNodeIdAllocator idAllo this.determinismEvaluator = new RowExpressionDeterminismEvaluator(metadata); this.ignoreMetadataStats = SystemSessionProperties.isOptimizeMetadataQueriesIgnoreStats(session); this.metastoreCallNumThreshold = SystemSessionProperties.getOptimizeMetadataQueriesCallThreshold(session); - this.metadataQueryOptimizer = new MetadataQueryOptimizer(metadata); + this.metadataQueryOptimizer = new MetadataQueryOptimizer(metadata, expressionOptimizerManager); + this.expressionOptimizerManager = expressionOptimizerManager; } public boolean isPlanChanged() @@ -374,15 +379,17 @@ private RowExpression evaluateMinMax(FunctionMetadata aggregationFunctionMetadat List reducedArguments = new ArrayList<>(); // We fold for every 100 values because GREATEST/LEAST has argument count limit for (List partitionedArguments : Lists.partition(arguments, 100)) { - Object reducedValue = evaluateConstantRowExpression( + RowExpression expression = expressionOptimizerManager.getExpressionOptimizer(connectorSession).optimize( call( metadata.getFunctionAndTypeManager(), scalarFunctionName, returnType, partitionedArguments), - metadata.getFunctionAndTypeManager(), - connectorSession); - reducedArguments.add(constant(reducedValue, returnType)); + EVALUATED, + connectorSession, + i -> i); + verify(expression instanceof ConstantExpression, "Expected constant expression"); + reducedArguments.add(expression); } arguments = reducedArguments; } diff --git a/presto-main-base/src/main/java/com/facebook/presto/testing/LocalQueryRunner.java b/presto-main-base/src/main/java/com/facebook/presto/testing/LocalQueryRunner.java index e6a1e2495ab06..fa1913e3d80d6 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/testing/LocalQueryRunner.java +++ b/presto-main-base/src/main/java/com/facebook/presto/testing/LocalQueryRunner.java @@ -478,7 +478,7 @@ private LocalQueryRunner(Session defaultSession, FeaturesConfig featuresConfig, this.filterStatsCalculator = new FilterStatsCalculator(metadata, scalarStatsCalculator, statsNormalizer); this.historyBasedPlanStatisticsManager = new HistoryBasedPlanStatisticsManager(objectMapper, createTestingSessionPropertyManager(), metadata, new HistoryBasedOptimizationConfig(), featuresConfig, new NodeVersion("1")); this.fragmentStatsProvider = new FragmentStatsProvider(); - this.statsCalculator = createNewStatsCalculator(metadata, scalarStatsCalculator, statsNormalizer, filterStatsCalculator, historyBasedPlanStatisticsManager, fragmentStatsProvider); + this.statsCalculator = createNewStatsCalculator(metadata, scalarStatsCalculator, statsNormalizer, filterStatsCalculator, historyBasedPlanStatisticsManager, fragmentStatsProvider, expressionOptimizerManager); this.taskCountEstimator = new TaskCountEstimator(() -> nodeCountForStats); this.costCalculator = new CostCalculatorUsingExchanges(taskCountEstimator); this.estimatedExchangesCostCalculator = new CostCalculatorWithEstimatedExchanges(costCalculator, taskCountEstimator); diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/planner/PrestoSparkStatsCalculatorModule.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/planner/PrestoSparkStatsCalculatorModule.java index b2471077841e6..bada2c5a5f61e 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/planner/PrestoSparkStatsCalculatorModule.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/planner/PrestoSparkStatsCalculatorModule.java @@ -22,6 +22,7 @@ import com.facebook.presto.cost.StatsCalculator; import com.facebook.presto.cost.StatsNormalizer; import com.facebook.presto.metadata.Metadata; +import com.facebook.presto.sql.expressions.ExpressionOptimizerManager; import com.google.inject.Binder; import com.google.inject.Module; import com.google.inject.Provides; @@ -55,9 +56,10 @@ public static StatsCalculator createNewStatsCalculator( FilterStatsCalculator filterStatsCalculator, FragmentStatsProvider fragmentStatsProvider, HistoryBasedPlanStatisticsManager historyBasedPlanStatisticsManager, - HistoryBasedOptimizationConfig historyBasedOptimizationConfig) + HistoryBasedOptimizationConfig historyBasedOptimizationConfig, + ExpressionOptimizerManager expressionOptimizerManager) { - StatsCalculator delegate = createComposableStatsCalculator(metadata, scalarStatsCalculator, normalizer, filterStatsCalculator, fragmentStatsProvider); + StatsCalculator delegate = createComposableStatsCalculator(metadata, scalarStatsCalculator, normalizer, filterStatsCalculator, fragmentStatsProvider, expressionOptimizerManager); return new PrestoSparkStatsCalculator(historyBasedPlanStatisticsManager.getHistoryBasedPlanStatisticsCalculator(delegate), delegate, historyBasedOptimizationConfig); } } From 6fcb695692cf621e558af84b6c908693f507aefe Mon Sep 17 00:00:00 2001 From: Tim Meehan Date: Fri, 16 May 2025 15:48:58 -0400 Subject: [PATCH 2/2] 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). --- .../relational/RowExpressionOptimizer.java | 65 ++++++++++++++++++- .../TestRowExpressionOptimizer.java | 29 +++++++++ .../sidecar/TestNativeSidecarPlugin.java | 5 +- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/relational/RowExpressionOptimizer.java b/presto-main-base/src/main/java/com/facebook/presto/sql/relational/RowExpressionOptimizer.java index 173b1c996e0ea..66cc803270c7b 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/relational/RowExpressionOptimizer.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/relational/RowExpressionOptimizer.java @@ -13,24 +13,34 @@ */ package com.facebook.presto.sql.relational; +import com.facebook.presto.common.CatalogSchemaName; +import com.facebook.presto.common.QualifiedObjectName; import com.facebook.presto.metadata.FunctionAndTypeManager; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.spi.relation.CallExpression; import com.facebook.presto.spi.relation.ExpressionOptimizer; import com.facebook.presto.spi.relation.RowExpression; +import com.facebook.presto.spi.relation.RowExpressionVisitor; import com.facebook.presto.spi.relation.VariableReferenceExpression; +import com.facebook.presto.sql.analyzer.TypeSignatureProvider; import com.facebook.presto.sql.planner.RowExpressionInterpreter; import java.util.function.Function; +import static com.facebook.presto.metadata.BuiltInTypeAndFunctionNamespaceManager.JAVA_BUILTIN_NAMESPACE; import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.OPTIMIZED; import static com.facebook.presto.sql.planner.LiteralEncoder.toRowExpression; +import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Objects.requireNonNull; +import static java.util.function.UnaryOperator.identity; public final class RowExpressionOptimizer implements ExpressionOptimizer { private final FunctionAndTypeManager functionAndTypeManager; + private final CatalogSchemaName defaultNamespace; + private final Function normalizeRowExpression; public RowExpressionOptimizer(Metadata metadata) { @@ -39,14 +49,26 @@ public RowExpressionOptimizer(Metadata metadata) public RowExpressionOptimizer(FunctionAndTypeManager functionAndTypeManager) { + this.defaultNamespace = requireNonNull(functionAndTypeManager, "functionMetadataManager is null").getDefaultNamespace(); this.functionAndTypeManager = requireNonNull(functionAndTypeManager, "functionMetadataManager is null"); + if (!defaultNamespace.equals(JAVA_BUILTIN_NAMESPACE)) { + this.normalizeRowExpression = rowExpression -> rowExpression.accept(new BuiltInFunctionNamespaceOverride(), null); + } + else { + this.normalizeRowExpression = identity(); + } } @Override public RowExpression optimize(RowExpression rowExpression, Level level, ConnectorSession session) { if (level.ordinal() <= OPTIMIZED.ordinal()) { - return toRowExpression(rowExpression.getSourceLocation(), new RowExpressionInterpreter(rowExpression, functionAndTypeManager, session, level).optimize(), rowExpression.getType()); + RowExpressionInterpreter rowExpressionInterpreter = new RowExpressionInterpreter( + normalizeRowExpression.apply(rowExpression), + functionAndTypeManager, + session, + level); + return toRowExpression(rowExpression.getSourceLocation(), rowExpressionInterpreter.optimize(), rowExpression.getType()); } throw new IllegalArgumentException("Not supported optimization level: " + level); } @@ -54,7 +76,46 @@ public RowExpression optimize(RowExpression rowExpression, Level level, Connecto @Override public RowExpression optimize(RowExpression expression, Level level, ConnectorSession session, Function variableResolver) { - RowExpressionInterpreter interpreter = new RowExpressionInterpreter(expression, functionAndTypeManager, session, level); + RowExpressionInterpreter interpreter = new RowExpressionInterpreter( + normalizeRowExpression.apply(expression), + functionAndTypeManager, + session, + level); return toRowExpression(expression.getSourceLocation(), interpreter.optimize(variableResolver::apply), expression.getType()); } + + /** + * TODO: GIANT HACK + * This class is a hack and should eventually be removed. It is used to ensure consistent constant folding behavior when the built-in + * function namespace has been switched (for example, to native.default. in the case of native functions). This will no longer be needed + * when the native sidecar is capable of providing its own expression optimizer. + */ + private class BuiltInFunctionNamespaceOverride + implements RowExpressionVisitor + { + @Override + public RowExpression visitExpression(RowExpression expression, Void context) + { + return expression; + } + + @Override + public RowExpression visitCall(CallExpression call, Void context) + { + if (call.getFunctionHandle().getCatalogSchemaName().equals(defaultNamespace)) { + call = new CallExpression( + call.getSourceLocation(), + call.getDisplayName(), + functionAndTypeManager.lookupFunction( + QualifiedObjectName.valueOf(JAVA_BUILTIN_NAMESPACE, call.getDisplayName()), + call.getArguments().stream() + .map(RowExpression::getType) + .map(x -> new TypeSignatureProvider(x.getTypeSignature())) + .collect(toImmutableList())), + call.getType(), + call.getArguments()); + } + return call; + } + } } diff --git a/presto-main-base/src/test/java/com/facebook/presto/sql/relational/TestRowExpressionOptimizer.java b/presto-main-base/src/test/java/com/facebook/presto/sql/relational/TestRowExpressionOptimizer.java index dca72b62123ef..649a59fa2ae9b 100644 --- a/presto-main-base/src/test/java/com/facebook/presto/sql/relational/TestRowExpressionOptimizer.java +++ b/presto-main-base/src/test/java/com/facebook/presto/sql/relational/TestRowExpressionOptimizer.java @@ -13,16 +13,20 @@ */ package com.facebook.presto.sql.relational; +import com.facebook.presto.common.QualifiedObjectName; import com.facebook.presto.common.block.IntArrayBlock; import com.facebook.presto.common.type.ArrayType; import com.facebook.presto.common.type.RowType; +import com.facebook.presto.metadata.BuiltInFunctionHandle; import com.facebook.presto.metadata.FunctionAndTypeManager; import com.facebook.presto.metadata.MetadataManager; import com.facebook.presto.spi.function.FunctionHandle; +import com.facebook.presto.spi.function.Signature; import com.facebook.presto.spi.relation.CallExpression; import com.facebook.presto.spi.relation.ConstantExpression; import com.facebook.presto.spi.relation.RowExpression; import com.facebook.presto.spi.relation.SpecialFormExpression; +import com.facebook.presto.sql.analyzer.FunctionsConfig; import com.google.common.collect.ImmutableList; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -34,6 +38,7 @@ import static com.facebook.presto.common.function.OperatorType.EQUAL; import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.common.type.BooleanType.BOOLEAN; +import static com.facebook.presto.common.type.DoubleType.DOUBLE; import static com.facebook.presto.common.type.IntegerType.INTEGER; import static com.facebook.presto.common.type.JsonType.JSON; import static com.facebook.presto.common.type.TypeSignature.parseTypeSignature; @@ -43,6 +48,7 @@ import static com.facebook.presto.metadata.CastType.JSON_TO_MAP_CAST; import static com.facebook.presto.metadata.CastType.JSON_TO_ROW_CAST; import static com.facebook.presto.metadata.FunctionAndTypeManager.createTestFunctionAndTypeManager; +import static com.facebook.presto.spi.function.FunctionKind.SCALAR; import static com.facebook.presto.spi.relation.ExpressionOptimizer.Level.OPTIMIZED; import static com.facebook.presto.spi.relation.SpecialFormExpression.Form.IF; import static com.facebook.presto.sql.analyzer.TypeSignatureProvider.fromTypes; @@ -52,7 +58,9 @@ import static com.facebook.presto.testing.TestingConnectorSession.SESSION; import static com.facebook.presto.util.StructuralTestUtil.mapType; import static io.airlift.slice.Slices.utf8Slice; +import static java.lang.String.format; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertThrows; public class TestRowExpressionOptimizer { @@ -134,6 +142,27 @@ public void testCastWithJsonParseOptimization() 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))); } + @Test + public void testDefaultExpressionOptimizerUsesJavaNamespaceForBuiltInFunctions() + { + String nativePrefix = "native.default"; + MetadataManager metadata = MetadataManager.createTestMetadataManager(new FunctionsConfig().setDefaultNamespacePrefix(nativePrefix)); + RowExpressionOptimizer nativeOptimizer = new RowExpressionOptimizer(metadata); + RowExpression simpleAddition = call( + "sqrt", + new BuiltInFunctionHandle( + new Signature( + QualifiedObjectName.valueOf(format("%s.sqrt", nativePrefix)), + SCALAR, + BIGINT.getTypeSignature(), + ImmutableList.of(BIGINT.getTypeSignature()))), + DOUBLE, + ImmutableList.of( + constant(4L, BIGINT))); + assertEquals(nativeOptimizer.optimize(simpleAddition, OPTIMIZED, SESSION), constant(2.0, DOUBLE)); + assertThrows(IllegalArgumentException.class, () -> optimizer.optimize(simpleAddition, OPTIMIZED, SESSION)); + } + private static RowExpression ifExpression(RowExpression condition, long trueValue, long falseValue) { return new SpecialFormExpression(IF, BIGINT, ImmutableList.of(condition, constant(trueValue, BIGINT), constant(falseValue, BIGINT))); diff --git a/presto-native-sidecar-plugin/src/test/java/com/facebook/presto/sidecar/TestNativeSidecarPlugin.java b/presto-native-sidecar-plugin/src/test/java/com/facebook/presto/sidecar/TestNativeSidecarPlugin.java index 75e5bb13104fd..f105dc0a77391 100644 --- a/presto-native-sidecar-plugin/src/test/java/com/facebook/presto/sidecar/TestNativeSidecarPlugin.java +++ b/presto-native-sidecar-plugin/src/test/java/com/facebook/presto/sidecar/TestNativeSidecarPlugin.java @@ -197,9 +197,8 @@ public void testArraySort() @Test public void testInformationSchemaTables() { - assertQueryFails("select lower(table_name) from information_schema.tables " - + "where table_name = 'lineitem' or table_name = 'LINEITEM' ", - "Compiler failed"); + assertQuery("select lower(table_name) from information_schema.tables " + + "where table_name = 'lineitem' or table_name = 'LINEITEM' "); } @Test