This is an automated email from the ASF dual-hosted git repository.

singhpk234 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/main by this push:
     new 67ed9d1165 CORE: Allow table level override for scan planning (#15572)
67ed9d1165 is described below

commit 67ed9d116581cc3d45d8c8f205eeaa1743d8d171
Author: Prashant Singh <[email protected]>
AuthorDate: Tue Mar 17 16:58:37 2026 -0700

    CORE: Allow table level override for scan planning (#15572)
    
    * Core: Simplify REST scan planning to 2 modes (client/catalog)
    
    Simplified scan planning configuration from boolean to 2-mode enum:
    - client (default): Use client-side scan planning
    - catalog: Use server-side scan planning if supported
    
    Changes:
    - RESTCatalogProperties: Added ScanPlanningMode enum with CLIENT and CATALOG
    - RESTSessionCatalog: Updated to check table config for scan planning mode
    - Updated OpenAPI specs with simplified documentation
    
    The mode can be configured per-table via LoadTableResponse.config() to
    allow fine-grained control over which tables use server-side planning.
    
    * address steven feedback
    
    * address peters feedback
    
    * address review feedback
    
    * more clean-up
    
    * Address feedback
    
    * Convert scan planning mode mismatch from exception to log warning
    
    When client and server have conflicting scan planning modes, log a
    warning instead of throwing IllegalStateException. Server config
    silently takes precedence.
    
    * Address Amogh's review feedback
    
    - Use Arrays.stream(values()) to dynamically list valid scan planning modes 
in error message
    - Simplify verbose comments in TestRESTScanPlanning
    - Fix fileIOForRemotePlanningIsPropagated to use SCAN_PLANNING_MODE after 
rebase
    
    * Address nastra's comments
    
    ---------
    
    Co-authored-by: Prashant Singh <[email protected]>
---
 .../apache/iceberg/rest/RESTCatalogProperties.java |  34 +++-
 .../apache/iceberg/rest/RESTSessionCatalog.java    |  53 ++++--
 .../iceberg/rest/TestBaseWithRESTServer.java       |   6 +-
 .../apache/iceberg/rest/TestRESTScanPlanning.java  | 189 +++++++++++++++++----
 .../spark/extensions/TestRemoteScanPlanning.java   |   4 +-
 .../spark/extensions/TestRemoteScanPlanning.java   |   4 +-
 .../spark/extensions/TestRemoteScanPlanning.java   |   4 +-
 .../spark/extensions/TestRemoteScanPlanning.java   |   4 +-
 8 files changed, 244 insertions(+), 54 deletions(-)

diff --git 
a/core/src/main/java/org/apache/iceberg/rest/RESTCatalogProperties.java 
b/core/src/main/java/org/apache/iceberg/rest/RESTCatalogProperties.java
index 7281862481..cda81b1d0d 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTCatalogProperties.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTCatalogProperties.java
@@ -18,7 +18,10 @@
  */
 package org.apache.iceberg.rest;
 
+import java.util.Arrays;
+import java.util.Locale;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 public final class RESTCatalogProperties {
 
@@ -40,9 +43,9 @@ public final class RESTCatalogProperties {
 
   public static final String NAMESPACE_SEPARATOR = "namespace-separator";
 
-  // Enable planning on the REST server side
-  public static final String REST_SCAN_PLANNING_ENABLED = 
"rest-scan-planning-enabled";
-  public static final boolean REST_SCAN_PLANNING_ENABLED_DEFAULT = false;
+  // Configure scan planning mode
+  // Can be set by server in LoadTableResponse.config() for table-level 
override
+  public static final String SCAN_PLANNING_MODE = "scan-planning-mode";
 
   public static final String REST_SCAN_PLAN_ID = "rest-scan-plan-id";
 
@@ -59,4 +62,29 @@ public final class RESTCatalogProperties {
     ALL,
     REFS
   }
+
+  public enum ScanPlanningMode {
+    CLIENT,
+    SERVER;
+
+    public String modeName() {
+      return name().toLowerCase(Locale.ROOT);
+    }
+
+    public static ScanPlanningMode fromString(String mode) {
+      for (ScanPlanningMode planningMode : values()) {
+        if (planningMode.modeName().equalsIgnoreCase(mode)) {
+          return planningMode;
+        }
+      }
+
+      throw new IllegalArgumentException(
+          String.format(
+              "Invalid scan planning mode: %s. Valid values are: %s",
+              mode,
+              Arrays.stream(values())
+                  .map(ScanPlanningMode::modeName)
+                  .collect(Collectors.joining(", "))));
+    }
+  }
 }
diff --git a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java 
b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
index cda71fccda..409615d624 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
@@ -166,7 +166,6 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
   private MetricsReporter reporter = null;
   private boolean reportingViaRestEnabled;
   private Integer pageSize = null;
-  private boolean restScanPlanningEnabled;
   private CloseableGroup closeables = null;
   private Set<Endpoint> endpoints;
   private Supplier<Map<String, String>> mutationHeaders = Map::of;
@@ -281,12 +280,6 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
             RESTCatalogProperties.NAMESPACE_SEPARATOR,
             RESTUtil.NAMESPACE_SEPARATOR_URLENCODED_UTF_8);
 
-    this.restScanPlanningEnabled =
-        PropertyUtil.propertyAsBoolean(
-            mergedProps,
-            RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED,
-            RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED_DEFAULT);
-
     this.tableCache = createTableCache(mergedProps);
     this.closeables.addCloseable(this.tableCache);
 
@@ -584,7 +577,7 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
 
       trackFileIO(ops);
 
-      RESTTable table = restTableForScanPlanning(ops, identifier, tableClient);
+      RESTTable table = restTableForScanPlanning(ops, identifier, tableClient, 
tableConf);
       if (table != null) {
         return table;
       }
@@ -595,9 +588,41 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
   }
 
   private RESTTable restTableForScanPlanning(
-      TableOperations ops, TableIdentifier finalIdentifier, RESTClient 
restClient) {
-    // server supports remote planning endpoint and server / client wants to 
do server side planning
-    if (endpoints.contains(Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN) && 
restScanPlanningEnabled) {
+      TableOperations ops,
+      TableIdentifier finalIdentifier,
+      RESTClient restClient,
+      Map<String, String> tableConf) {
+    // Get client-side and server-side scan planning modes
+    String planningModeClientConfig = 
properties().get(RESTCatalogProperties.SCAN_PLANNING_MODE);
+    String planningModeServerConfig = 
tableConf.get(RESTCatalogProperties.SCAN_PLANNING_MODE);
+
+    // Warn if client and server configs conflict; server config takes 
precedence
+    if (planningModeClientConfig != null
+        && planningModeServerConfig != null
+        && 
!planningModeClientConfig.equalsIgnoreCase(planningModeServerConfig)) {
+      LOG.warn(
+          "Scan planning mode mismatch for table {}: client config={}, server 
config={}. "
+              + "Server config will take precedence.",
+          finalIdentifier,
+          planningModeClientConfig,
+          planningModeServerConfig);
+    }
+
+    // Determine effective mode: prefer server config if present, otherwise 
use client config
+    String effectiveModeConfig =
+        planningModeServerConfig != null ? planningModeServerConfig : 
planningModeClientConfig;
+    RESTCatalogProperties.ScanPlanningMode effectiveMode =
+        effectiveModeConfig != null
+            ? 
RESTCatalogProperties.ScanPlanningMode.fromString(effectiveModeConfig)
+            : RESTCatalogProperties.ScanPlanningMode.CLIENT;
+
+    if (effectiveMode == RESTCatalogProperties.ScanPlanningMode.SERVER) {
+      Preconditions.checkState(
+          endpoints.contains(Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN),
+          "Server requires server-side scan planning for table %s but does not 
support endpoint %s",
+          finalIdentifier,
+          Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN);
+
       return new RESTTable(
           ops,
           fullTableName(finalIdentifier),
@@ -610,6 +635,8 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
           properties(),
           conf);
     }
+
+    // Default to client-side planning
     return null;
   }
 
@@ -683,7 +710,7 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
 
     trackFileIO(ops);
 
-    RESTTable restTable = restTableForScanPlanning(ops, ident, tableClient);
+    RESTTable restTable = restTableForScanPlanning(ops, ident, tableClient, 
tableConf);
     if (restTable != null) {
       return restTable;
     }
@@ -952,7 +979,7 @@ public class RESTSessionCatalog extends 
BaseViewSessionCatalog
 
       trackFileIO(ops);
 
-      RESTTable restTable = restTableForScanPlanning(ops, ident, tableClient);
+      RESTTable restTable = restTableForScanPlanning(ops, ident, tableClient, 
tableConf);
       if (restTable != null) {
         return restTable;
       }
diff --git 
a/core/src/test/java/org/apache/iceberg/rest/TestBaseWithRESTServer.java 
b/core/src/test/java/org/apache/iceberg/rest/TestBaseWithRESTServer.java
index f1a172a423..a79977c246 100644
--- a/core/src/test/java/org/apache/iceberg/rest/TestBaseWithRESTServer.java
+++ b/core/src/test/java/org/apache/iceberg/rest/TestBaseWithRESTServer.java
@@ -81,7 +81,7 @@ public abstract class TestBaseWithRESTServer {
     httpServer.setHandler(servletContext);
     httpServer.start();
 
-    restCatalog = initCatalog(catalogName(), ImmutableMap.of());
+    restCatalog = initCatalog(catalogName(), additionalCatalogProperties());
   }
 
   @AfterEach
@@ -119,6 +119,10 @@ public abstract class TestBaseWithRESTServer {
 
   protected abstract String catalogName();
 
+  protected Map<String, String> additionalCatalogProperties() {
+    return ImmutableMap.of();
+  }
+
   @SuppressWarnings("unchecked")
   protected <T> T roundTripSerialize(T payload, String description) {
     if (payload != null) {
diff --git 
a/core/src/test/java/org/apache/iceberg/rest/TestRESTScanPlanning.java 
b/core/src/test/java/org/apache/iceberg/rest/TestRESTScanPlanning.java
index 6ee257026b..cdde30abe0 100644
--- a/core/src/test/java/org/apache/iceberg/rest/TestRESTScanPlanning.java
+++ b/core/src/test/java/org/apache/iceberg/rest/TestRESTScanPlanning.java
@@ -35,15 +35,12 @@ import static org.mockito.ArgumentMatchers.any;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectReader;
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Function;
-import java.util.stream.Collectors;
+import org.apache.iceberg.BaseTable;
 import org.apache.iceberg.CatalogProperties;
-import org.apache.iceberg.ContentFile;
-import org.apache.iceberg.ContentScanTask;
 import org.apache.iceberg.DataFile;
 import org.apache.iceberg.DataFiles;
 import org.apache.iceberg.DeleteFile;
@@ -69,6 +66,7 @@ import org.apache.iceberg.rest.requests.PlanTableScanRequest;
 import org.apache.iceberg.rest.responses.ConfigResponse;
 import org.apache.iceberg.rest.responses.ErrorResponse;
 import org.apache.iceberg.rest.responses.FetchPlanningResultResponse;
+import org.apache.iceberg.rest.responses.LoadTableResponse;
 import org.apache.iceberg.rest.responses.PlanTableScanResponse;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -88,22 +86,22 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
               Class<T> responseType,
               Consumer<ErrorResponse> errorHandler,
               Consumer<Map<String, String>> responseHeaders) {
-            if (ResourcePaths.config().equals(request.path())) {
-              return castResponse(
-                  responseType,
-                  ConfigResponse.builder()
-                      .withEndpoints(
-                          Arrays.stream(Route.values())
-                              .map(r -> Endpoint.create(r.method().name(), 
r.resourcePath()))
-                              .collect(Collectors.toList()))
-                      .withOverrides(
-                          
ImmutableMap.of(RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED, "true"))
-                      .build());
-            }
+            // roundTripSerialize before intercepting so we modify the 
deserialized response
             Object body = roundTripSerialize(request.body(), "request");
             HTTPRequest req = 
ImmutableHTTPRequest.builder().from(request).body(body).build();
             T response = super.execute(req, responseType, errorHandler, 
responseHeaders);
-            return roundTripSerialize(response, "response");
+            response = roundTripSerialize(response, "response");
+
+            // Add scan planning mode to table config for LoadTableResponse
+            if (response instanceof LoadTableResponse) {
+              return castResponse(
+                  responseType,
+                  withPlanningMode(
+                      (LoadTableResponse) response,
+                      
RESTCatalogProperties.ScanPlanningMode.SERVER.modeName()));
+            }
+
+            return response;
           }
         });
   }
@@ -113,8 +111,24 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
     return "prod-with-scan-planning";
   }
 
