SQL: Apply DefaultQueryConfig as early as possible. (#18289)
* SQL: Apply DefaultQueryConfig as early as possible.
This patch allows the default query context parameters to work properly
with any context field. In particular, it allows "druid.query.default.context.engine"
to work properly. Previously, this was ignored.
* Fix tests.
* Add test case in SqlResourceTest.
diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java
index 99b16e0..0e153f2 100644
--- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java
+++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java
@@ -68,6 +68,7 @@
 import org.apache.druid.msq.sql.entity.SqlStatementResult;
 import org.apache.druid.msq.util.MultiStageQueryContext;
 import org.apache.druid.msq.util.SqlStatementResourceHelper;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.query.ExecutionMode;
 import org.apache.druid.query.QueryContext;
 import org.apache.druid.query.QueryContexts;
@@ -133,7 +134,7 @@
   private final OverlordClient overlordClient;
   private final StorageConnector storageConnector;
   private final AuthorizerMapper authorizerMapper;
-
+  private final DefaultQueryConfig defaultQueryConfig;
 
   @Inject
   public SqlStatementResource(
@@ -141,7 +142,8 @@
       final ObjectMapper jsonMapper,
       final OverlordClient overlordClient,
       final @MultiStageQuery StorageConnectorProvider storageConnectorProvider,
-      final AuthorizerMapper authorizerMapper
+      final AuthorizerMapper authorizerMapper,
+      final DefaultQueryConfig defaultQueryConfig
   )
   {
     this.msqSqlStatementFactory = msqSqlStatementFactory;
@@ -149,6 +151,7 @@
     this.overlordClient = overlordClient;
     this.storageConnector = storageConnectorProvider.createStorageConnector(null);
     this.authorizerMapper = authorizerMapper;
+    this.defaultQueryConfig = defaultQueryConfig;
   }
 
   /**
@@ -186,9 +189,9 @@
 
     try {
       sqlQuery = createModifiedSqlQuery(sqlQuery);
-      sqlQueryPlus = SqlResource.makeSqlQueryPlus(sqlQuery, req);
+      sqlQueryPlus = SqlResource.makeSqlQueryPlus(sqlQuery, req, defaultQueryConfig);
       queryContext = QueryContext.of(sqlQueryPlus.context());
-      stmt = msqSqlStatementFactory.httpStatement(SqlResource.makeSqlQueryPlus(sqlQuery, req), req);
+      stmt = msqSqlStatementFactory.httpStatement(sqlQueryPlus, req);
     }
     catch (Exception e) {
       return SqlResource.handleExceptionBeforeStatementCreated(e, sqlQuery.queryContext());
diff --git a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlTaskResource.java b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlTaskResource.java
index 1dd84a8..cc2e12d 100644
--- a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlTaskResource.java
+++ b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlTaskResource.java
@@ -33,13 +33,12 @@
 import org.apache.druid.java.util.common.logger.Logger;
 import org.apache.druid.msq.guice.MultiStageQuery;
 import org.apache.druid.msq.sql.MSQTaskSqlEngine;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.query.QueryException;
 import org.apache.druid.query.http.SqlTaskStatus;
 import org.apache.druid.server.QueryResponse;
-import org.apache.druid.server.initialization.ServerConfig;
 import org.apache.druid.server.security.Access;
 import org.apache.druid.server.security.AuthorizationUtils;
-import org.apache.druid.server.security.AuthorizerMapper;
 import org.apache.druid.server.security.ForbiddenException;
 import org.apache.druid.sql.DirectStatement;
 import org.apache.druid.sql.HttpStatement;
@@ -81,21 +80,18 @@
   private static final Logger log = new Logger(SqlTaskResource.class);
 
   private final SqlStatementFactory sqlStatementFactory;
-  private final ServerConfig serverConfig;
-  private final AuthorizerMapper authorizerMapper;
+  private final DefaultQueryConfig defaultQueryConfig;
   private final ObjectMapper jsonMapper;
 
   @Inject
   public SqlTaskResource(
       final @MultiStageQuery SqlStatementFactory sqlStatementFactory,
-      final ServerConfig serverConfig,
-      final AuthorizerMapper authorizerMapper,
+      final DefaultQueryConfig defaultQueryConfig,
       final ObjectMapper jsonMapper
   )
   {
     this.sqlStatementFactory = sqlStatementFactory;
-    this.serverConfig = serverConfig;
-    this.authorizerMapper = authorizerMapper;
+    this.defaultQueryConfig = defaultQueryConfig;
     this.jsonMapper = jsonMapper;
   }
 
@@ -131,7 +127,7 @@
     final SqlQueryPlus sqlQueryPlus;
     final HttpStatement stmt;
     try {
-      sqlQueryPlus = SqlResource.makeSqlQueryPlus(sqlQuery, req);
+      sqlQueryPlus = SqlResource.makeSqlQueryPlus(sqlQuery, req, defaultQueryConfig);
       stmt = sqlStatementFactory.httpStatement(sqlQueryPlus, req);
     }
     catch (Exception e) {
diff --git a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
index f51002e..2c898e1 100644
--- a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
+++ b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/dart/controller/http/DartSqlResourceTest.java
@@ -215,7 +215,6 @@
         NoopServiceEmitter.instance(),
         NoopRequestLogger.instance(),
         QueryStackTests.DEFAULT_NOOP_SCHEDULER,
-        new DefaultQueryConfig(ImmutableMap.of()),
         lifecycleManager
     );
 
@@ -272,6 +271,7 @@
         lifecycleManager,
         new SqlEngineRegistry(Set.of(engine)),
         ResponseContextConfig.newConfig(false),
+        DefaultQueryConfig.NIL,
         SELF_NODE
     );
 
diff --git a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlMSQStatementResourcePostTest.java b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlMSQStatementResourcePostTest.java
index 0437fbc..308ad66 100644
--- a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlMSQStatementResourcePostTest.java
+++ b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlMSQStatementResourcePostTest.java
@@ -40,6 +40,7 @@
 import org.apache.druid.msq.test.MSQTestBase;
 import org.apache.druid.msq.test.MSQTestOverlordServiceClient;
 import org.apache.druid.msq.util.MultiStageQueryContext;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.query.ExecutionMode;
 import org.apache.druid.query.QueryContexts;
 import org.apache.druid.segment.column.ValueType;
@@ -75,7 +76,8 @@
         objectMapper,
         indexingServiceClient,
         s -> localFileStorageConnector,
-        authorizerMapper
+        authorizerMapper,
+        DefaultQueryConfig.NIL
     );
   }
 
@@ -329,7 +331,8 @@
         objectMapper,
         indexingServiceClient,
         s -> NilStorageConnector.getInstance(),
-        authorizerMapper
+        authorizerMapper,
+        DefaultQueryConfig.NIL
     );
 
     String errorMessage = "The sql statement api cannot read from the select destination [durableStorage] provided in "
diff --git a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlStatementResourceTest.java b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlStatementResourceTest.java
index 49f6184..714f35b 100644
--- a/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlStatementResourceTest.java
+++ b/extensions-core/multi-stage-query/src/test/java/org/apache/druid/msq/sql/resources/SqlStatementResourceTest.java
@@ -62,6 +62,7 @@
 import org.apache.druid.msq.sql.entity.ResultSetInformation;
 import org.apache.druid.msq.sql.entity.SqlStatementResult;
 import org.apache.druid.msq.test.MSQTestBase;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.query.Druids;
 import org.apache.druid.query.Query;
 import org.apache.druid.query.scan.ScanQuery;
@@ -711,7 +712,8 @@
         objectMapper,
         overlordClient,
         tempDir -> localFileStorageConnector,
-        authorizerMapper
+        authorizerMapper,
+        DefaultQueryConfig.NIL
     );
   }
 
diff --git a/processing/src/main/java/org/apache/druid/query/DefaultQueryConfig.java b/processing/src/main/java/org/apache/druid/query/DefaultQueryConfig.java
index 6c585ee..d831fa2 100644
--- a/processing/src/main/java/org/apache/druid/query/DefaultQueryConfig.java
+++ b/processing/src/main/java/org/apache/druid/query/DefaultQueryConfig.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.ImmutableMap;
 
 import javax.annotation.Nonnull;
+import java.util.Collections;
 import java.util.Map;
 
 /**
@@ -39,6 +40,11 @@
 public class DefaultQueryConfig
 {
   /**
+   * Config that does nothing.
+   */
+  public static final DefaultQueryConfig NIL = new DefaultQueryConfig(Collections.emptyMap());
+
+  /**
    * Note that context values should not be directly retrieved from this field but instead should
    * be read through {@link QueryContexts}. This field contains context configs from runtime property
    * which is then merged with configs passed in query context. The result of the merge is subsequently stored in
diff --git a/sql/src/main/java/org/apache/druid/sql/AbstractStatement.java b/sql/src/main/java/org/apache/druid/sql/AbstractStatement.java
index 32003a9..99cdbdf 100644
--- a/sql/src/main/java/org/apache/druid/sql/AbstractStatement.java
+++ b/sql/src/main/java/org/apache/druid/sql/AbstractStatement.java
@@ -91,9 +91,6 @@
       log.warn("'bySegment' results are not supported for SQL queries, ignoring query context parameter");
     }
     this.queryContext.putIfAbsent(QueryContexts.CTX_SQL_QUERY_ID, UUID.randomUUID().toString());
-    for (Map.Entry<String, Object> entry : sqlToolbox.defaultQueryConfig.getContext().entrySet()) {
-      this.queryContext.putIfAbsent(entry.getKey(), entry.getValue());
-    }
   }
 
   public String sqlQueryId()
diff --git a/sql/src/main/java/org/apache/druid/sql/SqlToolbox.java b/sql/src/main/java/org/apache/druid/sql/SqlToolbox.java
index 6ba8b59..66e55db 100644
--- a/sql/src/main/java/org/apache/druid/sql/SqlToolbox.java
+++ b/sql/src/main/java/org/apache/druid/sql/SqlToolbox.java
@@ -21,7 +21,6 @@
 
 import com.google.common.base.Preconditions;
 import org.apache.druid.java.util.emitter.service.ServiceEmitter;
-import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.server.QueryScheduler;
 import org.apache.druid.server.log.RequestLogger;
 import org.apache.druid.sql.calcite.planner.PlannerFactory;
@@ -37,7 +36,6 @@
   final ServiceEmitter emitter;
   final RequestLogger requestLogger;
   final QueryScheduler queryScheduler;
-  final DefaultQueryConfig defaultQueryConfig;
   final SqlLifecycleManager sqlLifecycleManager;
 
   public SqlToolbox(
@@ -46,7 +44,6 @@
       final ServiceEmitter emitter,
       final RequestLogger requestLogger,
       final QueryScheduler queryScheduler,
-      final DefaultQueryConfig defaultQueryConfig,
       final SqlLifecycleManager sqlLifecycleManager
   )
   {
@@ -55,7 +52,6 @@
     this.emitter = emitter;
     this.requestLogger = requestLogger;
     this.queryScheduler = queryScheduler;
-    this.defaultQueryConfig = defaultQueryConfig;
     this.sqlLifecycleManager = Preconditions.checkNotNull(sqlLifecycleManager, "sqlLifecycleManager");
   }
 
@@ -67,7 +63,6 @@
         emitter,
         requestLogger,
         queryScheduler,
-        defaultQueryConfig,
         sqlLifecycleManager
     );
   }
diff --git a/sql/src/main/java/org/apache/druid/sql/guice/SqlModule.java b/sql/src/main/java/org/apache/druid/sql/guice/SqlModule.java
index 06b3b8b..1565527 100644
--- a/sql/src/main/java/org/apache/druid/sql/guice/SqlModule.java
+++ b/sql/src/main/java/org/apache/druid/sql/guice/SqlModule.java
@@ -20,7 +20,6 @@
 package org.apache.druid.sql.guice;
 
 import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
 import com.google.inject.Binder;
 import com.google.inject.Inject;
 import com.google.inject.Key;
@@ -32,7 +31,6 @@
 import org.apache.druid.guice.PolyBind;
 import org.apache.druid.guice.annotations.NativeQuery;
 import org.apache.druid.java.util.emitter.service.ServiceEmitter;
-import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.server.QueryScheduler;
 import org.apache.druid.server.log.RequestLogger;
 import org.apache.druid.sql.SqlLifecycleManager;
@@ -172,7 +170,6 @@
         final ServiceEmitter emitter,
         final RequestLogger requestLogger,
         final QueryScheduler queryScheduler,
-        final Supplier<DefaultQueryConfig> defaultQueryConfig,
         final SqlLifecycleManager sqlLifecycleManager
     )
     {
@@ -182,7 +179,6 @@
           emitter,
           requestLogger,
           queryScheduler,
-          defaultQueryConfig.get(),
           sqlLifecycleManager
       );
     }
diff --git a/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java b/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
index 3640ce7..42d25a1 100644
--- a/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
+++ b/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
@@ -30,6 +30,7 @@
 import org.apache.druid.guice.annotations.Self;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.java.util.common.logger.Logger;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.query.QueryContext;
 import org.apache.druid.query.QueryContexts;
 import org.apache.druid.server.DruidNode;
@@ -72,6 +73,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -93,6 +95,7 @@
   private final AuthorizerMapper authorizerMapper;
   private final ServerConfig serverConfig;
   private final ResponseContextConfig responseContextConfig;
+  private final DefaultQueryConfig defaultQueryConfig;
   private final DruidNode selfNode;
   private final SqlLifecycleManager sqlLifecycleManager;
   private final SqlEngineRegistry sqlEngineRegistry;
@@ -105,8 +108,9 @@
       final ServerConfig serverConfig,
       final SqlLifecycleManager sqlLifecycleManager,
       final SqlEngineRegistry sqlEngineRegistry,
-      ResponseContextConfig responseContextConfig,
-      @Self DruidNode selfNode
+      final ResponseContextConfig responseContextConfig,
+      final DefaultQueryConfig defaultQueryConfig,
+      @Self final DruidNode selfNode
   )
   {
     this.sqlEngineRegistry = Preconditions.checkNotNull(sqlEngineRegistry, "sqlEngineRegistry");
@@ -114,6 +118,7 @@
     this.authorizerMapper = Preconditions.checkNotNull(authorizerMapper, "authorizerMapper");
     this.serverConfig = Preconditions.checkNotNull(serverConfig, "serverConfig");
     this.responseContextConfig = responseContextConfig;
+    this.defaultQueryConfig = Preconditions.checkNotNull(defaultQueryConfig, "defaultQueryConfig");
     this.selfNode = selfNode;
     this.sqlLifecycleManager = Preconditions.checkNotNull(sqlLifecycleManager, "sqlLifecycleManager");
   }
@@ -187,7 +192,7 @@
     final QueryContext queryContext;
 
     try {
-      final SqlQueryPlus sqlQueryPlus = makeSqlQueryPlus(sqlQuery, req);
+      final SqlQueryPlus sqlQueryPlus = makeSqlQueryPlus(sqlQuery, req, defaultQueryConfig);
       queryContext = new QueryContext(sqlQueryPlus.context()); // Redefine queryContext to include SET parameters
       final String engineName = queryContext.getEngine();
       final SqlEngine engine = sqlEngineRegistry.getEngine(engineName);
@@ -448,11 +453,23 @@
    * Create a {@link SqlQueryPlus}, which involves parsing the query from {@link SqlQuery#getQuery()} and
    * extracing any SET parameters into the query context.
    */
-  public static SqlQueryPlus makeSqlQueryPlus(final SqlQuery sqlQuery, final HttpServletRequest req)
+  public static SqlQueryPlus makeSqlQueryPlus(
+      final SqlQuery sqlQuery,
+      final HttpServletRequest req,
+      final DefaultQueryConfig defaultQueryConfig
+  )
   {
+    final Map<String, Object> queryContext;
+    if (!defaultQueryConfig.getContext().isEmpty()) {
+      queryContext = new HashMap<>(defaultQueryConfig.getContext());
+      queryContext.putAll(sqlQuery.getContext());
+    } else {
+      queryContext = sqlQuery.getContext();
+    }
+
     return SqlQueryPlus.builder()
                        .sql(sqlQuery.getQuery())
-                       .context(sqlQuery.getContext())
+                       .context(queryContext)
                        .parameters(sqlQuery.getParameterList())
                        .auth(AuthorizationUtils.authenticationResultFromRequest(req))
                        .build();
diff --git a/sql/src/test/java/org/apache/druid/sql/SqlStatementTest.java b/sql/src/test/java/org/apache/druid/sql/SqlStatementTest.java
index ff21f98..732f0a8 100644
--- a/sql/src/test/java/org/apache/druid/sql/SqlStatementTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/SqlStatementTest.java
@@ -486,7 +486,7 @@
   }
 
   @Test
-  public void testPreparePolicyEnforcerThrowsForNoPolicy() throws Exception
+  public void testPreparePolicyEnforcerThrowsForNoPolicy()
   {
     policyEnforcer = new RestrictAllTablesPolicyEnforcer(null);
     sqlStatementFactory = buildSqlStatementFactory();
@@ -531,26 +531,8 @@
         .build();
     DirectStatement stmt = sqlStatementFactory.directStatement(sqlReq);
     Map<String, Object> context = stmt.context();
-    Assert.assertEquals(2, context.size());
     // should contain only query id, not bySegment since it is not valid for SQL
-    Assert.assertTrue(context.containsKey(QueryContexts.CTX_SQL_QUERY_ID));
-  }
-
-  @Test
-  public void testDefaultQueryContextIsApplied()
-  {
-    SqlQueryPlus sqlReq = SqlQueryPlus
-        .builder("select 1 + ?")
-        .context(ImmutableMap.of(QueryContexts.BY_SEGMENT_KEY, "true"))
-        .auth(CalciteTests.REGULAR_USER_AUTH_RESULT)
-        .build();
-    DirectStatement stmt = sqlStatementFactory.directStatement(sqlReq);
-    Map<String, Object> context = stmt.context();
-    Assert.assertEquals(2, context.size());
-    // Statement should contain default query context values
-    for (String defaultContextKey : defaultQueryConfig.getContext().keySet()) {
-      Assert.assertTrue(context.containsKey(defaultContextKey));
-    }
+    Assert.assertEquals(Collections.singleton(QueryContexts.CTX_SQL_QUERY_ID), context.keySet());
   }
 
   private SqlStatementFactory buildSqlStatementFactory()
@@ -591,7 +573,6 @@
             new NoopServiceEmitter(),
             testRequestLogger,
             QueryStackTests.DEFAULT_NOOP_SCHEDULER,
-            defaultQueryConfig,
             new SqlLifecycleManager()
         )
     );
diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/QueryFrameworkUtils.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/QueryFrameworkUtils.java
index 0d0deb1..af5dd53 100644
--- a/sql/src/test/java/org/apache/druid/sql/calcite/util/QueryFrameworkUtils.java
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/QueryFrameworkUtils.java
@@ -139,7 +139,6 @@
         NoopServiceEmitter.instance(),
         NoopRequestLogger.instance(),
         QueryStackTests.DEFAULT_NOOP_SCHEDULER,
-        new DefaultQueryConfig(ImmutableMap.of()),
         new SqlLifecycleManager()
     );
   }
diff --git a/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java b/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
index 08c7a0e..28e8923 100644
--- a/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/guice/SqlModuleTest.java
@@ -212,6 +212,7 @@
               binder.bind(CoordinatorClient.class).to(NoopCoordinatorClient.class);
               binder.bind(CentralizedDatasourceSchemaConfig.class)
                     .toInstance(CentralizedDatasourceSchemaConfig.enabled(false));
+              binder.bind(DefaultQueryConfig.class).toInstance(DefaultQueryConfig.NIL);
             },
             sqlModule,
             new TestViewManagerModule()
diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlHttpModuleTest.java b/sql/src/test/java/org/apache/druid/sql/http/SqlHttpModuleTest.java
index 483ca1a..efed767 100644
--- a/sql/src/test/java/org/apache/druid/sql/http/SqlHttpModuleTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/http/SqlHttpModuleTest.java
@@ -31,6 +31,7 @@
 import org.apache.druid.guice.annotations.Json;
 import org.apache.druid.guice.annotations.NativeQuery;
 import org.apache.druid.guice.annotations.Self;
