6666import io .trino .spi .connector .ColumnHandle ;
6767import io .trino .spi .connector .ColumnMetadata ;
6868import io .trino .spi .connector .ColumnSchema ;
69+ import io .trino .spi .connector .ConnectorMaterializedViewDefinition .WhenStaleBehavior ;
6970import io .trino .spi .connector .ConnectorTableMetadata ;
7071import io .trino .spi .connector .ConnectorTransactionHandle ;
7172import io .trino .spi .connector .MaterializedViewFreshness ;
@@ -2285,6 +2286,7 @@ protected Scope visitTable(Table table, Optional<Scope> scope)
22852286 if (optionalMaterializedView .isPresent ()) {
22862287 MaterializedViewDefinition materializedViewDefinition = optionalMaterializedView .get ();
22872288 analysis .addEmptyColumnReferencesForTable (accessControl , session .getIdentity (), name );
2289+ boolean useLogicalViewSemantics = shouldUseLogicalViewSemantics (materializedViewDefinition );
22882290 if (isMaterializedViewSufficientlyFresh (session , name , materializedViewDefinition )) {
22892291 // If materialized view is sufficiently fresh with respect to its grace period, answer the query using the storage table
22902292 QualifiedName storageName = getMaterializedViewStorageTableName (materializedViewDefinition )
@@ -2293,10 +2295,13 @@ protected Scope visitTable(Table table, Optional<Scope> scope)
22932295 checkStorageTableNotRedirected (storageTableName );
22942296 TableHandle tableHandle = metadata .getTableHandle (session , storageTableName )
22952297 .orElseThrow (() -> semanticException (INVALID_VIEW , table , "Storage table '%s' does not exist" , storageTableName ));
2296- return createScopeForMaterializedView (table , name , scope , materializedViewDefinition , Optional .of (tableHandle ));
2298+ return createScopeForMaterializedView (table , name , scope , materializedViewDefinition , Optional .of (tableHandle ), useLogicalViewSemantics );
2299+ }
2300+ else if (!useLogicalViewSemantics ) {
2301+ throw semanticException (VIEW_IS_STALE , table , "Materialized view '%s' is stale" , name );
22972302 }
22982303 // This is a stale materialized view and should be expanded like a logical view
2299- return createScopeForMaterializedView (table , name , scope , materializedViewDefinition , Optional .empty ());
2304+ return createScopeForMaterializedView (table , name , scope , materializedViewDefinition , Optional .empty (), useLogicalViewSemantics );
23002305 }
23012306
23022307 // This could be a reference to a logical view or a table
@@ -2385,6 +2390,15 @@ private boolean isMaterializedViewSufficientlyFresh(Session session, QualifiedOb
23852390 return staleness .compareTo (gracePeriod ) <= 0 ;
23862391 }
23872392
2393+ private static boolean shouldUseLogicalViewSemantics (MaterializedViewDefinition materializedViewDefinition )
2394+ {
2395+ WhenStaleBehavior whenStale = materializedViewDefinition .getWhenStaleBehavior ().orElse (WhenStaleBehavior .INLINE );
2396+ return switch (whenStale ) {
2397+ case WhenStaleBehavior .INLINE -> true ;
2398+ case WhenStaleBehavior .FAIL -> false ;
2399+ };
2400+ }
2401+
23882402 private void checkStorageTableNotRedirected (QualifiedObjectName source )
23892403 {
23902404 metadata .getRedirectionAwareTableHandle (session , source ).redirectedTableName ().ifPresent (name -> {
@@ -2529,7 +2543,13 @@ private Scope createScopeForCommonTableExpression(Table table, Optional<Scope> s
25292543 return createAndAssignScope (table , scope , fields );
25302544 }
25312545
2532- private Scope createScopeForMaterializedView (Table table , QualifiedObjectName name , Optional <Scope > scope , MaterializedViewDefinition view , Optional <TableHandle > storageTable )
2546+ private Scope createScopeForMaterializedView (
2547+ Table table ,
2548+ QualifiedObjectName name ,
2549+ Optional <Scope > scope ,
2550+ MaterializedViewDefinition view ,
2551+ Optional <TableHandle > storageTable ,
2552+ boolean useLogicalViewSemantics )
25332553 {
25342554 return createScopeForView (
25352555 table ,
@@ -2542,7 +2562,8 @@ private Scope createScopeForMaterializedView(Table table, QualifiedObjectName na
25422562 view .getPath (),
25432563 view .getColumns (),
25442564 storageTable ,
2545- true );
2565+ true ,
2566+ useLogicalViewSemantics );
25462567 }
25472568
25482569 private Scope createScopeForView (Table table , QualifiedObjectName name , Optional <Scope > scope , ViewDefinition view )
@@ -2557,7 +2578,8 @@ private Scope createScopeForView(Table table, QualifiedObjectName name, Optional
25572578 view .getPath (),
25582579 view .getColumns (),
25592580 Optional .empty (),
2560- false );
2581+ false ,
2582+ true );
25612583 }
25622584
25632585 private Scope createScopeForView (
@@ -2571,7 +2593,8 @@ private Scope createScopeForView(
25712593 List <CatalogSchemaName > path ,
25722594 List <ViewColumn > columns ,
25732595 Optional <TableHandle > storageTable ,
2574- boolean isMaterializedView )
2596+ boolean isMaterializedView ,
2597+ boolean useLogicalViewSemantics )
25752598 {
25762599 Statement statement = analysis .getStatement ();
25772600 if (statement instanceof CreateView viewStatement ) {
@@ -2590,18 +2613,27 @@ private Scope createScopeForView(
25902613 throw semanticException (VIEW_IS_RECURSIVE , table , "View is recursive" );
25912614 }
25922615
2593- Query query = parseView (originalSql , name , table );
2616+ if (useLogicalViewSemantics ) {
2617+ Query query = parseView (originalSql , name , table );
25942618
2595- if (!query .getFunctions ().isEmpty ()) {
2596- throw semanticException (NOT_SUPPORTED , table , "View contains inline function: %s" , name );
2597- }
2619+ if (!query .getFunctions ().isEmpty ()) {
2620+ throw semanticException (NOT_SUPPORTED , table , "View contains inline function: %s" , name );
2621+ }
25982622
2599- analysis .registerTableForView (table , name , isMaterializedView );
2600- RelationType descriptor = analyzeView (query , name , catalog , schema , owner , path , table );
2601- analysis .unregisterTableForView ();
2623+ analysis .registerTableForView (table , name , isMaterializedView );
2624+ RelationType descriptor = analyzeView (query , name , catalog , schema , owner , path , table );
2625+ analysis .unregisterTableForView ();
26022626
2603- checkViewStaleness (columns , descriptor .getVisibleFields (), name , table )
2604- .ifPresent (explanation -> { throw semanticException (VIEW_IS_STALE , table , "View '%s' is stale or in invalid state: %s" , name , explanation ); });
2627+ checkViewStaleness (columns , descriptor .getVisibleFields (), name , table )
2628+ .ifPresent (explanation -> { throw semanticException (VIEW_IS_STALE , table , "View '%s' is stale or in invalid state: %s" , name , explanation ); });
2629+
2630+ if (storageTable .isEmpty ()) {
2631+ analysis .registerNamedQuery (table , query );
2632+ }
2633+ }
2634+ else {
2635+ checkArgument (storageTable .isPresent (), "A storage table must be present when query analysis is skipped" );
2636+ }
26052637
26062638 // Derive the type of the view from the stored definition, not from the analysis of the underlying query.
26072639 // This is needed in case the underlying table(s) changed and the query in the view now produces types that
@@ -2621,9 +2653,6 @@ private Scope createScopeForView(
26212653 List <Field > storageTableFields = analyzeStorageTable (table , viewFields , storageTable .get ());
26222654 analysis .setMaterializedViewStorageTableFields (table , storageTableFields );
26232655 }
2624- else {
2625- analysis .registerNamedQuery (table , query );
2626- }
26272656
26282657 Scope accessControlScope = Scope .builder ()
26292658 .withRelationType (RelationId .anonymous (), new RelationType (viewFields ))
0 commit comments