+  @Override
+  protected Map<String, String> additionalCatalogProperties() {
+    return ImmutableMap.of(
+        RESTCatalogProperties.SCAN_PLANNING_MODE,
+        RESTCatalogProperties.ScanPlanningMode.SERVER.modeName());
+  }
+
   // ==================== Helper Methods ====================
 
+  private static LoadTableResponse withPlanningMode(LoadTableResponse 
response, String mode) {
+    return LoadTableResponse.builder()
+        .withTableMetadata(response.tableMetadata())
+        .addAllConfig(response.config())
+        .addConfig(RESTCatalogProperties.SCAN_PLANNING_MODE, mode)
+        .addAllCredentials(response.credentials())
+        .build();
+  }
+
   @Override
   @SuppressWarnings("unchecked")
   protected <T> T roundTripSerialize(T payload, String description) {
@@ -848,6 +862,41 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
     }
   }
 
+  private CatalogWithAdapter catalogWithModes(String clientMode, String 
serverMode) {
+    RESTCatalogAdapter adapter =
+        Mockito.spy(
+            new RESTCatalogAdapter(backendCatalog) {
+              @Override
+              public <T extends RESTResponse> T execute(
+                  HTTPRequest request,
+                  Class<T> responseType,
+                  Consumer<ErrorResponse> errorHandler,
+                  Consumer<Map<String, String>> responseHeaders) {
+                T response = super.execute(request, responseType, 
errorHandler, responseHeaders);
+                if (response instanceof LoadTableResponse && serverMode != 
null) {
+                  return castResponse(
+                      responseType, withPlanningMode((LoadTableResponse) 
response, serverMode));
+                }
+
+                return response;
+              }
+            });
+
+    RESTCatalog catalog =
+        new RESTCatalog(SessionCatalog.SessionContext.createEmpty(), (config) 
-> adapter);
+
+    ImmutableMap.Builder<String, String> clientConfigBuilder =
+        ImmutableMap.<String, String>builder()
+            .put(CatalogProperties.FILE_IO_IMPL, 
"org.apache.iceberg.inmemory.InMemoryFileIO");
+
+    if (clientMode != null) {
+      clientConfigBuilder.put(RESTCatalogProperties.SCAN_PLANNING_MODE, 
clientMode);
+    }
+
+    catalog.initialize("test-scan-planning-modes", 
clientConfigBuilder.build());
+    return new CatalogWithAdapter(catalog, adapter);
+  }
+
   // Helper: Create base catalog endpoints (namespace and table operations)
   private List<Endpoint> baseCatalogEndpoints() {
     return ImmutableList.of(
@@ -883,7 +932,18 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
                   return castResponse(
                       responseType, 
ConfigResponse.builder().withEndpoints(endpoints).build());
                 }
-                return super.execute(request, responseType, errorHandler, 
responseHeaders);
+                T response = super.execute(request, responseType, 
errorHandler, responseHeaders);
+
+                // Add scan planning mode to table config for LoadTableResponse
+                if (response instanceof LoadTableResponse) {
+                  return castResponse(
+                      responseType,
+                      withPlanningMode(
+                          (LoadTableResponse) response,
+                          
RESTCatalogProperties.ScanPlanningMode.SERVER.modeName()));
+                }
+
+                return response;
               }
             });
 
