diff --git a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java index 01949df79bcc..96e904f72558 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java +++ b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java @@ -443,7 +443,8 @@ Optional finishRefreshMaterializedView( Collection fragments, Collection computedStatistics, List sourceTableHandles, - List sourceTableFunctions); + List sourceTableFunctions, + boolean hasNonDeterministicFunctions); /** * Push update into connector diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java index 891c50b65d9b..1978754120ac 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java @@ -1319,7 +1319,8 @@ public Optional finishRefreshMaterializedView( Collection fragments, Collection computedStatistics, List sourceTableHandles, - List sourceTableFunctions) + List sourceTableFunctions, + boolean hasNonDeterministicFunctions) { CatalogHandle catalogHandle = insertHandle.catalogHandle(); ConnectorMetadata metadata = getMetadata(session, catalogHandle); @@ -1337,7 +1338,8 @@ public Optional finishRefreshMaterializedView( computedStatistics, sourceConnectorHandles, sourceConnectorHandles.size() < sourceTableHandles.size(), - !sourceTableFunctions.isEmpty()); + !sourceTableFunctions.isEmpty(), + hasNonDeterministicFunctions); } @Override diff --git a/core/trino-main/src/main/java/io/trino/sql/analyzer/DeterminismEvaluator.java b/core/trino-main/src/main/java/io/trino/sql/analyzer/DeterminismEvaluator.java index 69db8b37345a..2effa34aedb9 100644 --- a/core/trino-main/src/main/java/io/trino/sql/analyzer/DeterminismEvaluator.java +++ b/core/trino-main/src/main/java/io/trino/sql/analyzer/DeterminismEvaluator.java @@ -22,6 +22,7 @@ import io.trino.sql.tree.FunctionCall; import io.trino.sql.tree.LocalTime; import io.trino.sql.tree.LocalTimestamp; +import io.trino.sql.tree.Node; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -66,12 +67,12 @@ protected Void visitFunctionCall(FunctionCall node, AtomicBoolean deterministic) } } - public static boolean containsCurrentTimeFunctions(Expression expression) + public static boolean containsCurrentTimeFunctions(Node node) { - requireNonNull(expression, "expression is null"); + requireNonNull(node, "node is null"); AtomicBoolean hasTemporalFunction = new AtomicBoolean(false); - new DeterminismEvaluator.TemporalFunctionVisitor().process(expression, hasTemporalFunction); + new DeterminismEvaluator.TemporalFunctionVisitor().process(node, hasTemporalFunction); return hasTemporalFunction.get(); } diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/LocalExecutionPlanner.java b/core/trino-main/src/main/java/io/trino/sql/planner/LocalExecutionPlanner.java index d53258385adf..b612dd926e7d 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/LocalExecutionPlanner.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/LocalExecutionPlanner.java @@ -4199,7 +4199,8 @@ private static TableFinisher createTableFinisher(Session session, TableFinishNod fragments, statistics, refreshTarget.getSourceTableHandles(), - refreshTarget.getSourceTableFunctions()); + refreshTarget.getSourceTableFunctions(), + refreshTarget.hasNonDeterministicFunctions()); } if (target instanceof TableExecuteTarget tableExecuteTarget) { TableExecuteHandle tableExecuteHandle = tableExecuteTarget.getExecuteHandle(); diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/LogicalPlanner.java b/core/trino-main/src/main/java/io/trino/sql/planner/LogicalPlanner.java index aae817271f83..ca5a8bde3b15 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/LogicalPlanner.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/LogicalPlanner.java @@ -146,6 +146,7 @@ import static io.trino.spi.type.IntegerType.INTEGER; import static io.trino.spi.type.VarbinaryType.VARBINARY; import static io.trino.spi.type.VarcharType.VARCHAR; +import static io.trino.sql.analyzer.DeterminismEvaluator.containsCurrentTimeFunctions; import static io.trino.sql.analyzer.SemanticExceptions.semanticException; import static io.trino.sql.analyzer.TypeSignatureProvider.fromTypes; import static io.trino.sql.ir.Booleans.TRUE; @@ -605,7 +606,9 @@ private RelationPlan getInsertPlan( TableStatisticsMetadata statisticsMetadata = metadata.getStatisticsCollectionMetadataForWrite(session, tableHandle.catalogHandle(), tableMetadata.metadata(), false); if (materializedViewRefreshWriterTarget.isPresent()) { - RefreshType refreshType = IncrementalRefreshVisitor.canIncrementallyRefresh(plan.getRoot()); + RefreshType refreshType = materializedViewRefreshWriterTarget.get().hasNonDeterministicFunctions() + ? RefreshType.FULL + : IncrementalRefreshVisitor.canIncrementallyRefresh(plan.getRoot()); WriterTarget writerTarget = materializedViewRefreshWriterTarget.get().withRefreshType(refreshType); return createTableWriterPlan( analysis, @@ -688,11 +691,16 @@ private RelationPlan createRefreshMaterializedViewPlan(Analysis analysis) List tableFunctions = analysis.getPolymorphicTableFunctions().stream() .map(polymorphicTableFunction -> polymorphicTableFunction.getNode().getName().toString()) .collect(toImmutableList()); + // TODO: For time-based functions (current_date, current_timestamp) smarter freshness tracking + // could avoid treating the MV as stale when the time hasn't meaningfully changed. See https://github.com/trinodb/trino/issues/28731 + boolean hasNonDeterministicFunctions = analysis.getResolvedFunctions().stream().anyMatch(function -> !function.deterministic()) + || containsCurrentTimeFunctions(query); RefreshMaterializedViewReference writerTarget = new RefreshMaterializedViewReference( viewAnalysis.getTable().toString(), tableHandle, ImmutableList.copyOf(analysis.getTables()), tableFunctions, + hasNonDeterministicFunctions, // this is a placeholder value - refresh type will be determined by getInsertPlan based on the plan tree RefreshType.FULL); return getInsertPlan(analysis, viewAnalysis.getTable(), query, tableHandle, viewAnalysis.getColumns(), newTableLayout, Optional.of(writerTarget)); diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/optimizations/BeginTableWrite.java b/core/trino-main/src/main/java/io/trino/sql/planner/optimizations/BeginTableWrite.java index 4811ef82a3c3..effa7ed25cac 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/optimizations/BeginTableWrite.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/optimizations/BeginTableWrite.java @@ -264,6 +264,7 @@ private WriterTarget createWriterTarget(WriterTarget target, PlanNode planNode) metadata.getTableName(session, refreshMV.getStorageTableHandle()).getSchemaTableName(), refreshMV.getSourceTableHandles(), refreshMV.getSourceTableFunctions(), + refreshMV.hasNonDeterministicFunctions(), refreshMV.getWriterScalingOptions(metadata, session)); } if (target instanceof TableExecuteTarget tableExecute) { diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/plan/TableWriterNode.java b/core/trino-main/src/main/java/io/trino/sql/planner/plan/TableWriterNode.java index b9e7941c392f..f62aa7a5abbf 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/plan/TableWriterNode.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/plan/TableWriterNode.java @@ -489,6 +489,7 @@ public static class RefreshMaterializedViewReference private final TableHandle storageTableHandle; private final List sourceTableHandles; private final List sourceTableFunctions; + private final boolean hasNonDeterministicFunctions; private final RefreshType refreshType; public RefreshMaterializedViewReference( @@ -496,12 +497,14 @@ public RefreshMaterializedViewReference( TableHandle storageTableHandle, List sourceTableHandles, List sourceTableFunctions, + boolean hasNonDeterministicFunctions, RefreshType refreshType) { this.table = requireNonNull(table, "table is null"); this.storageTableHandle = requireNonNull(storageTableHandle, "storageTableHandle is null"); this.sourceTableHandles = ImmutableList.copyOf(sourceTableHandles); this.sourceTableFunctions = ImmutableList.copyOf(sourceTableFunctions); + this.hasNonDeterministicFunctions = hasNonDeterministicFunctions; this.refreshType = requireNonNull(refreshType, "refreshType is null"); } @@ -540,6 +543,11 @@ public List getSourceTableFunctions() return sourceTableFunctions; } + public boolean hasNonDeterministicFunctions() + { + return hasNonDeterministicFunctions; + } + @Override public WriterScalingOptions getWriterScalingOptions(Metadata metadata, Session session) { @@ -553,7 +561,7 @@ public RefreshType getRefreshType() public RefreshMaterializedViewReference withRefreshType(RefreshType refreshType) { - return new RefreshMaterializedViewReference(table, storageTableHandle, sourceTableHandles, sourceTableFunctions, refreshType); + return new RefreshMaterializedViewReference(table, storageTableHandle, sourceTableHandles, sourceTableFunctions, hasNonDeterministicFunctions, refreshType); } } @@ -565,6 +573,7 @@ public static class RefreshMaterializedViewTarget private final SchemaTableName schemaTableName; private final List sourceTableHandles; private final List sourceTableFunctions; + private final boolean hasNonDeterministicFunctions; private final WriterScalingOptions writerScalingOptions; @JsonCreator @@ -574,6 +583,7 @@ public RefreshMaterializedViewTarget( @JsonProperty("schemaTableName") SchemaTableName schemaTableName, @JsonProperty("sourceTableHandles") List sourceTableHandles, @JsonProperty("sourceTableFunctions") List sourceTableFunctions, + @JsonProperty("hasNonDeterministicFunctions") boolean hasNonDeterministicFunctions, @JsonProperty("writerScalingOptions") WriterScalingOptions writerScalingOptions) { this.tableHandle = requireNonNull(tableHandle, "tableHandle is null"); @@ -581,6 +591,7 @@ public RefreshMaterializedViewTarget( this.schemaTableName = requireNonNull(schemaTableName, "schemaTableName is null"); this.sourceTableHandles = ImmutableList.copyOf(sourceTableHandles); this.sourceTableFunctions = ImmutableList.copyOf(sourceTableFunctions); + this.hasNonDeterministicFunctions = hasNonDeterministicFunctions; this.writerScalingOptions = requireNonNull(writerScalingOptions, "writerScalingOptions is null"); } @@ -614,6 +625,12 @@ public List getSourceTableFunctions() return sourceTableFunctions; } + @JsonProperty + public boolean hasNonDeterministicFunctions() + { + return hasNonDeterministicFunctions; + } + @JsonProperty public WriterScalingOptions getWriterScalingOptions() { diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java b/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java index 420c19175055..58e5d52094a3 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java @@ -748,11 +748,11 @@ public ConnectorInsertTableHandle beginRefreshMaterializedView(ConnectorSession } @Override - public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions) + public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions, boolean hasNonDeterministicFunctions) { Span span = startSpan("finishRefreshMaterializedView", tableHandle); try (var _ = scopedSpan(span)) { - return delegate.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, sourceTableHandles, hasForeignSourceTables, hasSourceTableFunctions); + return delegate.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, sourceTableHandles, hasForeignSourceTables, hasSourceTableFunctions, hasNonDeterministicFunctions); } } diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java index eaba0b4adead..70b0ca009c2a 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java @@ -791,7 +791,8 @@ public Optional finishRefreshMaterializedView( Collection fragments, Collection computedStatistics, List sourceTableHandles, - List sourceTableFunctions) + List sourceTableFunctions, + boolean hasNonDeterministicFunctions) { Span span = startSpan("finishRefreshMaterializedView", tableHandle); try (var _ = scopedSpan(span)) { @@ -802,7 +803,8 @@ public Optional finishRefreshMaterializedView( fragments, computedStatistics, sourceTableHandles, - sourceTableFunctions); + sourceTableFunctions, + hasNonDeterministicFunctions); } } diff --git a/core/trino-main/src/test/java/io/trino/connector/MockConnector.java b/core/trino-main/src/test/java/io/trino/connector/MockConnector.java index 8f26363b687d..4b57c05d4929 100644 --- a/core/trino-main/src/test/java/io/trino/connector/MockConnector.java +++ b/core/trino-main/src/test/java/io/trino/connector/MockConnector.java @@ -771,7 +771,7 @@ public ConnectorInsertTableHandle beginRefreshMaterializedView(ConnectorSession } @Override - public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions) + public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions, boolean hasNonDeterministicFunctions) { return Optional.empty(); } diff --git a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java index 923234e7af01..28d343dcb681 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java +++ b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java @@ -538,7 +538,8 @@ public Optional finishRefreshMaterializedView( Collection fragments, Collection computedStatistics, List sourceTableHandles, - List sourceTableFunctions) + List sourceTableFunctions, + boolean hasNonDeterministicFunctions) { throw new UnsupportedOperationException(); } diff --git a/core/trino-spi/pom.xml b/core/trino-spi/pom.xml index 79f5bfc9c68f..730cc88181e4 100644 --- a/core/trino-spi/pom.xml +++ b/core/trino-spi/pom.xml @@ -252,6 +252,680 @@ method io.opentelemetry.api.common.Value<java.util.List<io.opentelemetry.api.common.Value<?>>> io.opentelemetry.api.common.Value<T>::of(io.opentelemetry.api.common.Value<?>[]) Revapi now detects new API changes to vararg args + + java.method.numberOfParametersChanged + method void io.trino.spi.eventlistener.QueryStatistics::<init>(java.time.Duration, java.time.Duration, java.time.Duration, java.time.Duration, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, long, long, long, long, long, long, long, long, long, long, long, long, long, long, double, double, java.util.List<io.trino.spi.eventlistener.StageGcStatistics>, int, boolean, java.util.List<io.trino.spi.eventlistener.StageCpuDistribution>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferUtilization>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferMetrics>, java.util.List<io.trino.spi.eventlistener.StageTaskStatistics>, java.util.List<io.trino.spi.eventlistener.DynamicFilterDomainStatistics>, java.util.function.Supplier<java.util.List<java.lang.String>>, java.util.List<io.trino.spi.eventlistener.QueryPlanOptimizerStatistics>, java.util.Map<java.lang.String, io.trino.spi.metrics.Metrics>, java.util.Optional<java.lang.String>) + method void io.trino.spi.eventlistener.QueryStatistics::<init>(java.time.Duration, java.time.Duration, java.time.Duration, java.time.Duration, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, long, long, long, long, long, long, long, long, long, long, long, long, long, long, double, double, java.util.List<io.trino.spi.eventlistener.StageGcStatistics>, int, boolean, java.util.List<io.trino.spi.eventlistener.StageCpuDistribution>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferUtilization>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferMetrics>, java.util.List<io.trino.spi.eventlistener.StageTaskStatistics>, java.util.List<io.trino.spi.eventlistener.DynamicFilterDomainStatistics>, java.util.function.Supplier<java.util.List<java.lang.String>>, java.util.List<io.trino.spi.eventlistener.QueryPlanOptimizerStatistics>, java.util.Map<java.lang.String, io.trino.spi.metrics.Metrics>, java.util.Optional<java.lang.String>) + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.ArrayBlockEncoding::<init>() + method void io.trino.spi.block.ArrayBlockEncoding::<init>(boolean) + ArrayBlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.ByteArrayBlockEncoding::<init>(boolean) + method void io.trino.spi.block.ByteArrayBlockEncoding::<init>(boolean, boolean, boolean) + ByteArrayBlockEncoding needs to accept parameters to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.Fixed12BlockEncoding::<init>() + method void io.trino.spi.block.Fixed12BlockEncoding::<init>(boolean) + Fixed12BlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.Int128ArrayBlockEncoding::<init>() + method void io.trino.spi.block.Int128ArrayBlockEncoding::<init>(boolean) + Int128ArrayBlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.IntArrayBlockEncoding::<init>(boolean) + method void io.trino.spi.block.IntArrayBlockEncoding::<init>(boolean, boolean, boolean) + IntArrayBlockEncoding needs to accept parameters to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.LongArrayBlockEncoding::<init>(boolean) + method void io.trino.spi.block.LongArrayBlockEncoding::<init>(boolean, boolean, boolean) + LongArrayBlockEncoding needs to accept parameters to to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.MapBlockEncoding::<init>() + method void io.trino.spi.block.MapBlockEncoding::<init>(boolean) + MapBlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.RowBlockEncoding::<init>() + method void io.trino.spi.block.RowBlockEncoding::<init>(boolean) + RowBlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.ShortArrayBlockEncoding::<init>(boolean) + method void io.trino.spi.block.ShortArrayBlockEncoding::<init>(boolean, boolean, boolean) + ShortArrayBlockEncoding needs to accept parameters to enable SIMD support + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.block.VariableWidthBlockEncoding::<init>() + method void io.trino.spi.block.VariableWidthBlockEncoding::<init>(boolean) + VariableWidthBlockEncoding needs to accept a parameter to enable SIMD support + + + true + java.method.removed + method void io.trino.spi.block.PageBuilderStatus::<init>() + Method is unnecessary + + + java.method.numberOfParametersChanged + method void io.trino.spi.connector.ConnectorMaterializedViewDefinition::<init>(java.lang.String, java.util.Optional<io.trino.spi.connector.CatalogSchemaTableName>, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.List<io.trino.spi.connector.ConnectorMaterializedViewDefinition.Column>, java.util.Optional<java.time.Duration>, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.List<io.trino.spi.connector.CatalogSchemaName>) + method void io.trino.spi.connector.ConnectorMaterializedViewDefinition::<init>(java.lang.String, java.util.Optional<io.trino.spi.connector.CatalogSchemaTableName>, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.List<io.trino.spi.connector.ConnectorMaterializedViewDefinition.Column>, java.util.Optional<java.time.Duration>, java.util.Optional<io.trino.spi.connector.ConnectorMaterializedViewDefinition.WhenStaleBehavior>, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.List<io.trino.spi.connector.CatalogSchemaName>) + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.resourcegroups.SelectionCriteria::<init>(boolean, java.lang.String, java.util.Set<java.lang.String>, java.lang.String, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.Set<java.lang.String>, io.trino.spi.session.ResourceEstimates, java.util.Optional<java.lang.String>) + method void io.trino.spi.resourcegroups.SelectionCriteria::<init>(boolean, java.lang.String, java.util.Set<java.lang.String>, java.lang.String, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.Set<java.lang.String>, io.trino.spi.session.ResourceEstimates, java.lang.String, java.util.Optional<java.lang.String>) + Added queryText before queryType parameter + + + true + java.method.removed + method void io.trino.spi.resourcegroups.SelectionCriteria::<init>(boolean, java.lang.String, java.util.Set<java.lang.String>, java.lang.String, java.util.Optional<java.lang.String>, java.util.Optional<java.lang.String>, java.util.Set<java.lang.String>, io.trino.spi.session.ResourceEstimates, java.util.Optional<java.lang.String>) + Added queryText before queryType parameter + + + true + java.method.removed + method io.trino.spi.type.RowType io.trino.spi.type.RowType::createWithTypeSignature(io.trino.spi.type.TypeSignature, java.util.List<io.trino.spi.type.RowType.Field>) + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.ParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.ParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.QuantileDigestParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.QuantileDigestParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.TimeParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.TimeParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.TimeWithTimeZoneParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.TimeWithTimeZoneParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.TimestampParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.TimestampParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.TimestampWithTimeZoneParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.TimestampWithTimeZoneParametricType::createType(io.trino.spi.type.TypeManager, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + 1 + TypeParameter not needed + + + true + java.class.removed + class io.trino.spi.type.TypeParameter + TypeParameter not needed + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.Type io.trino.spi.type.TypeManager::getParameterizedType(java.lang.String, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + parameter io.trino.spi.type.Type io.trino.spi.type.TypeManager::getParameterizedType(java.lang.String, ===java.util.List<io.trino.spi.type.TypeParameter>===) + 1 + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.NamedType io.trino.spi.type.TypeParameter::getNamedType() + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.Type io.trino.spi.type.TypeParameter::getType() + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.visibilityReduced + method <A> A io.trino.spi.type.TypeParameter::getValue(io.trino.spi.type.ParameterKind, java.lang.Class<A>) + method <A> A io.trino.spi.type.TypeParameter::getValue(io.trino.spi.type.ParameterKind, java.lang.Class<A>) + public + private + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.TypeParameter io.trino.spi.type.TypeParameter::of(io.trino.spi.type.NamedType) + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.TypeParameter io.trino.spi.type.TypeParameter::of(io.trino.spi.type.Type) + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.TypeParameter io.trino.spi.type.TypeParameter::of(io.trino.spi.type.TypeSignatureParameter, io.trino.spi.type.TypeManager) + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.TypeParameter io.trino.spi.type.TypeParameter::of(java.lang.String) + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.removed + method io.trino.spi.type.TypeParameter io.trino.spi.type.TypeParameter::of(long) + Rename TypeSignatureParameter to TypeParameter + + + true + java.class.nowFinal + class io.trino.spi.type.TypeParameter + class io.trino.spi.type.TypeParameter + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.parameterTypeParameterChanged + parameter void io.trino.spi.type.TypeSignature::<init>(java.lang.String, ===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + parameter void io.trino.spi.type.TypeSignature::<init>(java.lang.String, ===java.util.List<io.trino.spi.type.TypeParameter>===) + 1 + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.parameterTypeChanged + parameter void io.trino.spi.type.TypeSignature::<init>(java.lang.String, ===io.trino.spi.type.TypeSignatureParameter[]===) + parameter void io.trino.spi.type.TypeSignature::<init>(java.lang.String, ===io.trino.spi.type.TypeParameter[]===) + 1 + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.parameterTypeChanged + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::arrayType(===io.trino.spi.type.TypeSignatureParameter===) + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::arrayType(===io.trino.spi.type.TypeParameter===) + 0 + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.returnTypeTypeParametersChanged + method java.util.List<io.trino.spi.type.TypeSignatureParameter> io.trino.spi.type.TypeSignature::getParameters() + method java.util.List<io.trino.spi.type.TypeParameter> io.trino.spi.type.TypeSignature::getParameters() + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.parameterTypeParameterChanged + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::rowType(===java.util.List<io.trino.spi.type.TypeSignatureParameter>===) + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::rowType(===java.util.List<io.trino.spi.type.TypeParameter>===) + 0 + Rename TypeSignatureParameter to TypeParameter + + + true + java.method.parameterTypeChanged + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::rowType(===io.trino.spi.type.TypeSignatureParameter[]===) + parameter io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::rowType(===io.trino.spi.type.TypeParameter[]===) + 0 + Rename TypeSignatureParameter to TypeParameter + + + true + java.class.removed + class io.trino.spi.type.TypeSignatureParameter + Rename TypeSignatureParameter to TypeParameter + + + true + java.class.removed + class io.trino.spi.type.NamedType + Removing NamedType and NamedTypeParameter + + + true + java.class.removed + class io.trino.spi.type.NamedTypeSignature + Removing NamedType and NamedTypeParameter + + + true + java.field.removed + field io.trino.spi.type.ParameterKind.NAMED_TYPE + Removing NamedType and NamedTypeParameter + + + true + java.class.removed + class io.trino.spi.type.RowFieldName + Removing NamedType and NamedTypeParameter + + + true + java.method.removed + method io.trino.spi.type.ParameterKind io.trino.spi.type.TypeParameter::getKind() + Improve type-safety of TypeParameter + + + true + java.method.removed + method java.lang.Long io.trino.spi.type.TypeParameter::getLongLiteral() + Improve type-safety of TypeParameter + + + true + java.method.removed + method <A> A io.trino.spi.type.TypeParameter::getValue(io.trino.spi.type.ParameterKind, java.lang.Class<A>) + Improve type-safety of TypeParameter + + + true + java.method.removed + method java.lang.String io.trino.spi.type.TypeParameter::getVariable() + Improve type-safety of TypeParameter + + + true + java.method.removed + method boolean io.trino.spi.type.TypeParameter::isLongLiteral() + Improve type-safety of TypeParameter + + + true + java.method.addedToInterface + method boolean io.trino.spi.type.TypeParameter::isCalculated() + Improve type-safety of TypeParameter + + + true + java.method.addedToInterface + method java.lang.String io.trino.spi.type.TypeParameter::jsonValue() + Improve type-safety of TypeParameter + + + true + java.class.kindChanged + class io.trino.spi.type.TypeParameter + interface io.trino.spi.type.TypeParameter + Improve type-safety of TypeParameter + + + true + java.class.nowAbstract + class io.trino.spi.type.TypeParameter + interface io.trino.spi.type.TypeParameter + Improve type-safety of TypeParameter + + + true + java.method.nowAbstract + method java.lang.String io.trino.spi.type.AbstractType::getDisplayName() + method java.lang.String io.trino.spi.type.Type::getDisplayName() @ io.trino.spi.type.AbstractType + Don't rely on TypeSignature for deriving the display name + + + true + java.method.removed + method java.util.List<io.trino.spi.type.TypeSignature> io.trino.spi.type.TypeSignature::getTypeParametersAsTypeSignatures() + Not needed. Use getParameters() instead. + + + true + java.method.removed + method io.trino.spi.type.TypeSignature io.trino.spi.type.TypeSignature::rowType(io.trino.spi.type.TypeSignatureParameter[]) + Method unused + + + true + java.method.removed + method io.trino.spi.function.Signature.Builder io.trino.spi.function.Signature.Builder::variadicTypeParameter(java.lang.String, java.lang.String) + Remove support for arbitrary variadic bounds + + + true + java.method.removed + method io.trino.spi.function.TypeVariableConstraint.TypeVariableConstraintBuilder io.trino.spi.function.TypeVariableConstraint.TypeVariableConstraintBuilder::variadicBound(java.lang.String) + Remove support for arbitrary variadic bounds + + + true + java.method.parameterTypeChanged + parameter io.trino.spi.function.TypeVariableConstraint io.trino.spi.function.TypeVariableConstraint::fromJson(java.lang.String, boolean, boolean, ===java.util.Optional<java.lang.String>===, java.util.Set<io.trino.spi.type.TypeSignature>, java.util.Set<io.trino.spi.type.TypeSignature>) + parameter io.trino.spi.function.TypeVariableConstraint io.trino.spi.function.TypeVariableConstraint::fromJson(java.lang.String, boolean, boolean, ===boolean===, java.util.Set<io.trino.spi.type.TypeSignature>, java.util.Set<io.trino.spi.type.TypeSignature>) + 3 + Remove support for arbitrary variadic bounds + + + true + java.method.removed + method java.util.Optional<java.lang.String> io.trino.spi.function.TypeVariableConstraint::getVariadicBound() + Remove support for arbitrary variadic bounds + + + true + java.annotation.attributeValueChanged + parameter io.trino.spi.function.TypeVariableConstraint io.trino.spi.function.TypeVariableConstraint::fromJson(java.lang.String, boolean, boolean, ===java.util.Optional<java.lang.String>===, java.util.Set<io.trino.spi.type.TypeSignature>, java.util.Set<io.trino.spi.type.TypeSignature>) + parameter io.trino.spi.function.TypeVariableConstraint io.trino.spi.function.TypeVariableConstraint::fromJson(java.lang.String, boolean, boolean, ===boolean===, java.util.Set<io.trino.spi.type.TypeSignature>, java.util.Set<io.trino.spi.type.TypeSignature>) + com.fasterxml.jackson.annotation.JsonProperty + value + "variadicBound" + "rowType" + Remove support for arbitrary variadic bounds + + + true + java.method.parameterTypeChanged + parameter void io.trino.spi.type.TypeNotFoundException::<init>(===io.trino.spi.type.TypeSignature===) + parameter void io.trino.spi.type.TypeNotFoundException::<init>(===java.lang.String===) + 0 + Remove TypeSignature dependency from + + + true + java.method.removed + method void io.trino.spi.type.TypeNotFoundException::<init>(io.trino.spi.type.TypeSignature, java.lang.Throwable) + Remove TypeSignature dependency from + + + true + java.annotation.attributeValueChanged + parameter void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, ===java.util.Map<io.trino.spi.QueryId, java.lang.Long>===, java.util.Map<java.lang.String, java.lang.Long>, java.util.Map<java.lang.String, java.lang.Long>) + parameter void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, ===java.util.Map<java.lang.String, java.lang.Long>===, java.util.Map<java.lang.String, java.lang.Long>) + com.fasterxml.jackson.annotation.JsonProperty + value + "queryMemoryRevocableReservations" + "taskMemoryReservations" + Removal of unused field + + + true + java.annotation.attributeValueChanged + parameter void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, ===java.util.Map<java.lang.String, java.lang.Long>===, java.util.Map<java.lang.String, java.lang.Long>) + parameter void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, java.util.Map<java.lang.String, java.lang.Long>, ===java.util.Map<java.lang.String, java.lang.Long>===) + com.fasterxml.jackson.annotation.JsonProperty + value + "taskMemoryReservations" + "taskMemoryRevocableReservations" + Removal of unused field + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<java.lang.String, java.lang.Long>, java.util.Map<java.lang.String, java.lang.Long>) + method void io.trino.spi.memory.MemoryPoolInfo::<init>(long, long, long, java.util.Map<io.trino.spi.QueryId, java.lang.Long>, java.util.Map<io.trino.spi.QueryId, java.util.List<io.trino.spi.memory.MemoryAllocation>>, java.util.Map<java.lang.String, java.lang.Long>, java.util.Map<java.lang.String, java.lang.Long>) + Removal of unused field + + + true + java.method.removed + method java.util.Map<io.trino.spi.QueryId, java.lang.Long> io.trino.spi.memory.MemoryPoolInfo::getQueryMemoryRevocableReservations() + Removal of unused field + + + true + java.annotation.removed + parameter void io.trino.spi.memory.MemoryAllocation::<init>(===java.lang.String===, long) + parameter void io.trino.spi.memory.MemoryAllocation::<init>(===java.lang.String===, long) + @com.fasterxml.jackson.annotation.JsonProperty("tag") + Class converted to a record + + + true + java.annotation.removed + parameter void io.trino.spi.memory.MemoryAllocation::<init>(java.lang.String, ===long===) + parameter void io.trino.spi.memory.MemoryAllocation::<init>(java.lang.String, ===long===) + @com.fasterxml.jackson.annotation.JsonProperty("allocation") + Class converted to a record + + + true + java.annotation.removed + method void io.trino.spi.memory.MemoryAllocation::<init>(java.lang.String, long) + method void io.trino.spi.memory.MemoryAllocation::<init>(java.lang.String, long) + @com.fasterxml.jackson.annotation.JsonCreator + Class converted to a record + + + true + java.method.removed + method long io.trino.spi.memory.MemoryAllocation::getAllocation() + Class converted to a record + + + true + java.method.removed + method java.lang.String io.trino.spi.memory.MemoryAllocation::getTag() + Class converted to a record + + + true + java.class.kindChanged + class io.trino.spi.memory.MemoryAllocation + class io.trino.spi.memory.MemoryAllocation + Class converted to a record + + + true + java.class.kindChanged + class io.trino.spi.NodeVersion + class io.trino.spi.NodeVersion + Class converted to Record + + + true + java.method.numberOfParametersChanged + method void io.trino.spi.eventlistener.QueryStatistics::<init>(java.time.Duration, java.time.Duration, java.time.Duration, java.time.Duration, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, long, long, long, long, long, long, long, long, long, long, long, long, long, long, double, double, java.util.List<io.trino.spi.eventlistener.StageGcStatistics>, int, boolean, java.util.List<io.trino.spi.eventlistener.StageCpuDistribution>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferUtilization>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferMetrics>, java.util.List<io.trino.spi.eventlistener.StageTaskStatistics>, java.util.List<io.trino.spi.eventlistener.DynamicFilterDomainStatistics>, java.util.function.Supplier<java.util.List<java.lang.String>>, java.util.List<io.trino.spi.eventlistener.QueryPlanOptimizerStatistics>, java.util.Map<java.lang.String, io.trino.spi.metrics.Metrics>, java.util.Optional<java.lang.String>) + method void io.trino.spi.eventlistener.QueryStatistics::<init>(java.time.Duration, java.time.Duration, java.time.Duration, java.time.Duration, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, java.util.Optional<java.time.Duration>, long, long, long, long, long, long, long, long, long, long, long, long, long, long, double, double, java.util.List<io.trino.spi.eventlistener.StageGcStatistics>, int, boolean, java.util.List<io.trino.spi.eventlistener.StageCpuDistribution>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferUtilization>, java.util.List<io.trino.spi.eventlistener.StageOutputBufferMetrics>, java.util.List<io.trino.spi.eventlistener.StageTaskStatistics>, java.util.List<io.trino.spi.eventlistener.DynamicFilterDomainStatistics>, java.util.function.Supplier<java.util.List<java.lang.String>>, java.util.List<io.trino.spi.eventlistener.QueryPlanOptimizerStatistics>, java.util.Map<java.lang.String, io.trino.spi.metrics.Metrics>, java.util.Map<java.lang.String, io.trino.spi.metrics.Metrics>, java.util.Optional<java.lang.String>) + Expose exchange performance metrics via event listener SPI + + + true + java.method.returnTypeChanged + method java.lang.String io.trino.spi.connector.ColumnMetadata::getComment() + method java.util.Optional<java.lang.String> io.trino.spi.connector.ColumnMetadata::getComment() + Make field optional + + + true + java.annotation.removed + method java.lang.String io.trino.spi.connector.ColumnMetadata::getComment() + method java.util.Optional<java.lang.String> io.trino.spi.connector.ColumnMetadata::getComment() + @jakarta.annotation.Nullable + Make field optional + + + true + java.method.returnTypeChanged + method java.lang.String io.trino.spi.connector.ColumnMetadata::getExtraInfo() + method java.util.Optional<java.lang.String> io.trino.spi.connector.ColumnMetadata::getExtraInfo() + Make field optional + + + true + java.annotation.removed + method java.lang.String io.trino.spi.connector.ColumnMetadata::getExtraInfo() + method java.util.Optional<java.lang.String> io.trino.spi.connector.ColumnMetadata::getExtraInfo() + @jakarta.annotation.Nullable + Make field optional + + + true + java.class.externalClassExposedInAPI + class io.opentelemetry.api.common.Empty + + + true + java.method.removed + method java.lang.String io.trino.spi.function.CatalogSchemaFunctionName::getCatalogName() + Class converted to a record + + + true + java.method.removed + method io.trino.spi.function.SchemaFunctionName io.trino.spi.function.CatalogSchemaFunctionName::getSchemaFunctionName() + Class converted to a record + + + true + java.class.kindChanged + class io.trino.spi.function.CatalogSchemaFunctionName + class io.trino.spi.function.CatalogSchemaFunctionName + Class converted to a record + + + true + java.annotation.removed + parameter void io.trino.spi.function.SchemaFunctionName::<init>(===java.lang.String===, java.lang.String) + parameter void io.trino.spi.function.SchemaFunctionName::<init>(===java.lang.String===, java.lang.String) + @com.fasterxml.jackson.annotation.JsonProperty("schemaName") + Class converted to a record + + + true + java.annotation.removed + parameter void io.trino.spi.function.SchemaFunctionName::<init>(java.lang.String, ===java.lang.String===) + parameter void io.trino.spi.function.SchemaFunctionName::<init>(java.lang.String, ===java.lang.String===) + @com.fasterxml.jackson.annotation.JsonProperty("functionName") + Class converted to a record + + + true + java.annotation.removed + method void io.trino.spi.function.SchemaFunctionName::<init>(java.lang.String, java.lang.String) + method void io.trino.spi.function.SchemaFunctionName::<init>(java.lang.String, java.lang.String) + @com.fasterxml.jackson.annotation.JsonCreator + Class converted to a record + + + true + java.method.removed + method java.lang.String io.trino.spi.function.SchemaFunctionName::getFunctionName() + Class converted to a record + + + true + java.method.removed + method java.lang.String io.trino.spi.function.SchemaFunctionName::getSchemaName() + Class converted to a record + + + true + java.class.kindChanged + class io.trino.spi.function.SchemaFunctionName + class io.trino.spi.function.SchemaFunctionName + Class converted to a record + + + true + java.method.removed + method java.lang.String io.trino.spi.function.CatalogSchemaFunctionName::getFunctionName() + Class converted to a record + + + true + java.method.removed + method java.lang.String io.trino.spi.function.CatalogSchemaFunctionName::getSchemaName() + Class converted to a record + + + true + java.method.removed + method int io.trino.spi.Location::getColumnNumber() + Location converted to a record class + + + true + java.method.removed + method int io.trino.spi.Location::getLineNumber() + Location converted to a record class + + + true + java.class.kindChanged + class io.trino.spi.Location + class io.trino.spi.Location + Location converted to a record class + + + true + java.annotation.removed + class io.trino.spi.Location + class io.trino.spi.Location + @com.google.errorprone.annotations.Immutable + Location converted to a record class + + + java.method.numberOfParametersChanged + method io.trino.spi.function.FunctionMetadata io.trino.spi.function.FunctionMetadata::fromJson(io.trino.spi.function.FunctionId, io.trino.spi.function.Signature, java.lang.String, java.util.Set<java.lang.String>, io.trino.spi.function.FunctionNullability, boolean, boolean, java.lang.String, io.trino.spi.function.FunctionKind, boolean) + method io.trino.spi.function.FunctionMetadata io.trino.spi.function.FunctionMetadata::fromJson(io.trino.spi.function.FunctionId, io.trino.spi.function.Signature, java.lang.String, java.util.Set<java.lang.String>, io.trino.spi.function.FunctionNullability, boolean, boolean, boolean, java.lang.String, io.trino.spi.function.FunctionKind, boolean) + Function declares whether it never fails + + + true + java.class.externalClassExposedInAPI + interface io.opentelemetry.api.trace.TraceFlagsBuilder + New OpenTelemetry API version + + + java.method.numberOfParametersChanged + method java.util.Optional<io.trino.spi.connector.ConnectorOutputMetadata> io.trino.spi.connector.ConnectorMetadata::finishRefreshMaterializedView(io.trino.spi.connector.ConnectorSession, io.trino.spi.connector.ConnectorTableHandle, io.trino.spi.connector.ConnectorInsertTableHandle, java.util.Collection<io.airlift.slice.Slice>, java.util.Collection<io.trino.spi.statistics.ComputedStatistics>, java.util.List<io.trino.spi.connector.ConnectorTableHandle>, boolean, boolean) + method java.util.Optional<io.trino.spi.connector.ConnectorOutputMetadata> io.trino.spi.connector.ConnectorMetadata::finishRefreshMaterializedView(io.trino.spi.connector.ConnectorSession, io.trino.spi.connector.ConnectorTableHandle, io.trino.spi.connector.ConnectorInsertTableHandle, java.util.Collection<io.airlift.slice.Slice>, java.util.Collection<io.trino.spi.statistics.ComputedStatistics>, java.util.List<io.trino.spi.connector.ConnectorTableHandle>, boolean, boolean, boolean) + Add hasNonDeterministicFunctions parameter to detect stale materialized views + diff --git a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java index 9fca0ee87906..e5541273ee9b 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java +++ b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java @@ -889,7 +889,8 @@ default Optional finishRefreshMaterializedView( Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, - boolean hasSourceTableFunctions) + boolean hasSourceTableFunctions, + boolean hasNonDeterministicFunctions) { throw new TrinoException(GENERIC_INTERNAL_ERROR, "ConnectorMetadata beginRefreshMaterializedView() is implemented without finishRefreshMaterializedView()"); } diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java index c651c30695da..818b5605bb4f 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java @@ -664,10 +664,10 @@ public ConnectorInsertTableHandle beginRefreshMaterializedView(ConnectorSession } @Override - public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions) + public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions, boolean hasNonDeterministicFunctions) { try (ThreadContextClassLoader _ = new ThreadContextClassLoader(classLoader)) { - return delegate.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, sourceTableHandles, hasForeignSourceTables, hasSourceTableFunctions); + return delegate.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, sourceTableHandles, hasForeignSourceTables, hasSourceTableFunctions, hasNonDeterministicFunctions); } } diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java index 28e119a909b6..9c5875aa37c9 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java @@ -520,6 +520,7 @@ public class IcebergMetadata private static final String DEPENDS_ON_TABLES = "dependsOnTables"; private static final String DEPENDS_ON_TABLE_FUNCTIONS = "dependsOnTableFunctions"; + private static final String DEPENDS_ON_NON_DETERMINISTIC_FUNCTIONS = "dependsOnNonDeterministicFunctions"; // Value should be ISO-8601 formatted time instant private static final String TRINO_QUERY_START_TIME = "trino-query-start-time"; @@ -4296,7 +4297,8 @@ public Optional finishRefreshMaterializedView( Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, - boolean hasSourceTableFunctions) + boolean hasSourceTableFunctions, + boolean hasNonDeterministicFunctions) { IcebergWritableTableHandle table = (IcebergWritableTableHandle) insertHandle; @@ -4358,6 +4360,7 @@ public Optional finishRefreshMaterializedView( // Update the 'dependsOnTables' property that tracks tables on which the materialized view depends and the corresponding snapshot ids of the tables appendFiles.set(DEPENDS_ON_TABLES, String.join(",", tableDependencies)); appendFiles.set(DEPENDS_ON_TABLE_FUNCTIONS, String.valueOf(hasSourceTableFunctions)); + appendFiles.set(DEPENDS_ON_NON_DETERMINISTIC_FUNCTIONS, String.valueOf(hasNonDeterministicFunctions)); appendFiles.set(TRINO_QUERY_START_TIME, session.getStart().toString()); appendFiles.scanManifestsWith(icebergScanExecutor); commitUpdateAndTransaction(appendFiles, session, transaction, "refresh materialized view"); @@ -4456,6 +4459,11 @@ public MaterializedViewFreshness getMaterializedViewFreshness(ConnectorSession s boolean dependsOnTableFunctions = currentSnapshot .map(snapshot -> Boolean.valueOf(snapshot.summary().getOrDefault(DEPENDS_ON_TABLE_FUNCTIONS, "false"))) .orElse(false); + // For MVs refreshed before non-deterministic function tracking was added this flag + // defaults to false. Such MVs will be correctly flagged after their next refresh. + boolean dependsOnNonDeterministicFunctions = currentSnapshot + .map(snapshot -> Boolean.valueOf(snapshot.summary().getOrDefault(DEPENDS_ON_NON_DETERMINISTIC_FUNCTIONS, "false"))) + .orElse(false); Optional refreshStartTime = currentSnapshot.map(snapshot -> snapshot.summary().get(TRINO_QUERY_START_TIME)) .map(Instant::parse); @@ -4468,6 +4476,12 @@ public MaterializedViewFreshness getMaterializedViewFreshness(ConnectorSession s return new MaterializedViewFreshness(UNKNOWN, refreshTime); } + if (dependsOnNonDeterministicFunctions) { + // Non-deterministic functions like current_timestamp produce different values over time, + // so the materialized view may be stale even if base tables haven't changed + return new MaterializedViewFreshness(UNKNOWN, refreshTime); + } + if (dependsOnTables.isEmpty()) { // Information missing. While it's "unknown" whether storage is stale, we return "stale". // Normally dependsOnTables may be missing only when there was no refresh yet. diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMaterializedViewTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMaterializedViewTest.java index 4615506222a8..34884fe1aa05 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMaterializedViewTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMaterializedViewTest.java @@ -42,6 +42,7 @@ import io.trino.spi.function.table.TableFunctionProcessorState; import io.trino.spi.function.table.TableFunctionSplitProcessor; import io.trino.spi.security.ConnectorIdentity; +import io.trino.spi.security.Identity; import io.trino.sql.tree.ExplainType; import io.trino.testing.AbstractTestQueryFramework; import io.trino.testing.MaterializedRow; @@ -52,7 +53,9 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.time.Instant; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.Optional; @@ -67,6 +70,7 @@ import static io.trino.plugin.iceberg.IcebergTestUtils.FILE_IO_FACTORY; import static io.trino.plugin.iceberg.IcebergTestUtils.getFileSystemFactory; import static io.trino.plugin.iceberg.IcebergTestUtils.withSmallRowGroups; +import static io.trino.server.testing.TestingTrinoServer.SESSION_START_TIME_PROPERTY; import static io.trino.spi.function.table.ReturnTypeSpecification.GenericTable.GENERIC_TABLE; import static io.trino.spi.function.table.TableFunctionProcessorState.Finished.FINISHED; import static io.trino.spi.function.table.TableFunctionProcessorState.Processed.produced; @@ -947,6 +951,146 @@ public void testMaterializedViewCreatedFromTableFunctionWithGracePeriod() assertThat(result4).isNotEqualTo(result3); } + @Test + public void testMaterializedViewWithNonDeterministicFunction() + { + String sourceTableName = "source_table_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + sourceTableName + " (value INTEGER)"); + assertUpdate("INSERT INTO " + sourceTableName + " VALUES 1", 1); + + // Test with current_timestamp in SELECT list + String mvName = "mv_with_current_timestamp_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName + " AS SELECT *, current_timestamp AS ts FROM " + sourceTableName); + + assertFreshness(mvName, "STALE"); + assertThat(getLastFreshTime(mvName)).isNull(); + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName, 1); + // After refresh, MV should be UNKNOWN (not FRESH) because it uses current_timestamp + assertFreshness(mvName, "UNKNOWN"); + assertThat(getLastFreshTime(mvName)).isNotNull(); + // With no grace period clause (unlimited), UNKNOWN freshness still serves cached data + ZonedDateTime cachedTs1 = (ZonedDateTime) computeActual("SELECT ts FROM " + mvName).getOnlyValue(); + ZonedDateTime cachedTs2 = (ZonedDateTime) computeActual("SELECT ts FROM " + mvName).getOnlyValue(); + assertThat(cachedTs2).isEqualTo(cachedTs1); + + // Test with current_timestamp in WHERE clause + String mvName2 = "mv_with_timestamp_in_where_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName2 + " AS SELECT * FROM " + sourceTableName + + " WHERE current_timestamp > TIMESTAMP '2000-01-01 00:00:00.000 UTC'"); + + assertFreshness(mvName2, "STALE"); + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName2, 1); + assertFreshness(mvName2, "UNKNOWN"); + + // Test with random() to verify detection via analysis.getResolvedFunctions() rather than AST node + String mvName3 = "mv_with_random_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName3 + " AS SELECT *, random() AS rand_val FROM " + sourceTableName); + + assertFreshness(mvName3, "STALE"); + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName3, 1); + assertFreshness(mvName3, "UNKNOWN"); + + // Verify that a deterministic MV is still FRESH after refresh (backward compatibility) + String mvName4 = "mv_deterministic_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName4 + " AS SELECT * FROM " + sourceTableName); + + assertFreshness(mvName4, "STALE"); + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName4, 1); + assertFreshness(mvName4, "FRESH"); + + assertUpdate("DROP MATERIALIZED VIEW " + mvName); + assertUpdate("DROP MATERIALIZED VIEW " + mvName2); + assertUpdate("DROP MATERIALIZED VIEW " + mvName3); + assertUpdate("DROP MATERIALIZED VIEW " + mvName4); + assertUpdate("DROP TABLE " + sourceTableName); + } + + @Test + public void testMaterializedViewWithSessionScopedExpressions() + { + String sourceTableName = "source_table_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + sourceTableName + " (value INTEGER)"); + assertUpdate("INSERT INTO " + sourceTableName + " VALUES 1", 1); + + // Session-scoped expressions (current_user, current_catalog, current_schema, current_path) + // are constants for materialized views (fixed at creation time), so the MV should be FRESH after refresh + String mvName = "mv_session_scoped_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName + " AS SELECT *, current_user AS created_by FROM " + sourceTableName); + + assertFreshness(mvName, "STALE"); + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName, 1); + assertFreshness(mvName, "FRESH"); + assertQuery("SELECT created_by FROM " + mvName, "VALUES 'user'"); + + // A different user querying the MV still sees the original creator's name + // because the MV is FRESH and returns cached data + Session otherUserSession = Session.builder(getSession()) + .setIdentity(Identity.ofUser("other_user")) + .build(); + assertQuery(otherUserSession, "SELECT created_by FROM " + mvName, "VALUES 'user'"); + + assertUpdate("INSERT INTO " + sourceTableName + " VALUES 2", 1); + assertFreshness(mvName, "STALE"); + // Stale MV still serves cached data from storage + assertQuery(otherUserSession, "SELECT created_by FROM " + mvName, "VALUES 'user'"); + // Refresh by a different user picks up the new row + assertUpdate(otherUserSession, "REFRESH MATERIALIZED VIEW " + mvName, 1); + assertFreshness(mvName, "FRESH"); + // TODO https://github.com/trinodb/trino/issues/28738 session-scoped expressions should resolve using + // the MV owner's identity during refresh (like the stale inline path does via analyzeView), but currently + // the refresh path resolves them from the refreshing user's session. + // When fixed, this should be: VALUES ('user'), ('user') + assertQuery("SELECT created_by FROM " + mvName, "VALUES ('user'), ('other_user')"); + + assertUpdate("DROP MATERIALIZED VIEW " + mvName); + assertUpdate("DROP TABLE " + sourceTableName); + } + + @Test + public void testMaterializedViewWithNonDeterministicFunctionAndGracePeriod() + { + String sourceTableName = "source_table_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + sourceTableName + " (value INTEGER)"); + assertUpdate("INSERT INTO " + sourceTableName + " VALUES 1", 1); + + String mvName = "mv_nondet_grace_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + mvName + " GRACE PERIOD INTERVAL '1' HOUR" + + " AS SELECT CURRENT_TIMESTAMP AS ts FROM " + sourceTableName); + + assertFreshness(mvName, "STALE"); + assertThat(getLastFreshTime(mvName)).isNull(); + ZonedDateTime ts1 = (ZonedDateTime) computeActual("SELECT * FROM " + mvName).getOnlyValue(); + ZonedDateTime ts2 = (ZonedDateTime) computeActual("SELECT * FROM " + mvName).getOnlyValue(); + // Each SELECT re-executes query since MV is STALE, so timestamps differ + assertThat(ts2).isNotEqualTo(ts1); + + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName, 1); + assertFreshness(mvName, "UNKNOWN"); + ZonedDateTime lastFreshTime = getLastFreshTime(mvName); + assertThat(lastFreshTime).isNotNull(); + + // SELECT within grace period returns cached data + ZonedDateTime cachedTs = (ZonedDateTime) computeActual("SELECT * FROM " + mvName).getOnlyValue(); + ZonedDateTime cachedTs2 = (ZonedDateTime) computeActual("SELECT * FROM " + mvName).getOnlyValue(); + assertThat(cachedTs2).isEqualTo(cachedTs); + + // SELECT with session start beyond grace period re-executes base query, gets fresh timestamp + Session afterGracePeriod = Session.builder(getSession()) + .setSystemProperty(SESSION_START_TIME_PROPERTY, Instant.now().plus(1, ChronoUnit.DAYS).toString()) + .build(); + ZonedDateTime freshTs = (ZonedDateTime) computeActual(afterGracePeriod, "SELECT * FROM " + mvName).getOnlyValue(); + assertThat(freshTs).isNotEqualTo(cachedTs); + + // Refresh again and verify new cached data is served, with updated last_fresh_time + assertUpdate("REFRESH MATERIALIZED VIEW " + mvName, 1); + assertThat(getLastFreshTime(mvName)).isAfter(lastFreshTime); + ZonedDateTime newCachedTs = (ZonedDateTime) computeActual("SELECT * FROM " + mvName).getOnlyValue(); + assertThat(newCachedTs).isNotEqualTo(cachedTs); + + assertUpdate("DROP MATERIALIZED VIEW " + mvName); + assertUpdate("DROP TABLE " + sourceTableName); + } + @Test public void testIncrementalRefresh() { @@ -988,6 +1132,44 @@ public void testIncrementalRefresh() assertUpdate("DROP TABLE %s".formatted(sourceTableName)); } + @Test + public void testFullRefreshForNonDeterministicFunction() + { + String sourceTableName = "source_table" + randomNameSuffix(); + String materializedViewName = "test_materialized_view_" + randomNameSuffix(); + + assertUpdate("CREATE TABLE %s (a int, b varchar)".formatted(sourceTableName)); + assertUpdate("INSERT INTO %s VALUES (1, 'abc'), (2, 'def')".formatted(sourceTableName), 2); + + // non-deterministic function in SELECT + String mvInSelect = materializedViewName + "_select"; + assertUpdate("CREATE MATERIALIZED VIEW %s AS SELECT a, b, current_timestamp AS ts FROM %s WHERE a < 3 OR a > 5".formatted(mvInSelect, sourceTableName)); + + // non-deterministic function in WHERE + String mvInWhere = materializedViewName + "_where"; + assertUpdate("CREATE MATERIALIZED VIEW %s AS SELECT a, b FROM %s WHERE (a < 3 OR a > 5) AND current_timestamp > timestamp '2000-01-01'".formatted(mvInWhere, sourceTableName)); + + // first refresh is always full, should contain 2 rows + assertUpdate("REFRESH MATERIALIZED VIEW %s".formatted(mvInSelect), 2); + assertUpdate("REFRESH MATERIALIZED VIEW %s".formatted(mvInWhere), 2); + + // add new rows to source + assertUpdate("INSERT INTO %s VALUES (3, 'ghi'), (4, 'jkl'), (5, 'mno'), (6, 'pqr')".formatted(sourceTableName), 4); + + // second refresh should be full too because of non-deterministic function + // full refresh should return rows matching filter: (1, 'abc'), (2, 'def'), (6, 'pqr') = 3 rows + // incremental would only return the new matching row: (6, 'pqr') = 1 row + assertUpdate("REFRESH MATERIALIZED VIEW %s".formatted(mvInSelect), 3); + assertUpdate("REFRESH MATERIALIZED VIEW %s".formatted(mvInWhere), 3); + assertThat(query("SELECT a, b FROM %s".formatted(mvInSelect))).matches("VALUES (1, VARCHAR 'abc'), (2, VARCHAR 'def'), (6, VARCHAR 'pqr')"); + assertThat(query("SELECT a, b FROM %s".formatted(mvInWhere))).matches("VALUES (1, VARCHAR 'abc'), (2, VARCHAR 'def'), (6, VARCHAR 'pqr')"); + + // cleanup + assertUpdate("DROP MATERIALIZED VIEW %s".formatted(mvInSelect)); + assertUpdate("DROP MATERIALIZED VIEW %s".formatted(mvInWhere)); + assertUpdate("DROP TABLE %s".formatted(sourceTableName)); + } + @Test public void testFullRefreshForUnion() { @@ -1155,6 +1337,11 @@ private void assertFreshness(String viewName, String expected) assertThat((String) computeScalar("SELECT freshness FROM system.metadata.materialized_views WHERE catalog_name = CURRENT_CATALOG AND schema_name = CURRENT_SCHEMA AND name = '" + viewName + "'")).isEqualTo(expected); } + private ZonedDateTime getLastFreshTime(String viewName) + { + return (ZonedDateTime) computeActual("SELECT last_fresh_time FROM system.metadata.materialized_views WHERE catalog_name = CURRENT_CATALOG AND schema_name = CURRENT_SCHEMA AND name = '" + viewName + "'").getOnlyValue(); + } + public static class SequenceTableFunction extends AbstractConnectorTableFunction { diff --git a/plugin/trino-lakehouse/src/main/java/io/trino/plugin/lakehouse/LakehouseMetadata.java b/plugin/trino-lakehouse/src/main/java/io/trino/plugin/lakehouse/LakehouseMetadata.java index 218c2ec01d83..6d7bb516517d 100644 --- a/plugin/trino-lakehouse/src/main/java/io/trino/plugin/lakehouse/LakehouseMetadata.java +++ b/plugin/trino-lakehouse/src/main/java/io/trino/plugin/lakehouse/LakehouseMetadata.java @@ -597,13 +597,13 @@ public ConnectorInsertTableHandle beginRefreshMaterializedView(ConnectorSession } @Override - public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions) + public Optional finishRefreshMaterializedView(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics, List sourceTableHandles, boolean hasForeignSourceTables, boolean hasSourceTableFunctions, boolean hasNonDeterministicFunctions) { List icebergSourceHandles = sourceTableHandles.stream() .filter(IcebergTableHandle.class::isInstance) .toList(); hasForeignSourceTables |= icebergSourceHandles.size() < sourceTableHandles.size(); - return icebergMetadata.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, icebergSourceHandles, hasForeignSourceTables, hasSourceTableFunctions); + return icebergMetadata.finishRefreshMaterializedView(session, tableHandle, insertHandle, fragments, computedStatistics, icebergSourceHandles, hasForeignSourceTables, hasSourceTableFunctions, hasNonDeterministicFunctions); } @Override