Browse Source

ESQL: Add warning header when default LIMIT is applied (#100894)

Fixes https://github.com/elastic/elasticsearch/issues/100555

ESQL [by default](https://github.com/elastic/elasticsearch/pull/99816)
adds an implicit `LIMIT 500` to queries that do not define a limit.
Since this can be confusing for the end user, with this PR we also add a
warning to the response, making this default clear and explicit.
Luigi Dell'Aquila 2 years ago
parent
commit
8d89f913a1
32 changed files with 328 additions and 18 deletions
  1. 3 1
      docs/reference/esql/esql-rest.asciidoc
  2. 6 6
      docs/reference/esql/multivalued-fields.asciidoc
  3. 5 0
      x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java
  4. 2 0
      x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/HeapAttackIT.java
  5. 2 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/100_bug_fix.yml
  6. 8 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/10_basic.yml
  7. 48 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/20_aggs.yml
  8. 53 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/30_types.yml
  9. 4 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/40_tsdb.yml
  10. 2 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/40_unsupported_types.yml
  11. 8 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/45_non_tsdb_counter.yml
  12. 25 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/50_index_patterns.yml
  13. 8 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/60_enrich.yml
  14. 4 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/61_enrich_ip.yml
  15. 6 1
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/70_locale.yml
  16. 38 1
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/80_text.yml
  17. 1 0
      x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/90_non_indexed.yml
  18. 12 5
      x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java
  19. 7 0
      x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java
  20. 11 3
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java
  21. 5 1
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java
  22. 7 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java
  23. 6 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
  24. 6 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java
  25. 7 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java
  26. 6 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java
  27. 5 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java
  28. 5 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
  29. 7 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
  30. 6 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java
  31. 7 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java
  32. 8 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/VerifierMetricsTests.java

+ 3 - 1
docs/reference/esql/esql-rest.asciidoc

@@ -107,7 +107,7 @@ s|Description
 
 |smile
 |application/smile
-|{wikipedia}/Smile_(data_interchange_format)[Smile] binary data format similar 
+|{wikipedia}/Smile_(data_interchange_format)[Smile] binary data format similar
 to CBOR
 
 |===
@@ -220,6 +220,7 @@ POST /_query
     | WHERE page_count > 300 AND author == "Frank Herbert"
     | STATS count = COUNT(*) by year
     | WHERE count > 0
+    | LIMIT 5
   """
 }
 ----
@@ -239,6 +240,7 @@ POST /_query
     | WHERE page_count > ? AND author == ?
     | STATS count = COUNT(*) by year
     | WHERE count > ?
+    | LIMIT 5
   """,
   "params": [300, "Frank Herbert", 0]
 }

+ 6 - 6
docs/reference/esql/multivalued-fields.asciidoc

@@ -17,7 +17,7 @@ POST /mv/_bulk?refresh
 
 POST /_query
 {
-  "query": "FROM mv"
+  "query": "FROM mv | LIMIT 2"
 }
 ----
 
@@ -65,7 +65,7 @@ POST /mv/_bulk?refresh
 
 POST /_query
 {
-  "query": "FROM mv"
+  "query": "FROM mv | LIMIT 2"
 }
 ----
 
@@ -106,7 +106,7 @@ POST /mv/_bulk?refresh
 
 POST /_query
 {
-  "query": "FROM mv"
+  "query": "FROM mv | LIMIT 2"
 }
 ----
 
@@ -148,7 +148,7 @@ POST /mv/_bulk?refresh
 
 POST /_query
 {
-  "query": "FROM mv | EVAL b=TO_STRING(b)"
+  "query": "FROM mv | EVAL b=TO_STRING(b) | LIMIT 2"
 }
 ----
 
@@ -183,7 +183,7 @@ POST /mv/_bulk?refresh
 
 POST /_query
 {
-  "query": "FROM mv | EVAL b + 2, a + b"
+  "query": "FROM mv | EVAL b + 2, a + b | LIMIT 4"
 }
 ----
 
@@ -217,7 +217,7 @@ Work around this limitation by converting the field to single value with one of:
 ----
 POST /_query
 {
-  "query": "FROM mv | EVAL b=MV_MIN(b) | EVAL b + 2, a + b"
+  "query": "FROM mv | EVAL b=MV_MIN(b) | EVAL b + 2, a + b | LIMIT 4"
 }
 ----
 // TEST[continued]

+ 5 - 0
x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java

@@ -24,6 +24,7 @@ import org.junit.Before;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import static org.hamcrest.Matchers.equalTo;
@@ -248,6 +249,10 @@ public class EsqlSecurityIT extends ESRestTestCase {
     }
 
     private Response runESQLCommand(String user, String command) throws IOException {
+        if (command.toLowerCase(Locale.ROOT).contains("limit") == false) {
+            // add a (high) limit to avoid warnings on default limit
+            command += " | limit 10000000";
+        }
         Settings pragmas = Settings.EMPTY;
         if (Build.current().isSnapshot()) {
             Settings.Builder settings = Settings.builder();

+ 2 - 0
x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/HeapAttackIT.java

@@ -13,6 +13,7 @@ import org.elasticsearch.client.Request;
 import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.ResponseException;
+import org.elasticsearch.client.WarningsHandler;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.xcontent.XContentHelper;
@@ -279,6 +280,7 @@ public class HeapAttackIT extends ESRestTestCase {
         request.setOptions(
             RequestOptions.DEFAULT.toBuilder()
                 .setRequestConfig(RequestConfig.custom().setSocketTimeout(Math.toIntExact(TimeValue.timeValueMinutes(5).millis())).build())
+                .setWarningsHandler(WarningsHandler.PERMISSIVE)
         );
         return client().performRequest(request);
     }

+ 2 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/100_bug_fix.yml

@@ -18,6 +18,7 @@ setup:
       warnings:
         - "Line 1:37: evaluation of [to_ip(coalesce(ip1.keyword, \"255.255.255.255\"))] failed, treating result as null. Only first 20 failures recorded."
         - "Line 1:37: java.lang.IllegalArgumentException: '127.0' is not an IP string literal."
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'FROM test | sort emp_no | eval ip = to_ip(coalesce(ip1.keyword, "255.255.255.255")) | keep emp_no, ip'
@@ -36,6 +37,7 @@ setup:
       warnings:
         - "Line 1:98: evaluation of [to_ip(x2)] failed, treating result as null. Only first 20 failures recorded."
         - "Line 1:98: java.lang.IllegalArgumentException: '127.00.1' is not an IP string literal."
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'FROM test | sort emp_no | eval x1 = concat(ip1, ip2), x2 = coalesce(x1, "255.255.255.255"), x3 = to_ip(x2) | keep emp_no, x*'

+ 8 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/10_basic.yml

@@ -1,5 +1,7 @@
 ---
 setup:
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index:  test
@@ -109,6 +111,8 @@ setup:
 ---
 "Test From":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test'
@@ -266,6 +270,8 @@ setup:
 ---
 "Test Input Params":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'row a = ? | eval b = ?, c = 1 + ?'
@@ -283,6 +289,8 @@ setup:
 
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where color == ? and count == ? and time == ? | keep data, count, color'

+ 48 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/20_aggs.yml

@@ -1,5 +1,7 @@
 ---
 setup:
+  - skip:
+      features: warnings
   - do:
       indices.create:
         index:  test
@@ -109,6 +111,8 @@ setup:
 ---
 "Test From":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -130,6 +134,8 @@ setup:
 ---
 "Test simple grouping avg":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | where color == "red" | stats avg(data) by color'
@@ -144,6 +150,8 @@ setup:
 ---
 "Test From Stats Avg":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats avg(count)'
@@ -156,6 +164,8 @@ setup:
 ---
 "Test From Stats Avg With Alias":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats f1 = avg(count)'
@@ -168,6 +178,8 @@ setup:
 ---
 "Test From Stats Count":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats count(data)'
@@ -180,6 +192,8 @@ setup:
 ---
 "Test From Stats Count With Alias":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats dataCount = count(data)'
@@ -192,6 +206,8 @@ setup:
 ---
 "Test From Stats Min":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats min(count)'
@@ -204,6 +220,8 @@ setup:
 ---
 "Test From Stats Min With Alias":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats minCount=min(count)'
@@ -216,6 +234,8 @@ setup:
 ---
 "Test From Stats Max":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats max(count)'
@@ -228,6 +248,8 @@ setup:
 ---
 "Test From Stats Max With Alias":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats maxCount=max(count)'
@@ -255,6 +277,8 @@ setup:
 ---
 "Test Median On Long":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median(count)'
@@ -267,6 +291,8 @@ setup:
 ---
 "Test Median On Double":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median(count_d)'
@@ -279,6 +305,8 @@ setup:
 ---
 "Test Grouping Median On Long":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median(count) by color | sort med'
@@ -294,6 +322,8 @@ setup:
 ---
 "Test Grouping Median On Double":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median(count_d) by color | sort med'
@@ -309,6 +339,8 @@ setup:
 ---
 "Test Median Absolute Deviation On Long":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median_absolute_deviation(count)'
@@ -321,6 +353,8 @@ setup:
 ---
 "Test Median Absolute Deviation On Double":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median_absolute_deviation(count_d)'
@@ -333,6 +367,8 @@ setup:
 ---
 "Test Grouping Median Absolute Deviation On Long":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median_absolute_deviation(count) by color | sort color'
@@ -348,6 +384,8 @@ setup:
 ---
 "Test Grouping Median Absolute Deviation On Double":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats med=median_absolute_deviation(count_d) by color | sort color'
@@ -363,6 +401,8 @@ setup:
 ---
 "Test From Stats Eval":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats avg_count = avg(count) | eval x = avg_count + 7'
@@ -374,6 +414,8 @@ setup:
 ---
 "Test Stats Where":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats x = avg(count) | where x > 100'
@@ -396,6 +438,8 @@ setup:
 ---
 "Test Eval Row With Null":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'row a = 1, b = 2, c = null | eval z = c + b + a'
@@ -419,6 +463,8 @@ setup:
 ---
 "Test Eval With Null And Count":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval nullsum = count_d + null | stats count(nullsum)'
@@ -433,6 +479,8 @@ setup:
 ---
 "Test Eval With Multiple Expressions":
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'row l=1, d=1.0, ln=1 + null, dn=1.0 + null | stats sum(l), sum(d), sum(ln), sum(dn)'

+ 53 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/30_types.yml

@@ -1,5 +1,12 @@
+---
+setup:
+  - skip:
+      features: warnings
+
 ---
 constant_keyword:
+  - skip:
+      features: warnings
   - do:
       indices.create:
         index:  test
@@ -21,6 +28,8 @@ constant_keyword:
           - { "color": "red" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -33,6 +42,8 @@ constant_keyword:
   - match: { values.0.1: wow such constant }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval l=length(kind) | keep l'
@@ -62,6 +73,8 @@ multivalued keyword:
           - { "card": ["jack", "of", "diamonds"] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -91,6 +104,8 @@ keyword no doc_values:
           - { "card": ["jack", "of", "diamonds"] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -119,6 +134,8 @@ wildcard:
           - { "card": "jack of diamonds" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -128,6 +145,8 @@ wildcard:
   - match: {values.0.0: jack of diamonds}
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval l=length(card) | keep l'
@@ -166,6 +185,8 @@ numbers:
           - { i: 123, l: -1234567891011121131, d: 1.234567891234568, mv_i: [123456, -123456], mv_l: [1234567891011121131, -1234567891011121131], mv_d: [1.234567891234568, -1.234567891234568] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -215,6 +236,8 @@ small_numbers:
           - { b: 1, s: 1245, hf: 12.01, f: 112.0 }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -233,6 +256,8 @@ small_numbers:
   - match: {values.0.3: 1245}
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval sum_d = b + f + hf + s, sum_i = b + s | keep sum_d, sum_i'
@@ -245,6 +270,8 @@ small_numbers:
   - match: {values.0.1: 1246}
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval r_f = round(f), r_hf = round(hf) | keep r_f, r_hf'
@@ -279,6 +306,8 @@ scaled_float:
           - { f: 112.01, d: 1.0 }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -291,6 +320,8 @@ scaled_float:
   - match: {values.0.1: 112.01}
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | eval sum = d + f | keep sum'
@@ -319,6 +350,8 @@ multivalued boolean:
           - { "booleans": [ true, false, false, false ] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -349,6 +382,8 @@ ip:
           - { "ip": "127.0.0.1", "keyword": "127.0.0.2" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -361,6 +396,8 @@ ip:
   - match: { values.0.1: "127.0.0.2" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | where keyword == "127.0.0.2" | rename ip as IP | drop keyword'
@@ -415,6 +452,8 @@ alias:
           - { "foo": "def", "level1": {"level2": 50}, "some_long": 15, "some_date": "2015-01-01T12:00:00.000Z" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | keep foo, bar, level1.level2, level2_alias, some_long, some_long_alias, some_long_alias2, some_date, some_date_alias | sort level2_alias'
@@ -457,6 +496,8 @@ alias:
   - match: { values.1.8: 2015-01-01T12:00:00.000Z }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | where bar == "abc" | keep foo, bar, level1.level2, level2_alias'
@@ -475,6 +516,8 @@ alias:
   - match: { values.0.3: 10 }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | where level2_alias == 10 | keep foo, bar, level1.level2, level2_alias'
@@ -493,12 +536,16 @@ alias:
   - match: { values.0.3: 10 }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | where level2_alias == 20'
   - length: { values: 0 }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test | stats x = max(level2_alias)'
@@ -527,6 +574,8 @@ version:
           - { "version": [ "1.2.3", "4.5.6-SNOOPY" ] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'
@@ -555,6 +604,8 @@ id:
           - { "kw": "keyword1" }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test [metadata _id] | keep _id, kw'
@@ -584,6 +635,8 @@ unsigned_long:
           - { "number": [ "1", "9223372036854775808", "0", "18446744073709551615" ] }
 
   - do:
+      warnings:
+        - "No limit defined, adding default limit of [500]"
       esql.query:
         body:
           query: 'from test'

+ 4 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/40_tsdb.yml

@@ -108,6 +108,7 @@ load everything:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test'
@@ -133,6 +134,7 @@ load a document:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where @timestamp == "2021-04-28T18:50:23.142Z"'
@@ -160,6 +162,7 @@ from doc with aggregate_metric_double:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test2'
@@ -189,6 +192,7 @@ from index pattern unsupported counter:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'FROM test*'

+ 2 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/40_unsupported_types.yml

@@ -104,6 +104,7 @@ unsupported:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test'
@@ -269,6 +270,7 @@ unsupported with sort:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort some_doc.bar'

+ 8 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/45_non_tsdb_counter.yml

@@ -1,4 +1,6 @@
 setup:
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index: test
@@ -57,6 +59,8 @@ setup:
 ---
 load everything:
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test'
@@ -80,6 +84,8 @@ load everything:
 ---
 load a document:
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where @timestamp == "2021-04-28T18:50:23.142Z"'
@@ -97,6 +103,8 @@ load a document:
 ---
 filter on counter:
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where k8s.pod.network.tx == 1434577921'

+ 25 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/50_index_patterns.yml

@@ -1,3 +1,7 @@
+setup:
+  - skip:
+      features: allowed_warnings_regex
+
 ---
 disjoint_mappings:
   - do:
@@ -40,6 +44,8 @@ disjoint_mappings:
           - { "message2": 2 }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | keep message1, message2 | sort message1'
@@ -82,6 +88,8 @@ disjoint_mappings:
   - match: { values.0.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | keep message1, message2 | sort message1, message2'
@@ -147,6 +155,8 @@ disjoint_mappings:
   - match: { values.1.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | keep message1, message2 | sort message1 nulls first, message2'
@@ -165,6 +175,8 @@ disjoint_mappings:
   - match: { values.3.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | keep message1, message2 | sort message1 nulls first, message2 nulls first'
@@ -183,6 +195,8 @@ disjoint_mappings:
   - match: { values.3.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | keep message1, message2 | sort message1 desc nulls first, message2 desc nulls first'
@@ -201,6 +215,8 @@ disjoint_mappings:
   - match: { values.3.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | where message1 == "foo1" | keep message1, message2 | sort message1, message2'
@@ -213,6 +229,8 @@ disjoint_mappings:
   - match: { values.0.1: null }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | where message1 == "foo1" or message2 == 2 | keep message1, message2 | sort message1, message2'
@@ -227,6 +245,8 @@ disjoint_mappings:
   - match: { values.1.1: 2 }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | stats x = max(message2)'
@@ -236,6 +256,8 @@ disjoint_mappings:
   - match: { values.0.0: 2 }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | sort message1, message2 | eval x = message1, y = message2 + 1 | keep message1, message2, x, y'
@@ -311,6 +333,7 @@ same_name_different_type:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2  '
@@ -360,6 +383,8 @@ same_name_different_type_same_family:
           - { "message": "foo4" }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test1,test2 | sort message | keep message'

+ 8 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/60_enrich.yml

@@ -1,5 +1,7 @@
 ---
 setup:
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index:  cities
@@ -65,6 +67,8 @@ setup:
 ---
 "Basic":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | enrich cities_policy on city_id | keep name, city, country | sort name'
@@ -84,6 +88,8 @@ setup:
 
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | keep name, city_id | enrich cities_policy on city_id with country | sort name'
@@ -103,6 +109,8 @@ setup:
 
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | keep name, city_id | enrich cities_policy on city_id with country_name = country | sort name'

+ 4 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/61_enrich_ip.yml

@@ -1,5 +1,7 @@
 ---
 setup:
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index: networks
@@ -73,6 +75,8 @@ setup:
 "IP strings":
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'FROM events | eval ip_str = to_string(ip) | ENRICH networks-policy ON ip_str | sort @timestamp | KEEP ip, name, department, message'

+ 6 - 1
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/70_locale.yml

@@ -1,6 +1,7 @@
 ---
 setup:
-
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index: events
@@ -24,6 +25,8 @@ setup:
 ---
 "Date format with default locale":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'FROM events | eval fixed_format = date_format("MMMM", @timestamp), variable_format = date_format(format, @timestamp) | sort @timestamp | keep @timestamp, fixed_format, variable_format'
@@ -43,6 +46,8 @@ setup:
 ---
 "Date format with Italian locale":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'FROM events | eval fixed_format = date_format("MMMM", @timestamp), variable_format = date_format(format, @timestamp) | sort @timestamp | keep @timestamp, fixed_format, variable_format'

+ 38 - 1
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/80_text.yml

@@ -1,6 +1,7 @@
 ---
 setup:
-
+  - skip:
+      features: allowed_warnings_regex
   - do:
       indices.create:
         index: test
@@ -32,6 +33,8 @@ setup:
 ---
 "all":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort emp_no'
@@ -55,6 +58,8 @@ setup:
 ---
 "filter by text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where tag == "baz" | keep emp_no, name, job, tag'
@@ -74,6 +79,8 @@ setup:
 ---
 "like by text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where tag LIKE "*az" | keep emp_no, name, job, tag'
@@ -93,6 +100,8 @@ setup:
 ---
 "rlike by text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where tag RLIKE ".*az" | keep emp_no, name, job, tag'
@@ -112,6 +121,8 @@ setup:
 ---
 "eval and filter text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | eval x = tag | where x == "baz" | keep emp_no, name, job, x'
@@ -131,6 +142,8 @@ setup:
 ---
 "filter on text multi-field":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test |  where job == "IT Director" | keep emp_no, name, job, tag'
@@ -150,6 +163,8 @@ setup:
 ---
 "like by multi-field text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where job LIKE "*Specialist" | keep emp_no, name, job, tag'
@@ -169,6 +184,8 @@ setup:
 ---
 "rlike by multi-field text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | where job RLIKE ".*Specialist" | keep emp_no, name, job, tag'
@@ -189,6 +206,8 @@ setup:
 ---
 "sort by text":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort tag | keep emp_no, name, job, tag'
@@ -210,6 +229,8 @@ setup:
 ---
 "sort by text multi-field":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort job | keep emp_no, name, job, tag'
@@ -230,6 +251,8 @@ setup:
 ---
 "sort by text multi-field desc":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort job desc | keep emp_no, name, job, tag'
@@ -251,6 +274,8 @@ setup:
 ---
 "text in functions":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | sort name | eval description = concat(name, " - ", job) | keep description'
@@ -266,6 +291,8 @@ setup:
 ---
 "stats text with raw":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | stats jobs = count(job) | keep jobs'
@@ -280,6 +307,8 @@ setup:
 ---
 "stats text no raw":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | stats tags = count(tag) | keep tags'
@@ -294,6 +323,8 @@ setup:
 ---
 "stats by text with raw":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | stats names = count(name) by job | keep names'
@@ -309,6 +340,8 @@ setup:
 ---
 "stats by text no raw":
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test | stats names = count(name) by tag | keep names'
@@ -351,6 +384,8 @@ setup:
           - { "emp_no": 20, "name": "John", "job": "Payroll Specialist" }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test2 | sort emp_no | keep job'
@@ -392,6 +427,8 @@ setup:
           - { "emp_no": 20, "name": "John", "job": "Payroll Specialist" }
 
   - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test2 | sort emp_no | keep job'

+ 1 - 0
x-pack/plugin/esql/qa/server/single-node/src/yamlRestTest/resources/rest-api-spec/test/90_non_indexed.yml

@@ -89,6 +89,7 @@ unsupported:
   - do:
       allowed_warnings_regex:
         - "Field \\[.*\\] cannot be retrieved, it is unsupported or not indexed; returning null"
+        - "No limit defined, adding default limit of \\[.*\\]"
       esql.query:
         body:
           query: 'from test'

+ 12 - 5
x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java

@@ -39,6 +39,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 import static java.util.Collections.emptySet;
 import static org.elasticsearch.test.ListMatcher.matchesList;
@@ -209,27 +210,27 @@ public class RestEsqlTestCase extends ESRestTestCase {
     public void testTextMode() throws IOException {
         int count = randomIntBetween(0, 100);
         bulkLoadTestData(count);
-        var builder = builder().query(fromIndex() + " | keep keyword, integer").build();
+        var builder = builder().query(fromIndex() + " | keep keyword, integer | limit 100").build();
         assertEquals(expectedTextBody("txt", count, null), runEsqlAsTextWithFormat(builder, "txt", null));
     }
 
     public void testCSVMode() throws IOException {
         int count = randomIntBetween(0, 100);
         bulkLoadTestData(count);
-        var builder = builder().query(fromIndex() + " | keep keyword, integer").build();
+        var builder = builder().query(fromIndex() + " | keep keyword, integer | limit 100").build();
         assertEquals(expectedTextBody("csv", count, '|'), runEsqlAsTextWithFormat(builder, "csv", '|'));
     }
 
     public void testTSVMode() throws IOException {
         int count = randomIntBetween(0, 100);
         bulkLoadTestData(count);
-        var builder = builder().query(fromIndex() + " | keep keyword, integer").build();
+        var builder = builder().query(fromIndex() + " | keep keyword, integer | limit 100").build();
         assertEquals(expectedTextBody("tsv", count, null), runEsqlAsTextWithFormat(builder, "tsv", null));
     }
 
     public void testCSVNoHeaderMode() throws IOException {
         bulkLoadTestData(1);
-        var builder = builder().query(fromIndex() + " | keep keyword, integer").build();
+        var builder = builder().query(fromIndex() + " | keep keyword, integer | limit 100").build();
         Request request = prepareRequest();
         String mediaType = attachBody(builder, request);
         RequestOptions.Builder options = request.getOptions().toBuilder();
@@ -495,10 +496,16 @@ public class RestEsqlTestCase extends ESRestTestCase {
     private static HttpEntity performRequest(Request request, List<String> allowedWarnings) throws IOException {
         Response response = client().performRequest(request);
         assertEquals(200, response.getStatusLine().getStatusCode());
-        assertMap(response.getWarnings(), matchesList(allowedWarnings));
+        List<String> warnings = new ArrayList<>(response.getWarnings());
+        warnings.removeAll(mutedWarnings());
+        assertMap(warnings, matchesList(allowedWarnings));
         return response.getEntity();
     }
 
+    private static Set<String> mutedWarnings() {
+        return Set.of("No limit defined, adding default limit of [500]");
+    }
+
     private static void bulkLoadTestData(int count) throws IOException {
         Request request = new Request("PUT", "/" + testIndexName());
         request.setJsonEntity("""

+ 7 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java

@@ -166,4 +166,11 @@ public final class EsqlTestUtils {
         });
         return valuesList;
     }
+
+    public static List<String> withDefaultLimitWarning(List<String> warnings) {
+        List<String> result = warnings == null ? new ArrayList<>() : new ArrayList<>(warnings);
+        result.add("No limit defined, adding default limit of [500]");
+        return result;
+    }
+
 }

+ 11 - 3
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java

@@ -7,6 +7,7 @@
 
 package org.elasticsearch.xpack.esql.analysis;
 
+import org.elasticsearch.common.logging.HeaderWarning;
 import org.elasticsearch.common.regex.Regex;
 import org.elasticsearch.common.util.set.Sets;
 import org.elasticsearch.index.mapper.DateFieldMapper;
@@ -614,9 +615,16 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
         @Override
         public LogicalPlan apply(LogicalPlan logicalPlan, AnalyzerContext context) {
             List<LogicalPlan> limits = logicalPlan.collectFirstChildren(Limit.class::isInstance);
-            var limit = limits.isEmpty() == false
-                ? context.configuration().resultTruncationMaxSize() // user provided a limit: cap result entries to the max
-                : context.configuration().resultTruncationDefaultSize(); // user provided no limit: cap to a default
+            int limit;
+            if (limits.isEmpty()) {
+                HeaderWarning.addWarning(
+                    "No limit defined, adding default limit of [{}]",
+                    context.configuration().resultTruncationDefaultSize()
+                );
+                limit = context.configuration().resultTruncationDefaultSize(); // user provided no limit: cap to a default
+            } else {
+                limit = context.configuration().resultTruncationMaxSize(); // user provided a limit: cap result entries to the max
+            }
             return new Limit(Source.EMPTY, new Literal(Source.EMPTY, limit, DataTypes.INTEGER), logicalPlan);
         }
     }

+ 5 - 1
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java

@@ -422,7 +422,11 @@ public class CsvTests extends ESTestCase {
     private void assertWarnings(List<String> warnings) {
         List<String> normalized = new ArrayList<>(warnings.size());
         for (String w : warnings) {
-            normalized.add(HeaderWarning.extractWarningValueFromWarningHeader(w, false));
+            String normW = HeaderWarning.extractWarningValueFromWarningHeader(w, false);
+            if (normW.startsWith("No limit defined, adding default limit of [") == false) {
+                // too many tests do not have a LIMIT, we'll test this warning separately
+                normalized.add(normW);
+            }
         }
         assertMap(normalized, matchesList(testCase.expectedWarnings));
     }

+ 7 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java

@@ -39,6 +39,7 @@ import java.util.Map;
 import java.util.stream.IntStream;
 
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyze;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzer;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping;
@@ -1375,4 +1376,10 @@ public class AnalyzerTests extends ESTestCase {
         var limit = as(plan, Limit.class);
         assertThat(Expressions.names(limit.output()), contains(names));
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
+
 }

+ 6 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java

@@ -16,6 +16,7 @@ import org.elasticsearch.xpack.ql.type.DataType;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.hamcrest.Matchers.containsString;
 
@@ -340,4 +341,9 @@ public class VerifierTests extends ESTestCase {
         int index = message.indexOf(pattern);
         return message.substring(index + pattern.length());
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 6 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java

@@ -25,6 +25,7 @@ import java.util.Set;
 import java.util.function.Function;
 
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.configuration;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.SerializationTestUtils.serializeDeserialize;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyze;
 import static org.hamcrest.Matchers.equalTo;
@@ -145,4 +146,9 @@ public class PlanStreamInputTests extends ESTestCase {
             assertThat(sources.apply(planIn), equalTo(sources.apply(planOut)));
         }
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 7 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java

@@ -31,6 +31,7 @@ import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.ql.type.EsField;
 import org.junit.BeforeClass;
 
+import java.util.List;
 import java.util.Map;
 
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.L;
@@ -38,6 +39,7 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.statsForMissingField;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.nullValue;
@@ -282,4 +284,9 @@ public class LocalLogicalPlanOptimizerTests extends ESTestCase {
         // System.out.println(localPlan);
         return localPlan;
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 6 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java

@@ -57,6 +57,7 @@ import static java.util.Arrays.asList;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.configuration;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode.FINAL;
 import static org.elasticsearch.xpack.esql.plan.physical.EsStatsQueryExec.StatsType;
 import static org.hamcrest.Matchers.contains;
@@ -407,4 +408,9 @@ public class LocalPhysicalPlanOptimizerTests extends ESTestCase {
         var physical = mapper.map(logical);
         return physical;
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 5 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java

@@ -90,6 +90,7 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.emptySource;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.localSource;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.ql.TestUtils.relation;
 import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
 import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER;
@@ -1968,4 +1969,8 @@ public class LogicalPlanOptimizerTests extends ESTestCase {
         return new RLike(EMPTY, left, new RLikePattern(exp));
     }
 
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 5 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java

@@ -89,6 +89,7 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.configuration;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.statsForMissingField;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.SerializationTestUtils.assertSerialization;
 import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode.FINAL;
 import static org.elasticsearch.xpack.ql.expression.Expressions.name;
@@ -1963,4 +1964,8 @@ public class PhysicalPlanOptimizerTests extends ESTestCase {
         return sv.next();
     }
 
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 7 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java

@@ -36,12 +36,14 @@ import org.junit.BeforeClass;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.util.List;
 import java.util.Map;
 
 import static java.util.Arrays.asList;
 import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.SerializationTestUtils.assertSerialization;
 import static org.elasticsearch.xpack.ql.util.Queries.Clause.FILTER;
 import static org.elasticsearch.xpack.ql.util.Queries.Clause.MUST;
@@ -291,4 +293,9 @@ public class FilterTests extends ESTestCase {
     private QueryBuilder filterQueryForTransportNodes(PhysicalPlan plan) {
         return PlannerUtils.detectFilter(plan, AT_TIMESTAMP);
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 6 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java

@@ -41,6 +41,7 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_CFG;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.emptyPolicyResolution;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 
 public class DataNodeRequestTests extends AbstractWireSerializingTestCase<DataNodeRequest> {
 
@@ -182,4 +183,9 @@ public class DataNodeRequestTests extends AbstractWireSerializingTestCase<DataNo
         }
         return physical;
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 7 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java

@@ -27,11 +27,13 @@ import org.junit.Before;
 import org.mockito.stubbing.Answer;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonMap;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
@@ -117,4 +119,9 @@ public class PlanExecutorMetricsTests extends ESTestCase {
         fields.put(barField.getName(), singletonMap(barField.getName(), barField));
         return fields;
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }

+ 8 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/VerifierMetricsTests.java

@@ -14,6 +14,9 @@ import org.elasticsearch.xpack.esql.analysis.Verifier;
 import org.elasticsearch.xpack.esql.parser.EsqlParser;
 import org.elasticsearch.xpack.ql.index.IndexResolution;
 
+import java.util.List;
+
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzer;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.DISSECT;
 import static org.elasticsearch.xpack.esql.stats.FeatureMetric.EVAL;
@@ -196,4 +199,9 @@ public class VerifierMetricsTests extends ESTestCase {
 
         return metrics == null ? null : metrics.stats();
     }
+
+    @Override
+    protected List<String> filteredWarnings() {
+        return withDefaultLimitWarning(super.filteredWarnings());
+    }
 }