@@ -898,27 +958,25 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
         ImmutableMap.of(
             CatalogProperties.FILE_IO_IMPL,
             "org.apache.iceberg.inmemory.InMemoryFileIO",
-            RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED,
-            "true"));
+            RESTCatalogProperties.SCAN_PLANNING_MODE,
+            RESTCatalogProperties.ScanPlanningMode.SERVER.modeName()));
     return new CatalogWithAdapter(catalog, adapter);
   }
 
   @Test
   public void serverDoesNotSupportPlanningEndpoint() throws IOException {
-    // Server doesn't support scan planning at all - should fall back to 
client-side planning
+    // Server requires server-side planning but doesn't support the endpoint - 
should fail
     CatalogWithAdapter catalogWithAdapter = 
catalogWithEndpoints(baseCatalogEndpoints(), null);
     RESTCatalog catalog = catalogWithAdapter.catalog;
-    Table table = createTableWithScanPlanning(catalog, "no_planning_support");
-    assertThat(table).isNotInstanceOf(RESTTable.class);
-    table.newAppend().appendFile(FILE_A).commit();
 
-    // Should fall back to client-side planning when endpoint is not supported
-    assertThat(table.newScan().planFiles())
-        .hasSize(1)
-        .first()
-        .extracting(ContentScanTask::file)
-        .extracting(ContentFile::location)
-        .isEqualTo(FILE_A.location());
+    catalog.createNamespace(NS);
+    assertThatThrownBy(
+            () ->
+                catalog.buildTable(TableIdentifier.of(NS, 
"no_planning_support"), SCHEMA).create())
+        .isInstanceOf(IllegalStateException.class)
+        .hasMessage(
+            "Server requires server-side scan planning for table %s but does 
not support endpoint %s",
+            TableIdentifier.of(NS, "no_planning_support"), 
Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN);
   }
 
   @Test