+import org.apache.druid.query.DefaultQueryConfig;
 import org.apache.druid.server.DruidNode;
 import org.apache.druid.server.ResponseContextConfig;
 import org.apache.druid.server.security.AuthorizerMapper;
@@ -72,6 +73,7 @@
           binder.bind(SqlStatementFactory.class)
                 .annotatedWith(NativeQuery.class)
                 .toInstance(EasyMock.mock(SqlStatementFactory.class));
+          binder.bind(DefaultQueryConfig.class).toInstance(DefaultQueryConfig.NIL);
         },
         target
     );
diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
index ac04194..5959393 100644
--- a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
@@ -285,7 +285,6 @@
         stubServiceEmitter,
         testRequestLogger,
         scheduler,
-        defaultQueryConfig,
         lifecycleManager
     );
     sqlStatementFactory = new SqlStatementFactory(null)
@@ -331,6 +330,7 @@
         lifecycleManager,
         new SqlEngineRegistry(Set.of(engine)),
         TEST_RESPONSE_CONTEXT_CONFIG,
+        DefaultQueryConfig.NIL,
         DUMMY_DRUID_NODE
     );
   }
@@ -584,6 +584,46 @@
   }
 
   @Test
+  public void testTimestampsInResponseLosAngelesTimeZone_setViaDefaultQueryConfig() throws Exception
+  {
+    // Create a new SqlResource with a DefaultQueryConfig that sets sqlTimeZone
+    final DefaultQueryConfig queryConfigWithTimezone = new DefaultQueryConfig(
+        ImmutableMap.of("sqlTimeZone", "America/Los_Angeles")
+    );
+
+    // We need to create a new SqlResource instance with our custom DefaultQueryConfig
+    resource = new SqlResource(
+        JSON_MAPPER,
+        CalciteTests.TEST_AUTHORIZER_MAPPER,
+        new ServerConfig(),
+        lifecycleManager,
+        new SqlEngineRegistry(Set.of(engine)),
+        TEST_RESPONSE_CONTEXT_CONFIG,
+        queryConfigWithTimezone,
+        DUMMY_DRUID_NODE
+    );
+
+    final List<Map<String, Object>> rows = doPost(
+        new SqlQuery(
+            "SELECT __time, CAST(__time AS DATE) AS t2 FROM druid.foo LIMIT 1",
+            ResultFormat.OBJECT,
+            false,
+            false,
+            false,
+            null,
+            null
+        )
+    ).rhs;
+
+    Assert.assertEquals(
+        ImmutableList.of(
+            ImmutableMap.of("__time", "1999-12-31T16:00:00.000-08:00", "t2", "1999-12-31T00:00:00.000-08:00")
+        ),
+        rows
+    );
+  }
+
+  @Test
   public void testTimestampsInResponseWithNulls() throws Exception
   {
     final List<Map<String, Object>> rows = doPost(
@@ -1668,6 +1708,7 @@
         lifecycleManager,
         new SqlEngineRegistry(Set.of(engine)),
         TEST_RESPONSE_CONTEXT_CONFIG,
+        DefaultQueryConfig.NIL,
         DUMMY_DRUID_NODE
     );