From 722265f462c3288c3dc25deaad1cc06efcdce3ba Mon Sep 17 00:00:00 2001
From: drewdaemon <drew.tate@elastic.co>
Date: Fri, 9 May 2025 12:50:56 -0600
Subject: [PATCH 1/2] add validation_only option

---
 .../xpack/esql/action/EsqlQueryRequest.java              | 9 +++++++++
 .../elasticsearch/xpack/esql/action/RequestXContent.java | 2 ++
 .../xpack/esql/plugin/TransportEsqlQueryAction.java      | 2 +-
 .../elasticsearch/xpack/esql/querylog/EsqlQueryLog.java  | 4 +++-
 .../elasticsearch/xpack/esql/session/EsqlSession.java    | 8 +++++++-
 5 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequest.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequest.java
index bd0a7635a4653..e6192ffc81fe4 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequest.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequest.java
@@ -50,6 +50,7 @@ public class EsqlQueryRequest extends org.elasticsearch.xpack.core.esql.action.E
     private TimeValue waitForCompletionTimeout = DEFAULT_WAIT_FOR_COMPLETION;
     private TimeValue keepAlive = DEFAULT_KEEP_ALIVE;
     private boolean keepOnCompletion;
+    private boolean validationOnly;
     private boolean onSnapshotBuild = Build.current().isSnapshot();
     private boolean acceptedPragmaRisks = false;
     private Boolean allowPartialResults = null;
@@ -202,6 +203,14 @@ public void keepOnCompletion(boolean keepOnCompletion) {
         this.keepOnCompletion = keepOnCompletion;
     }
 
+    public boolean validationOnly() {
+        return validationOnly;
+    }
+
+    public void validationOnly(boolean validationOnly) {
+        this.validationOnly = validationOnly;
+    }
+
     /**
      * Add a "table" to the request for use with things like {@code LOOKUP}.
      */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java
index e77d7b41aaca6..011d8769b36f4 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RequestXContent.java
@@ -85,6 +85,7 @@ String fields() {
     static final ParseField WAIT_FOR_COMPLETION_TIMEOUT = new ParseField("wait_for_completion_timeout");
     static final ParseField KEEP_ALIVE = new ParseField("keep_alive");
     static final ParseField KEEP_ON_COMPLETION = new ParseField("keep_on_completion");
+    static final ParseField VALIDATION_ONLY = new ParseField("validation_only");
 
     private static final ObjectParser<EsqlQueryRequest, Void> SYNC_PARSER = objectParserSync(EsqlQueryRequest::syncEsqlQueryRequest);
     private static final ObjectParser<EsqlQueryRequest, Void> ASYNC_PARSER = objectParserAsync(EsqlQueryRequest::asyncEsqlQueryRequest);
@@ -114,6 +115,7 @@ private static void objectParserCommon(ObjectParser<EsqlQueryRequest, ?> parser)
         parser.declareString((request, localeTag) -> request.locale(Locale.forLanguageTag(localeTag)), LOCALE_FIELD);
         parser.declareBoolean(EsqlQueryRequest::profile, PROFILE_FIELD);
         parser.declareField((p, r, c) -> new ParseTables(r, p).parseTables(), TABLES_FIELD, ObjectParser.ValueType.OBJECT);
+        parser.declareBoolean(EsqlQueryRequest::validationOnly, VALIDATION_ONLY);
     }
 
     private static ObjectParser<EsqlQueryRequest, Void> objectParserSync(Supplier<EsqlQueryRequest> supplier) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