@@ -1027,8 +1085,8 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
         ImmutableMap.of(
             CatalogProperties.FILE_IO_IMPL,
             "org.apache.iceberg.inmemory.InMemoryFileIO",
-            RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED,
-            "true"));
+            RESTCatalogProperties.SCAN_PLANNING_MODE,
+            RESTCatalogProperties.ScanPlanningMode.SERVER.modeName()));
 
     Table table = restTableFor(catalog, "file_io_propagation");
 
@@ -1103,4 +1161,69 @@ public class TestRESTScanPlanning extends 
TestBaseWithRESTServer {
 
     return response;
   }
+
+  @Test
+  public void serverConfigTakesPrecedenceOnMismatch() {
+    // Client=SERVER, Server=CLIENT
+    CatalogWithAdapter catalogWithAdapter1 =
+        catalogWithModes(
+            RESTCatalogProperties.ScanPlanningMode.SERVER.modeName(),
+            RESTCatalogProperties.ScanPlanningMode.CLIENT.modeName());
+    catalogWithAdapter1.catalog.createNamespace(NS);
+
+    Table table1 =
+        catalogWithAdapter1
+            .catalog
+            .buildTable(TableIdentifier.of(NS, "mismatch_test"), SCHEMA)
+            .create();
+
+    
assertThat(table1).isNotInstanceOf(RESTTable.class).isInstanceOf(BaseTable.class);
+
+    // Client=CLIENT, Server=SERVER
+    CatalogWithAdapter catalogWithAdapter2 =
+        catalogWithModes(
+            RESTCatalogProperties.ScanPlanningMode.CLIENT.modeName(),
+            RESTCatalogProperties.ScanPlanningMode.SERVER.modeName());
+
+    Table table2 =
+        catalogWithAdapter2
+            .catalog
+            .buildTable(TableIdentifier.of(NS, 
"client_override_rejected_test"), SCHEMA)
+            .create();
+
+    assertThat(table2).isInstanceOf(RESTTable.class);
+  }
+
+  @Test
+  public void clientExplicitlyRequestsClientSidePlanning() {
+    CatalogWithAdapter catalogWithAdapter =
+        catalogWithModes(
+            RESTCatalogProperties.ScanPlanningMode.CLIENT.modeName(),
+            RESTCatalogProperties.ScanPlanningMode.CLIENT.modeName());
+    catalogWithAdapter.catalog.createNamespace(NS);
+
+    Table table =
+        catalogWithAdapter
+            .catalog
+            .buildTable(TableIdentifier.of(NS, "client_explicit_test"), SCHEMA)
+            .create();
+
+    
assertThat(table).isNotInstanceOf(RESTTable.class).isInstanceOf(BaseTable.class);
+  }
+
+  @Test
+  public void clientRequestsClientAndServerReturnsNothing() {
+    CatalogWithAdapter catalogWithAdapter =
+        
catalogWithModes(RESTCatalogProperties.ScanPlanningMode.CLIENT.modeName(), 
null);
+    catalogWithAdapter.catalog.createNamespace(NS);
+
+    Table table =
+        catalogWithAdapter
+            .catalog
+            .buildTable(TableIdentifier.of(NS, "client_server_null_test"), 
SCHEMA)
+            .create();
+
+    assertThat(table).isNotInstanceOf(RESTTable.class);
+    assertThat(table).isInstanceOf(BaseTable.class);
+  }
 }