index ab96b0505477d..ba326f3a8660d 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
@@ -250,7 +250,7 @@ private void innerExecute(Task task, EsqlQueryRequest request, ActionListener<Es
             services,
             ActionListener.wrap(result -> {
                 recordCCSTelemetry(task, executionInfo, request, null);
-                planExecutor.metrics().recordTook(executionInfo.overallTook().millis());
+//                planExecutor.metrics().recordTook(executionInfo.overallTook().millis());
                 listener.onResponse(toResponse(task, request, configuration, result));
             }, ex -> {
                 recordCCSTelemetry(task, executionInfo, request, ex);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querylog/EsqlQueryLog.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querylog/EsqlQueryLog.java
index cd410c8eba804..cc94dfd2bea39 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querylog/EsqlQueryLog.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querylog/EsqlQueryLog.java
@@ -15,6 +15,7 @@
 import org.elasticsearch.index.SlowLogFieldProvider;
 import org.elasticsearch.index.SlowLogFields;
 import org.elasticsearch.xcontent.json.JsonStringEncoder;
+import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo;
 import org.elasticsearch.xpack.esql.session.Result;
 
 import java.nio.charset.StandardCharsets;
@@ -66,7 +67,8 @@ public void onQueryPhase(Result esqlResult, String query) {
         if (esqlResult == null) {
             return; // TODO review, it happens in some tests, not sure if it's a thing also in prod
         }
-        long tookInNanos = esqlResult.executionInfo().overallTook().nanos();
+        EsqlExecutionInfo executionResult = esqlResult.executionInfo();
+        long tookInNanos = executionResult == null ? 0 : executionResult.overallTook().nanos();
         log(() -> Message.of(esqlResult, query, includeUser ? additionalFields.queryFields() : Map.of()), tookInNanos);
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index 7312ddb7da790..4b16052b34eb9 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -184,7 +184,13 @@ public void onResponse(LogicalPlan analyzedPlan) {
                     preMapper.preMapper(
                         analyzedPlan,
                         listener.delegateFailureAndWrap(
-                            (l, p) -> executeOptimizedPlan(request, executionInfo, planRunner, optimizedPlan(p), l)
+                            (l, p) -> {
+                                if (request.validationOnly()) {
+                                    l.onResponse(new Result(new ArrayList<>(), new ArrayList<>(), DriverCompletionInfo.EMPTY, null));
+                                } else {
+                                    executeOptimizedPlan(request, executionInfo, planRunner, optimizedPlan(p), l);
+                                }
+                            }
                         )
                     );
                 }

From 7a59275d339ddf74c864e3657116e44bbafe149c Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Fri, 9 May 2025 19:01:25 +0000
Subject: [PATCH 2/2] [CI] Auto commit changes from spotless

---
 .../esql/plugin/TransportEsqlQueryAction.java |  2 +-
 .../xpack/esql/session/EsqlSession.java       | 19 +++++++------------
 2 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
index ba326f3a8660d..caf55fc16ea41 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
@@ -250,7 +250,7 @@ private void innerExecute(Task task, EsqlQueryRequest request, ActionListener<Es
             services,
             ActionListener.wrap(result -> {
                 recordCCSTelemetry(task, executionInfo, request, null);
-//                planExecutor.metrics().recordTook(executionInfo.overallTook().millis());
+                // planExecutor.metrics().recordTook(executionInfo.overallTook().millis());
                 listener.onResponse(toResponse(task, request, configuration, result));
             }, ex -> {
                 recordCCSTelemetry(task, executionInfo, request, ex);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index 4b16052b34eb9..5bc1691949278 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -181,18 +181,13 @@ public void execute(EsqlQueryRequest request, EsqlExecutionInfo executionInfo, P
             new EsqlCCSUtils.CssPartialErrorsActionListener(executionInfo, listener) {
                 @Override
                 public void onResponse(LogicalPlan analyzedPlan) {
-                    preMapper.preMapper(
-                        analyzedPlan,
-                        listener.delegateFailureAndWrap(
-                            (l, p) -> {
-                                if (request.validationOnly()) {
-                                    l.onResponse(new Result(new ArrayList<>(), new ArrayList<>(), DriverCompletionInfo.EMPTY, null));
-                                } else {
-                                    executeOptimizedPlan(request, executionInfo, planRunner, optimizedPlan(p), l);
-                                }
-                            }
-                        )
-                    );
+                    preMapper.preMapper(analyzedPlan, listener.delegateFailureAndWrap((l, p) -> {
+                        if (request.validationOnly()) {
+                            l.onResponse(new Result(new ArrayList<>(), new ArrayList<>(), DriverCompletionInfo.EMPTY, null));
+                        } else {
+                            executeOptimizedPlan(request, executionInfo, planRunner, optimizedPlan(p), l);
+                        }
+                    }));
                 }
             }
         );