diff --git 
a/spark/v3.4/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
 
b/spark/v3.4/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
index ed90da7fd4..9c31eb970b 100644
--- 
a/spark/v3.4/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
+++ 
b/spark/v3.4/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
@@ -40,7 +40,9 @@ public class TestRemoteScanPlanning extends TestSelect {
             .put(CatalogProperties.URI, 
restCatalog.properties().get(CatalogProperties.URI))
             // this flag is typically only set by the server, but we set it 
from the client for
             // testing
-            .put(RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED, "true")
+            .put(
+                RESTCatalogProperties.SCAN_PLANNING_MODE,
+                RESTCatalogProperties.ScanPlanningMode.SERVER.modeName())
             .build(),
         SparkCatalogConfig.REST.catalogName() + ".default.binary_table"
       }
diff --git 
a/spark/v3.5/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
 
b/spark/v3.5/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
index ed90da7fd4..9c31eb970b 100644
--- 
a/spark/v3.5/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
+++ 
b/spark/v3.5/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
@@ -40,7 +40,9 @@ public class TestRemoteScanPlanning extends TestSelect {
             .put(CatalogProperties.URI, 
restCatalog.properties().get(CatalogProperties.URI))
             // this flag is typically only set by the server, but we set it 
from the client for
             // testing
-            .put(RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED, "true")
+            .put(
+                RESTCatalogProperties.SCAN_PLANNING_MODE,
+                RESTCatalogProperties.ScanPlanningMode.SERVER.modeName())
             .build(),
         SparkCatalogConfig.REST.catalogName() + ".default.binary_table"
       }
diff --git 
a/spark/v4.0/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
 
b/spark/v4.0/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
index ed90da7fd4..9c31eb970b 100644
--- 
a/spark/v4.0/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
+++ 
b/spark/v4.0/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
@@ -40,7 +40,9 @@ public class TestRemoteScanPlanning extends TestSelect {
             .put(CatalogProperties.URI, 
restCatalog.properties().get(CatalogProperties.URI))
             // this flag is typically only set by the server, but we set it 
from the client for
             // testing
-            .put(RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED, "true")
+            .put(
+                RESTCatalogProperties.SCAN_PLANNING_MODE,
+                RESTCatalogProperties.ScanPlanningMode.SERVER.modeName())
             .build(),
         SparkCatalogConfig.REST.catalogName() + ".default.binary_table"
       }
diff --git 
a/spark/v4.1/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
 
b/spark/v4.1/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
index ed90da7fd4..9c31eb970b 100644
--- 
a/spark/v4.1/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
+++ 
b/spark/v4.1/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoteScanPlanning.java
@@ -40,7 +40,9 @@ public class TestRemoteScanPlanning extends TestSelect {
             .put(CatalogProperties.URI, 
restCatalog.properties().get(CatalogProperties.URI))
             // this flag is typically only set by the server, but we set it 
from the client for
             // testing
-            .put(RESTCatalogProperties.REST_SCAN_PLANNING_ENABLED, "true")
+            .put(
+                RESTCatalogProperties.SCAN_PLANNING_MODE,
+                RESTCatalogProperties.ScanPlanningMode.SERVER.modeName())
             .build(),
         SparkCatalogConfig.REST.catalogName() + ".default.binary_table"
       }

Reply via email to