Browse Source

[ES|QL] Add/Modify annotations for operators for better doc generation (#108220)

* annotation for operators
Fang Xing 1 năm trước cách đây
mục cha
commit
4daac77e3b
44 tập tin đã thay đổi với 431 bổ sung273 xóa
  1. 0 34
      docs/reference/esql/functions/cidr_match.asciidoc
  2. 5 0
      docs/reference/esql/functions/description/cidr_match.asciidoc
  3. 1 1
      docs/reference/esql/functions/description/ends_with.asciidoc
  4. 1 1
      docs/reference/esql/functions/description/starts_with.asciidoc
  5. 0 34
      docs/reference/esql/functions/ends_with.asciidoc
  6. 13 0
      docs/reference/esql/functions/examples/cidr_match.asciidoc
  7. 13 0
      docs/reference/esql/functions/examples/ends_with.asciidoc
  8. 13 0
      docs/reference/esql/functions/examples/starts_with.asciidoc
  9. 47 0
      docs/reference/esql/functions/kibana/definition/cidr_match.json
  10. 8 5
      docs/reference/esql/functions/kibana/definition/ends_with.json
  11. 8 5
      docs/reference/esql/functions/kibana/definition/starts_with.json
  12. 12 0
      docs/reference/esql/functions/kibana/docs/cidr_match.md
  13. 6 1
      docs/reference/esql/functions/kibana/docs/ends_with.md
  14. 6 1
      docs/reference/esql/functions/kibana/docs/starts_with.md
  15. 15 0
      docs/reference/esql/functions/layout/cidr_match.asciidoc
  16. 1 0
      docs/reference/esql/functions/layout/ends_with.asciidoc
  17. 1 0
      docs/reference/esql/functions/layout/starts_with.asciidoc
  18. 3 1
      docs/reference/esql/functions/like.asciidoc
  19. 1 1
      docs/reference/esql/functions/operators.asciidoc
  20. 9 0
      docs/reference/esql/functions/parameters/cidr_match.asciidoc
  21. 2 2
      docs/reference/esql/functions/parameters/ends_with.asciidoc
  22. 2 2
      docs/reference/esql/functions/parameters/starts_with.asciidoc
  23. 3 1
      docs/reference/esql/functions/rlike.asciidoc
  24. 1 0
      docs/reference/esql/functions/signature/cidr_match.svg
  25. 0 34
      docs/reference/esql/functions/starts_with.asciidoc
  26. 2 2
      docs/reference/esql/functions/string-functions.asciidoc
  27. 10 0
      docs/reference/esql/functions/types/cidr_match.asciidoc
  28. 10 0
      docs/reference/esql/functions/types/like.asciidoc
  29. 6 0
      docs/reference/esql/functions/types/mul.asciidoc
  30. 10 0
      docs/reference/esql/functions/types/rlike.asciidoc
  31. 6 0
      docs/reference/esql/functions/types/sub.asciidoc
  32. 5 5
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec
  33. 11 2
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java
  34. 13 3
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java
  35. 13 3
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java
  36. 18 1
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java
  37. 8 0
      x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java
  38. 8 0
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
  39. 4 13
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java
  40. 2 13
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
  41. 2 13
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
  42. 39 3
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java
  43. 37 43
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java
  44. 56 49
      x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java

+ 0 - 34
docs/reference/esql/functions/cidr_match.asciidoc

@@ -1,34 +0,0 @@
-[discrete]
-[[esql-cidr_match]]
-=== `CIDR_MATCH`
-
-*Syntax*
-
-[source,esql]
-----
-CIDR_MATCH(ip, block1[, ..., blockN])
-----
-
-*Parameters*
-
-`ip`::
-IP address of type `ip` (both IPv4 and IPv6 are supported).
-
-`blockX`::
-CIDR block to test the IP against.
-
-*Description*
-
-Returns `true` if the provided IP is contained in one of the provided CIDR
-blocks.
-
-*Example*
-
-[source.merge.styled,esql]
-----
-include::{esql-specs}/ip.csv-spec[tag=cdirMatchMultipleArgs]
-----
-[%header.monospaced.styled,format=dsv,separator=|]
-|===
-include::{esql-specs}/ip.csv-spec[tag=cdirMatchMultipleArgs-result]
-|===

+ 5 - 0
docs/reference/esql/functions/description/cidr_match.asciidoc

@@ -0,0 +1,5 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Description*
+
+Returns true if the provided IP is contained in one of the provided CIDR blocks.

+ 1 - 1
docs/reference/esql/functions/description/ends_with.asciidoc

@@ -2,4 +2,4 @@
 
 *Description*
 
-Returns a boolean that indicates whether a keyword string ends with another string
+Returns a boolean that indicates whether a keyword string ends with another string.

+ 1 - 1
docs/reference/esql/functions/description/starts_with.asciidoc

@@ -2,4 +2,4 @@
 
 *Description*
 
-Returns a boolean that indicates whether a keyword string starts with another string
+Returns a boolean that indicates whether a keyword string starts with another string.

+ 0 - 34
docs/reference/esql/functions/ends_with.asciidoc

@@ -1,34 +0,0 @@
-[discrete]
-[[esql-ends_with]]
-=== `ENDS_WITH`
-
-*Syntax*
-
-[.text-center]
-image::esql/functions/signature/ends_with.svg[Embedded,opts=inline]
-
-*Parameters*
-
-`str`::
-String expression. If `null`, the function returns `null`.
-
-`suffix`::
-String expression. If `null`, the function returns `null`.
-
-*Description*
-
-Returns a boolean that indicates whether a keyword string ends with another
-string.
-
-include::types/ends_with.asciidoc[]
-
-*Example*
-
-[source.merge.styled,esql]
-----
-include::{esql-specs}/string.csv-spec[tag=endsWith]
-----
-[%header.monospaced.styled,format=dsv,separator=|]
-|===
-include::{esql-specs}/string.csv-spec[tag=endsWith-result]
-|===

+ 13 - 0
docs/reference/esql/functions/examples/cidr_match.asciidoc

@@ -0,0 +1,13 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Example*
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/ip.csv-spec[tag=cdirMatchMultipleArgs]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/ip.csv-spec[tag=cdirMatchMultipleArgs-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/ends_with.asciidoc

@@ -0,0 +1,13 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Example*
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/string.csv-spec[tag=endsWith]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/string.csv-spec[tag=endsWith-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/starts_with.asciidoc

@@ -0,0 +1,13 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Example*
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/docs.csv-spec[tag=startsWith]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/docs.csv-spec[tag=startsWith-result]
+|===
+

+ 47 - 0
docs/reference/esql/functions/kibana/definition/cidr_match.json

@@ -0,0 +1,47 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "cidr_match",
+  "description" : "Returns true if the provided IP is contained in one of the provided CIDR blocks.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "ip",
+          "type" : "ip",
+          "optional" : false,
+          "description" : "IP address of type `ip` (both IPv4 and IPv6 are supported)."
+        },
+        {
+          "name" : "blockX",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "CIDR block to test the IP against."
+        }
+      ],
+      "variadic" : true,
+      "returnType" : "boolean"
+    },
+    {
+      "params" : [
+        {
+          "name" : "ip",
+          "type" : "ip",
+          "optional" : false,
+          "description" : "IP address of type `ip` (both IPv4 and IPv6 are supported)."
+        },
+        {
+          "name" : "blockX",
+          "type" : "text",
+          "optional" : false,
+          "description" : "CIDR block to test the IP against."
+        }
+      ],
+      "variadic" : true,
+      "returnType" : "boolean"
+    }
+  ],
+  "examples" : [
+    "FROM hosts \n| WHERE CIDR_MATCH(ip1, \"127.0.0.2/32\", \"127.0.0.3/32\") \n| KEEP card, host, ip0, ip1"
+  ]
+}

+ 8 - 5
docs/reference/esql/functions/kibana/definition/ends_with.json

@@ -2,7 +2,7 @@
   "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
   "type" : "eval",
   "name" : "ends_with",
-  "description" : "Returns a boolean that indicates whether a keyword string ends with another string",
+  "description" : "Returns a boolean that indicates whether a keyword string ends with another string.",
   "signatures" : [
     {
       "params" : [
@@ -10,13 +10,13 @@
           "name" : "str",
           "type" : "keyword",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         },
         {
           "name" : "suffix",
           "type" : "keyword",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
@@ -28,17 +28,20 @@
           "name" : "str",
           "type" : "text",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         },
         {
           "name" : "suffix",
           "type" : "text",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
       "returnType" : "boolean"
     }
+  ],
+  "examples" : [
+    "FROM employees\n| KEEP last_name\n| EVAL ln_E = ENDS_WITH(last_name, \"d\")"
   ]
 }

+ 8 - 5
docs/reference/esql/functions/kibana/definition/starts_with.json

@@ -2,7 +2,7 @@
   "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
   "type" : "eval",
   "name" : "starts_with",
-  "description" : "Returns a boolean that indicates whether a keyword string starts with another string",
+  "description" : "Returns a boolean that indicates whether a keyword string starts with another string.",
   "signatures" : [
     {
       "params" : [
@@ -10,13 +10,13 @@
           "name" : "str",
           "type" : "keyword",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         },
         {
           "name" : "prefix",
           "type" : "keyword",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
@@ -28,17 +28,20 @@
           "name" : "str",
           "type" : "text",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         },
         {
           "name" : "prefix",
           "type" : "text",
           "optional" : false,
-          "description" : ""
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
       "returnType" : "boolean"
     }
+  ],
+  "examples" : [
+    "FROM employees\n| KEEP last_name\n| EVAL ln_S = STARTS_WITH(last_name, \"B\")"
   ]
 }

+ 12 - 0
docs/reference/esql/functions/kibana/docs/cidr_match.md

@@ -0,0 +1,12 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### CIDR_MATCH
+Returns true if the provided IP is contained in one of the provided CIDR blocks.
+
+```
+FROM hosts 
+| WHERE CIDR_MATCH(ip1, "127.0.0.2/32", "127.0.0.3/32") 
+| KEEP card, host, ip0, ip1
+```

+ 6 - 1
docs/reference/esql/functions/kibana/docs/ends_with.md

@@ -3,5 +3,10 @@ This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../READ
 -->
 
 ### ENDS_WITH
-Returns a boolean that indicates whether a keyword string ends with another string
+Returns a boolean that indicates whether a keyword string ends with another string.
 
+```
+FROM employees
+| KEEP last_name
+| EVAL ln_E = ENDS_WITH(last_name, "d")
+```

+ 6 - 1
docs/reference/esql/functions/kibana/docs/starts_with.md

@@ -3,5 +3,10 @@ This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../READ
 -->
 
 ### STARTS_WITH
-Returns a boolean that indicates whether a keyword string starts with another string
+Returns a boolean that indicates whether a keyword string starts with another string.
 
+```
+FROM employees
+| KEEP last_name
+| EVAL ln_S = STARTS_WITH(last_name, "B")
+```

+ 15 - 0
docs/reference/esql/functions/layout/cidr_match.asciidoc

@@ -0,0 +1,15 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+[discrete]
+[[esql-cidr_match]]
+=== `CIDR_MATCH`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/cidr_match.svg[Embedded,opts=inline]
+
+include::../parameters/cidr_match.asciidoc[]
+include::../description/cidr_match.asciidoc[]
+include::../types/cidr_match.asciidoc[]
+include::../examples/cidr_match.asciidoc[]

+ 1 - 0
docs/reference/esql/functions/layout/ends_with.asciidoc

@@ -12,3 +12,4 @@ image::esql/functions/signature/ends_with.svg[Embedded,opts=inline]
 include::../parameters/ends_with.asciidoc[]
 include::../description/ends_with.asciidoc[]
 include::../types/ends_with.asciidoc[]
+include::../examples/ends_with.asciidoc[]

+ 1 - 0
docs/reference/esql/functions/layout/starts_with.asciidoc

@@ -12,3 +12,4 @@ image::esql/functions/signature/starts_with.svg[Embedded,opts=inline]
 include::../parameters/starts_with.asciidoc[]
 include::../description/starts_with.asciidoc[]
 include::../types/starts_with.asciidoc[]
+include::../examples/starts_with.asciidoc[]

+ 3 - 1
docs/reference/esql/functions/like.asciidoc

@@ -13,6 +13,8 @@ The following wildcard characters are supported:
 * `*` matches zero or more characters.
 * `?` matches one character.
 
+include::./types/like.asciidoc[]
+
 [source.merge.styled,esql]
 ----
 include::{esql-specs}/docs.csv-spec[tag=like]
@@ -21,4 +23,4 @@ include::{esql-specs}/docs.csv-spec[tag=like]
 |===
 include::{esql-specs}/docs.csv-spec[tag=like-result]
 |===
-// end::body[]
+// end::body[]

+ 1 - 1
docs/reference/esql/functions/operators.asciidoc

@@ -24,7 +24,7 @@ include::unary.asciidoc[]
 include::logical.asciidoc[]
 include::predicates.asciidoc[]
 include::cast.asciidoc[]
-include::cidr_match.asciidoc[]
+include::layout/cidr_match.asciidoc[]
 include::in.asciidoc[]
 include::like.asciidoc[]
 include::rlike.asciidoc[]

+ 9 - 0
docs/reference/esql/functions/parameters/cidr_match.asciidoc

@@ -0,0 +1,9 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`ip`::
+IP address of type `ip` (both IPv4 and IPv6 are supported).
+
+`blockX`::
+CIDR block to test the IP against.

+ 2 - 2
docs/reference/esql/functions/parameters/ends_with.asciidoc

@@ -3,7 +3,7 @@
 *Parameters*
 
 `str`::
-
+String expression. If `null`, the function returns `null`.
 
 `suffix`::
-
+String expression. If `null`, the function returns `null`.

+ 2 - 2
docs/reference/esql/functions/parameters/starts_with.asciidoc

@@ -3,7 +3,7 @@
 *Parameters*
 
 `str`::
-
+String expression. If `null`, the function returns `null`.
 
 `prefix`::
-
+String expression. If `null`, the function returns `null`.

+ 3 - 1
docs/reference/esql/functions/rlike.asciidoc

@@ -8,6 +8,8 @@ Use `RLIKE` to filter data based on string patterns using using
 the left-hand side of the operator, but it can also act on a constant (literal)
 expression. The right-hand side of the operator represents the pattern.
 
+include::./types/like.asciidoc[]
+
 [source.merge.styled,esql]
 ----
 include::{esql-specs}/docs.csv-spec[tag=rlike]
@@ -16,4 +18,4 @@ include::{esql-specs}/docs.csv-spec[tag=rlike]
 |===
 include::{esql-specs}/docs.csv-spec[tag=rlike-result]
 |===
-// end::body[]
+// end::body[]

+ 1 - 0
docs/reference/esql/functions/signature/cidr_match.svg

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="432" height="46" viewbox="0 0 432 46"><defs><style type="text/css">#guide .c{fill:none;stroke:#222222;}#guide .k{fill:#000000;font-family:Roboto Mono,Sans-serif;font-size:20px;}#guide .s{fill:#e4f4ff;stroke:#222222;}#guide .syn{fill:#8D8D8D;font-family:Roboto Mono,Sans-serif;font-size:20px;}</style></defs><path class="c" d="M0 31h5m140 0h10m32 0h10m44 0h10m32 0h10m92 0h10m32 0h5"/><rect class="s" x="5" y="5" width="140" height="36"/><text class="k" x="15" y="31">CIDR_MATCH</text><rect class="s" x="155" y="5" width="32" height="36" rx="7"/><text class="syn" x="165" y="31">(</text><rect class="s" x="197" y="5" width="44" height="36" rx="7"/><text class="k" x="207" y="31">ip</text><rect class="s" x="251" y="5" width="32" height="36" rx="7"/><text class="syn" x="261" y="31">,</text><rect class="s" x="293" y="5" width="92" height="36" rx="7"/><text class="k" x="303" y="31">blockX</text><rect class="s" x="395" y="5" width="32" height="36" rx="7"/><text class="syn" x="405" y="31">)</text></svg>

+ 0 - 34
docs/reference/esql/functions/starts_with.asciidoc

@@ -1,34 +0,0 @@
-[discrete]
-[[esql-starts_with]]
-=== `STARTS_WITH`
-
-*Syntax*
-
-[.text-center]
-image::esql/functions/signature/starts_with.svg[Embedded,opts=inline]
-
-*Parameters*
-
-`str`::
-String expression. If `null`, the function returns `null`.
-
-`prefix`::
-String expression. If `null`, the function returns `null`.
-
-*Description*
-
-Returns a boolean that indicates whether a keyword string starts with another
-string.
-
-include::types/starts_with.asciidoc[]
-
-*Example*
-
-[source.merge.styled,esql]
-----
-include::{esql-specs}/docs.csv-spec[tag=startsWith]
-----
-[%header.monospaced.styled,format=dsv,separator=|]
-|===
-include::{esql-specs}/docs.csv-spec[tag=startsWith-result]
-|===

+ 2 - 2
docs/reference/esql/functions/string-functions.asciidoc

@@ -28,7 +28,7 @@
 // end::string_list[]
 
 include::layout/concat.asciidoc[]
-include::ends_with.asciidoc[]
+include::layout/ends_with.asciidoc[]
 include::layout/from_base64.asciidoc[]
 include::layout/left.asciidoc[]
 include::layout/length.asciidoc[]
@@ -38,7 +38,7 @@ include::layout/replace.asciidoc[]
 include::layout/right.asciidoc[]
 include::layout/rtrim.asciidoc[]
 include::layout/split.asciidoc[]
-include::starts_with.asciidoc[]
+include::layout/starts_with.asciidoc[]
 include::layout/substring.asciidoc[]
 include::layout/to_base64.asciidoc[]
 include::layout/to_lower.asciidoc[]

+ 10 - 0
docs/reference/esql/functions/types/cidr_match.asciidoc

@@ -0,0 +1,10 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Supported types*
+
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+ip | blockX | result
+ip | keyword | boolean
+ip | text | boolean
+|===

+ 10 - 0
docs/reference/esql/functions/types/like.asciidoc

@@ -0,0 +1,10 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Supported types*
+
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+str | pattern | result
+keyword | keyword | boolean
+text | text | boolean
+|===

+ 6 - 0
docs/reference/esql/functions/types/mul.asciidoc

@@ -6,7 +6,13 @@
 |===
 lhs | rhs | result
 double | double | double
+double | integer | double
+double | long | double
+integer | double | double
 integer | integer | integer
+integer | long | long
+long | double | double
+long | integer | long
 long | long | long
 unsigned_long | unsigned_long | unsigned_long
 |===

+ 10 - 0
docs/reference/esql/functions/types/rlike.asciidoc

@@ -0,0 +1,10 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Supported types*
+
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+str | pattern | caseInsensitive | result
+keyword | keyword | boolean | boolean
+text | text | boolean | boolean
+|===

+ 6 - 0
docs/reference/esql/functions/types/sub.asciidoc

@@ -9,7 +9,13 @@ date_period | date_period | date_period
 datetime | date_period | datetime
 datetime | time_duration | datetime
 double | double | double
+double | integer | double
+double | long | double
+integer | double | double
 integer | integer | integer
+integer | long | long
+long | double | double
+long | integer | long
 long | long | long
 time_duration | time_duration | time_duration
 unsigned_long | unsigned_long | unsigned_long

+ 5 - 5
x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec

@@ -125,7 +125,7 @@ bin           |[field, buckets, from, to]          |["integer|long|double|date",
 bucket        |[field, buckets, from, to]          |["integer|long|double|date", "integer|double|date_period|time_duration", "integer|long|double|date", "integer|long|double|date"]  |[Numeric or date expression from which to derive buckets., Target number of buckets., Start of the range. Can be a number or a date expressed as a string., End of the range. Can be a number or a date expressed as a string.]
 case          |[condition, trueValue]              |[boolean, "boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version"]                     |["", ""]
 ceil          |number                              |"double|integer|long|unsigned_long"                                                                                               |Numeric expression. If `null`, the function returns `null`.
-cidr_match    |[ip, blockX]                        |[ip, "keyword|text"]                                                                                                              |[, CIDR block to test the IP against.]
+cidr_match    |[ip, blockX]                        |[ip, "keyword|text"]                                                                                                              |[IP address of type `ip` (both IPv4 and IPv6 are supported)., CIDR block to test the IP against.]
 coalesce      |first                               |"boolean|text|integer|keyword|long"                                                                                               |Expression to evaluate
 concat        |[string1, string2]                  |["keyword|text", "keyword|text"]                                                                                                  |[Strings to concatenate., Strings to concatenate.]
 cos           |angle                               |"double|integer|long|unsigned_long"                                                                                               |An angle, in radians. If `null`, the function returns `null`.
@@ -138,7 +138,7 @@ date_format   |[dateFormat, date]                  |["keyword|text", date]
 date_parse    |[datePattern, dateString]           |["keyword|text", "keyword|text"]                                                                                                  |[The date format. Refer to the https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/time/format/DateTimeFormatter.html[`DateTimeFormatter` documentation] for the syntax. If `null`\, the function returns `null`., Date expression as a string. If `null` or an empty string\, the function returns `null`.]
 date_trunc    |[interval, date]                    |["date_period|time_duration", date]                                                                                               |[Interval; expressed using the timespan literal syntax., Date expression]
 e             |null                                |null                                                                                                                              |null
-ends_with     |[str, suffix]                       |["keyword|text", "keyword|text"]                                                                                                  |[, ]
+ends_with     |[str, suffix]                       |["keyword|text", "keyword|text"]                                                                                                  |[String expression. If `null`\, the function returns `null`., String expression. If `null`\, the function returns `null`.]
 floor         |number                              |"double|integer|long|unsigned_long"                                                                                               |Numeric expression. If `null`, the function returns `null`.
 from_base64   |string                              |"keyword|text"                                                                                                                    |A base64 string.
 greatest      |first                               |"integer|long|double|boolean|keyword|text|ip|version"                                                                             |[""]
@@ -186,7 +186,7 @@ st_intersects |[geomA, geomB]                      |["geo_point|cartesian_point|
 st_within     |[geomA, geomB]                      |["geo_point|cartesian_point|geo_shape|cartesian_shape", "geo_point|cartesian_point|geo_shape|cartesian_shape"]                    |[Geometry column name or variable of geometry type, Geometry column name or variable of geometry type]
 st_x          |point                               |"geo_point|cartesian_point"                                                                                                       |[""]
 st_y          |point                               |"geo_point|cartesian_point"                                                                                                       |[""]
-starts_with   |[str, prefix]                       |["keyword|text", "keyword|text"]                                                                                                  |[, ]
+starts_with   |[str, prefix]                       |["keyword|text", "keyword|text"]                                                                                                  |[String expression. If `null`\, the function returns `null`., String expression. If `null`\, the function returns `null`.]
 substring     |[string, start, length]             |["keyword|text", integer, integer]                                                                                                |[String expression. If `null`\, the function returns `null`., Start position., Length of the substring from the start position. Optional; if omitted\, all positions after `start` are returned.]
 sum           |number                              |"double|integer|long"                                                                                                             |[""]
 tan           |angle                               |"double|integer|long|unsigned_long"                                                                                               |An angle, in radians. If `null`, the function returns `null`.
@@ -252,7 +252,7 @@ date_format   |Returns a string representation of a date, in the provided format
 date_parse    |Returns a date by parsing the second argument using the format specified in the first argument.
 date_trunc    |Rounds down a date to the closest interval.
 e             |Returns {wikipedia}/E_(mathematical_constant)[Euler's number].
-ends_with     |Returns a boolean that indicates whether a keyword string ends with another string
+ends_with     |Returns a boolean that indicates whether a keyword string ends with another string.
 floor         |Round a number down to the nearest integer.
 from_base64   |Decode a base64 string.
 greatest      |Returns the maximum value from many columns.
@@ -300,7 +300,7 @@ st_intersects |Returns whether the two geometries or geometry columns intersect.
 st_within     |Returns whether the first geometry is within the second geometry.
 st_x          |Extracts the x-coordinate from a point geometry.
 st_y          |Extracts the y-coordinate from a point geometry.
-starts_with   |Returns a boolean that indicates whether a keyword string starts with another string
+starts_with   |Returns a boolean that indicates whether a keyword string starts with another string.
 substring     |Returns a substring of a string, specified by a start position and an optional length
 sum           |The sum of a numeric field.
 tan           |Returns the {wikipedia}/Sine_and_cosine[Tangent] trigonometric function of an angle.

+ 11 - 2
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java

@@ -12,6 +12,7 @@ import org.elasticsearch.common.network.CIDRUtils;
 import org.elasticsearch.compute.ann.Evaluator;
 import org.elasticsearch.compute.operator.EvalOperator;
 import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
@@ -49,10 +50,18 @@ public class CIDRMatch extends EsqlScalarFunction {
     private final Expression ipField;
     private final List<Expression> matches;
 
-    @FunctionInfo(returnType = "boolean", description = "Returns true if the provided IP is contained in one of the provided CIDR blocks.")
+    @FunctionInfo(
+        returnType = "boolean",
+        description = "Returns true if the provided IP is contained in one of the provided CIDR blocks.",
+        examples = @Example(file = "ip", tag = "cdirMatchMultipleArgs")
+    )
     public CIDRMatch(
         Source source,
-        @Param(name = "ip", type = { "ip" }) Expression ipField,
+        @Param(
+            name = "ip",
+            type = { "ip" },
+            description = "IP address of type `ip` (both IPv4 and IPv6 are supported)."
+        ) Expression ipField,
         @Param(name = "blockX", type = { "keyword", "text" }, description = "CIDR block to test the IP against.") List<Expression> matches
     ) {
         super(source, CollectionUtils.combine(singletonList(ipField), matches));

+ 13 - 3
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java

@@ -10,6 +10,7 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.compute.ann.Evaluator;
 import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
@@ -34,12 +35,21 @@ public class EndsWith extends EsqlScalarFunction {
 
     @FunctionInfo(
         returnType = "boolean",
-        description = "Returns a boolean that indicates whether a keyword string ends with another string"
+        description = "Returns a boolean that indicates whether a keyword string ends with another string.",
+        examples = @Example(file = "string", tag = "endsWith")
     )
     public EndsWith(
         Source source,
-        @Param(name = "str", type = { "keyword", "text" }) Expression str,
-        @Param(name = "suffix", type = { "keyword", "text" }) Expression suffix
+        @Param(
+            name = "str",
+            type = { "keyword", "text" },
+            description = "String expression. If `null`, the function returns `null`."
+        ) Expression str,
+        @Param(
+            name = "suffix",
+            type = { "keyword", "text" },
+            description = "String expression. If `null`, the function returns `null`."
+        ) Expression suffix
     ) {
         super(source, Arrays.asList(str, suffix));
         this.str = str;

+ 13 - 3
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java

@@ -10,6 +10,7 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.compute.ann.Evaluator;
 import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
@@ -34,12 +35,21 @@ public class StartsWith extends EsqlScalarFunction {
 
     @FunctionInfo(
         returnType = "boolean",
-        description = "Returns a boolean that indicates whether a keyword string starts with another string"
+        description = "Returns a boolean that indicates whether a keyword string starts with another string.",
+        examples = @Example(file = "docs", tag = "startsWith")
     )
     public StartsWith(
         Source source,
-        @Param(name = "str", type = { "keyword", "text" }) Expression str,
-        @Param(name = "prefix", type = { "keyword", "text" }) Expression prefix
+        @Param(
+            name = "str",
+            type = { "keyword", "text" },
+            description = "String expression. If `null`, the function returns `null`."
+        ) Expression str,
+        @Param(
+            name = "prefix",
+            type = { "keyword", "text" },
+            description = "String expression. If `null`, the function returns `null`."
+        ) Expression prefix
     ) {
         super(source, Arrays.asList(str, prefix));
         this.str = str;

+ 18 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java

@@ -10,6 +10,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string;
 import org.apache.lucene.util.automaton.Automata;
 import org.elasticsearch.compute.operator.EvalOperator;
 import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
+import org.elasticsearch.xpack.esql.expression.function.Example;
+import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
+import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern;
 import org.elasticsearch.xpack.ql.tree.NodeInfo;
@@ -21,7 +24,21 @@ import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal
 import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString;
 
 public class WildcardLike extends org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardLike implements EvaluatorMapper {
-    public WildcardLike(Source source, Expression left, WildcardPattern pattern) {
+    @FunctionInfo(returnType = "boolean", description = """
+        Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
+        usually acts on a field placed on the left-hand side of the operator, but it can
+        also act on a constant (literal) expression. The right-hand side of the operator
+        represents the pattern.
+
+        The following wildcard characters are supported:
+
+        * `*` matches zero or more characters.
+        * `?` matches one character.""", examples = @Example(file = "docs", tag = "like"))
+    public WildcardLike(
+        Source source,
+        @Param(name = "str", type = { "keyword", "text" }) Expression left,
+        @Param(name = "pattern", type = { "keyword", "text" }) WildcardPattern pattern
+    ) {
         super(source, left, pattern, false);
     }
 

+ 8 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java

@@ -8,6 +8,8 @@
 package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison;
 
 import org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions;
+import org.elasticsearch.xpack.esql.expression.function.Example;
+import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.type.EsqlDataTypes;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.expression.Expressions;
@@ -24,6 +26,12 @@ import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal
 import static org.elasticsearch.xpack.ql.util.StringUtils.ordinal;
 
 public class In extends org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In {
+    @FunctionInfo(
+        returnType = "boolean",
+        description = "The `IN` operator allows testing whether a field or expression equals an element in a list of literals, "
+            + "fields or expressions:",
+        examples = @Example(file = "row", tag = "in-with-expressions")
+    )
     public In(Source source, Expression value, List<Expression> list) {
         super(source, value, list);
     }

+ 8 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java

@@ -1172,6 +1172,14 @@ public abstract class AbstractFunctionTestCase extends ESTestCase {
             renderTypes(List.of("v"));
             return;
         }
+        if (name.equalsIgnoreCase("rlike")) {
+            renderTypes(List.of("str", "pattern", "caseInsensitive"));
+            return;
+        }
+        if (name.equalsIgnoreCase("like")) {
+            renderTypes(List.of("str", "pattern"));
+            return;
+        }
         FunctionDefinition definition = definition(name);
         if (definition != null) {
             EsqlFunctionRegistry.FunctionDescription description = EsqlFunctionRegistry.description(definition);

+ 4 - 13
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java

@@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name;
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
+import org.elasticsearch.xpack.esql.expression.function.FunctionName;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
 import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.tree.Source;
-import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 
 import java.util.List;
@@ -24,7 +24,8 @@ import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class CIDRMatchTests extends AbstractScalarFunctionTestCase {
+@FunctionName("cidr_match")
+public class CIDRMatchTests extends AbstractFunctionTestCase {
     public CIDRMatchTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
         this.testCase = testCaseSupplier.get();
     }
@@ -90,14 +91,4 @@ public class CIDRMatchTests extends AbstractScalarFunctionTestCase {
     protected Expression build(Source source, List<Expression> args) {
         return new CIDRMatch(source, args.get(0), List.of(args.get(1)));
     }
-
-    @Override
-    protected List<ArgumentSpec> argSpec() {
-        return List.of(required(DataTypes.IP), required(strings()));
-    }
-
-    @Override
-    protected DataType expectedType(List<DataType> argTypes) {
-        return DataTypes.BOOLEAN;
-    }
 }

+ 2 - 13
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java

@@ -11,11 +11,10 @@ import com.carrotsearch.randomizedtesting.annotations.Name;
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.tree.Source;
-import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.hamcrest.Matcher;
 
@@ -25,7 +24,7 @@ import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class EndsWithTests extends AbstractScalarFunctionTestCase {
+public class EndsWithTests extends AbstractFunctionTestCase {
     public EndsWithTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
         this.testCase = testCaseSupplier.get();
     }
@@ -122,22 +121,12 @@ public class EndsWithTests extends AbstractScalarFunctionTestCase {
         return parameterSuppliersFromTypedData(suppliers);
     }
 
-    @Override
-    protected DataType expectedType(List<DataType> argTypes) {
-        return DataTypes.BOOLEAN;
-    }
-
     private Matcher<Object> resultsMatcher(List<TestCaseSupplier.TypedData> typedData) {
         String str = ((BytesRef) typedData.get(0).data()).utf8ToString();
         String prefix = ((BytesRef) typedData.get(1).data()).utf8ToString();
         return equalTo(str.endsWith(prefix));
     }
 
-    @Override
-    protected List<ArgumentSpec> argSpec() {
-        return List.of(required(strings()), required(strings()));
-    }
-
     @Override
     protected Expression build(Source source, List<Expression> args) {
         return new EndsWith(source, args.get(0), args.get(1));

+ 2 - 13
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java

@@ -11,11 +11,10 @@ import com.carrotsearch.randomizedtesting.annotations.Name;
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.tree.Source;
-import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.hamcrest.Matcher;
 
@@ -24,7 +23,7 @@ import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class StartsWithTests extends AbstractScalarFunctionTestCase {
+public class StartsWithTests extends AbstractFunctionTestCase {
     public StartsWithTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
         this.testCase = testCaseSupplier.get();
     }
@@ -64,22 +63,12 @@ public class StartsWithTests extends AbstractScalarFunctionTestCase {
         })));
     }
 
-    @Override
-    protected DataType expectedType(List<DataType> argTypes) {
-        return DataTypes.BOOLEAN;
-    }
-
     private Matcher<Object> resultsMatcher(List<TestCaseSupplier.TypedData> typedData) {
         String str = ((BytesRef) typedData.get(0).data()).utf8ToString();
         String prefix = ((BytesRef) typedData.get(1).data()).utf8ToString();
         return equalTo(str.startsWith(prefix));
     }
 
-    @Override
-    protected List<ArgumentSpec> argSpec() {
-        return List.of(required(strings()), required(strings()));
-    }
-
     @Override
     protected Expression build(Source source, List<Expression> args) {
         return new StartsWith(source, args.get(0), args.get(1));

+ 39 - 3
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java

@@ -13,17 +13,23 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
+import org.elasticsearch.xpack.esql.expression.function.FunctionName;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
 import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.expression.Literal;
 import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern;
 import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DataTypes;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.startsWith;
 
+@FunctionName("like")
 public class WildcardLikeTests extends AbstractFunctionTestCase {
     public WildcardLikeTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
         this.testCase = testCaseSupplier.get();
@@ -31,12 +37,40 @@ public class WildcardLikeTests extends AbstractFunctionTestCase {
 
     @ParametersFactory
     public static Iterable<Object[]> parameters() {
-        return RLikeTests.parameters(str -> {
+        List<Object[]> cases = (List<Object[]>) RLikeTests.parameters(str -> {
             for (String syntax : new String[] { "\\", "*" }) {
                 str = str.replace(syntax, "\\" + syntax);
             }
             return str;
         }, () -> "*");
+
+        List<TestCaseSupplier> suppliers = new ArrayList<>();
+        addCases(suppliers);
+
+        for (TestCaseSupplier supplier : suppliers) {
+            cases.add(new Object[] { supplier });
+        }
+
+        return cases;
+    }
+
+    private static void addCases(List<TestCaseSupplier> suppliers) {
+        for (DataType type : new DataType[] { DataTypes.KEYWORD, DataTypes.TEXT }) {
+            suppliers.add(new TestCaseSupplier(" with " + type.esType(), List.of(type, type), () -> {
+                BytesRef str = new BytesRef(randomAlphaOfLength(5));
+                BytesRef pattern = new BytesRef(randomAlphaOfLength(2));
+                Boolean match = str.utf8ToString().startsWith(pattern.utf8ToString());
+                return new TestCaseSupplier.TestCase(
+                    List.of(
+                        new TestCaseSupplier.TypedData(str, type, "str"),
+                        new TestCaseSupplier.TypedData(pattern, type, "pattern").forceLiteral()
+                    ),
+                    startsWith("AutomataMatchEvaluator[input=Attribute[channel=0], pattern=digraph Automaton {\n"),
+                    DataTypes.BOOLEAN,
+                    equalTo(match)
+                );
+            }));
+        }
     }
 
     @Override
@@ -48,8 +82,10 @@ public class WildcardLikeTests extends AbstractFunctionTestCase {
     protected Expression build(Source source, List<Expression> args) {
         Expression expression = args.get(0);
         Literal pattern = (Literal) args.get(1);
-        Literal caseInsensitive = (Literal) args.get(2);
-        assertThat(caseInsensitive.fold(), equalTo(false));
+        if (args.size() > 2) {
+            Literal caseInsensitive = (Literal) args.get(2);
+            assertThat(caseInsensitive.fold(), equalTo(false));
+        }
         return new WildcardLike(source, expression, new WildcardPattern(((BytesRef) pattern.fold()).utf8ToString()));
     }
 }

+ 37 - 43
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java

@@ -16,6 +16,7 @@ import org.elasticsearch.xpack.ql.expression.Expression;
 import org.elasticsearch.xpack.ql.tree.Source;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Supplier;
 
@@ -30,33 +31,32 @@ public class MulTests extends AbstractFunctionTestCase {
 
     @ParametersFactory
     public static Iterable<Object[]> parameters() {
-        return parameterSuppliersFromTypedData(List.of(new TestCaseSupplier("Int * Int", () -> {
-            // Ensure we don't have an overflow
-            int rhs = randomIntBetween(-255, 255);
-            int lhs = randomIntBetween(-255, 255);
-            return new TestCaseSupplier.TestCase(
-                List.of(
-                    new TestCaseSupplier.TypedData(lhs, DataTypes.INTEGER, "lhs"),
-                    new TestCaseSupplier.TypedData(rhs, DataTypes.INTEGER, "rhs")
-                ),
-                "MulIntsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                DataTypes.INTEGER,
-                equalTo(lhs * rhs)
-            );
-        }), new TestCaseSupplier("Long * Long", () -> {
-            // Ensure we don't have an overflow
-            long rhs = randomLongBetween(-1024, 1024);
-            long lhs = randomLongBetween(-1024, 1024);
-            return new TestCaseSupplier.TestCase(
-                List.of(
-                    new TestCaseSupplier.TypedData(lhs, DataTypes.LONG, "lhs"),
-                    new TestCaseSupplier.TypedData(rhs, DataTypes.LONG, "rhs")
+        List<TestCaseSupplier> suppliers = new ArrayList<>();
+        suppliers.addAll(
+            TestCaseSupplier.forBinaryWithWidening(
+                new TestCaseSupplier.NumericTypeTestConfigs<Number>(
+                    new TestCaseSupplier.NumericTypeTestConfig<>(-255, 255, (l, r) -> l.intValue() * r.intValue(), "MulIntsEvaluator"),
+                    new TestCaseSupplier.NumericTypeTestConfig<>(
+                        -1024L,
+                        1024L,
+                        (l, r) -> l.longValue() * r.longValue(),
+                        "MulLongsEvaluator"
+                    ),
+                    new TestCaseSupplier.NumericTypeTestConfig<>(
+                        -1024D,
+                        1024D,
+                        (l, r) -> l.doubleValue() * r.doubleValue(),
+                        "MulDoublesEvaluator"
+                    )
                 ),
-                "MulLongsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                DataTypes.LONG,
-                equalTo(lhs * rhs)
-            );
-        }), new TestCaseSupplier("Double * Double", () -> {
+                "lhs",
+                "rhs",
+                (lhs, rhs) -> List.of(),
+                true
+            )
+        );
+
+        suppliers.add(new TestCaseSupplier("Double * Double", List.of(DataTypes.DOUBLE, DataTypes.DOUBLE), () -> {
             double rhs = randomDouble();
             double lhs = randomDouble();
             return new TestCaseSupplier.TestCase(
@@ -68,39 +68,33 @@ public class MulTests extends AbstractFunctionTestCase {
                 DataTypes.DOUBLE,
                 equalTo(lhs * rhs)
             );
-        }), /* new TestCaseSupplier("ULong * ULong", () -> {
-             // Ensure we don't have an overflow
-             long rhs = randomLongBetween(0, 1024);
-             long lhs = randomLongBetween(0, 1024);
-             BigInteger lhsBI = unsignedLongAsBigInteger(lhs);
-             BigInteger rhsBI = unsignedLongAsBigInteger(rhs);
-             return new TestCase(
-                 Source.EMPTY,
-                 List.of(new TypedData(lhs, DataTypes.UNSIGNED_LONG, "lhs"), new TypedData(rhs, DataTypes.UNSIGNED_LONG, "rhs")),
-                 "MulUnsignedLongsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                 equalTo(asLongUnsigned(lhsBI.multiply(rhsBI).longValue()))
-             );
-            })
-            */
+        }));
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.INTEGER,
                 () -> randomBoolean() ? Integer.MIN_VALUE : Integer.MAX_VALUE,
                 () -> randomIntBetween(2, Integer.MAX_VALUE),
                 "MulIntsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.LONG,
                 () -> randomBoolean() ? Long.MIN_VALUE : Long.MAX_VALUE,
                 () -> randomLongBetween(2L, Long.MAX_VALUE),
                 "MulLongsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.UNSIGNED_LONG,
                 () -> asLongUnsigned(UNSIGNED_LONG_MAX),
                 () -> asLongUnsigned(randomLongBetween(-Long.MAX_VALUE, Long.MAX_VALUE)),
                 "MulUnsignedLongsEvaluator"
             )
-        ));
+        );
+
+        return parameterSuppliersFromTypedData(suppliers);
     }
 
     @Override

+ 56 - 49
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java

@@ -37,45 +37,35 @@ public class SubTests extends AbstractFunctionTestCase {
 
     @ParametersFactory
     public static Iterable<Object[]> parameters() {
-        return parameterSuppliersFromTypedData(List.of(new TestCaseSupplier("Int - Int", () -> {
-            // Ensure we don't have an overflow
-            int rhs = randomIntBetween((Integer.MIN_VALUE >> 1) - 1, (Integer.MAX_VALUE >> 1) - 1);
-            int lhs = randomIntBetween((Integer.MIN_VALUE >> 1) - 1, (Integer.MAX_VALUE >> 1) - 1);
-            return new TestCaseSupplier.TestCase(
-                List.of(
-                    new TestCaseSupplier.TypedData(lhs, DataTypes.INTEGER, "lhs"),
-                    new TestCaseSupplier.TypedData(rhs, DataTypes.INTEGER, "rhs")
+
+        List<TestCaseSupplier> suppliers = TestCaseSupplier.forBinaryWithWidening(
+            new TestCaseSupplier.NumericTypeTestConfigs<Number>(
+                new TestCaseSupplier.NumericTypeTestConfig<>(
+                    (Integer.MIN_VALUE >> 1) - 1,
+                    (Integer.MAX_VALUE >> 1) - 1,
+                    (l, r) -> l.intValue() - r.intValue(),
+                    "SubIntsEvaluator"
                 ),
-                "SubIntsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                DataTypes.INTEGER,
-                equalTo(lhs - rhs)
-            );
-        }), new TestCaseSupplier("Long - Long", () -> {
-            // Ensure we don't have an overflow
-            long rhs = randomLongBetween((Long.MIN_VALUE >> 1) - 1, (Long.MAX_VALUE >> 1) - 1);
-            long lhs = randomLongBetween((Long.MIN_VALUE >> 1) - 1, (Long.MAX_VALUE >> 1) - 1);
-            return new TestCaseSupplier.TestCase(
-                List.of(
-                    new TestCaseSupplier.TypedData(lhs, DataTypes.LONG, "lhs"),
-                    new TestCaseSupplier.TypedData(rhs, DataTypes.LONG, "rhs")
+                new TestCaseSupplier.NumericTypeTestConfig<>(
+                    (Long.MIN_VALUE >> 1) - 1,
+                    (Long.MAX_VALUE >> 1) - 1,
+                    (l, r) -> l.longValue() - r.longValue(),
+                    "SubLongsEvaluator"
                 ),
-                "SubLongsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                DataTypes.LONG,
-                equalTo(lhs - rhs)
-            );
-        }), new TestCaseSupplier("Double - Double", () -> {
-            double rhs = randomDouble();
-            double lhs = randomDouble();
-            return new TestCaseSupplier.TestCase(
-                List.of(
-                    new TestCaseSupplier.TypedData(lhs, DataTypes.DOUBLE, "lhs"),
-                    new TestCaseSupplier.TypedData(rhs, DataTypes.DOUBLE, "rhs")
-                ),
-                "SubDoublesEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
-                DataTypes.DOUBLE,
-                equalTo(lhs - rhs)
-            );
-        })/*, new TestCaseSupplier("ULong - ULong", () -> {
+                new TestCaseSupplier.NumericTypeTestConfig<>(
+                    Double.NEGATIVE_INFINITY,
+                    Double.POSITIVE_INFINITY,
+                    (l, r) -> l.doubleValue() - r.doubleValue(),
+                    "SubDoublesEvaluator"
+                )
+            ),
+            "lhs",
+            "rhs",
+            (lhs, rhs) -> List.of(),
+            true
+        );
+
+        /* new TestCaseSupplier("ULong - ULong", () -> {
             // Ensure we don't have an overflow
             // TODO: we should be able to test values over Long.MAX_VALUE too...
             long rhs = randomLongBetween(0, (Long.MAX_VALUE >> 1) - 1);
@@ -88,7 +78,9 @@ public class SubTests extends AbstractFunctionTestCase {
                 "SubUnsignedLongsEvaluator[lhs=Attribute[channel=0], rhs=Attribute[channel=1]]",
                 equalTo(asLongUnsigned(lhsBI.subtract(rhsBI).longValue()))
             );
-          }) */, new TestCaseSupplier("Datetime - Period", () -> {
+          }) */
+
+        suppliers.add(new TestCaseSupplier("Datetime - Period", () -> {
             long lhs = (Long) randomLiteral(DataTypes.DATETIME).value();
             Period rhs = (Period) randomLiteral(EsqlDataTypes.DATE_PERIOD).value();
             return new TestCaseSupplier.TestCase(
@@ -100,7 +92,8 @@ public class SubTests extends AbstractFunctionTestCase {
                 DataTypes.DATETIME,
                 equalTo(asMillis(asDateTime(lhs).minus(rhs)))
             );
-        }), new TestCaseSupplier("Period - Period", () -> {
+        }));
+        suppliers.add(new TestCaseSupplier("Period - Period", () -> {
             Period lhs = (Period) randomLiteral(EsqlDataTypes.DATE_PERIOD).value();
             Period rhs = (Period) randomLiteral(EsqlDataTypes.DATE_PERIOD).value();
             return new TestCaseSupplier.TestCase(
@@ -112,7 +105,8 @@ public class SubTests extends AbstractFunctionTestCase {
                 EsqlDataTypes.DATE_PERIOD,
                 equalTo(lhs.minus(rhs))
             );
-        }), new TestCaseSupplier("Datetime - Duration", () -> {
+        }));
+        suppliers.add(new TestCaseSupplier("Datetime - Duration", () -> {
             long lhs = (Long) randomLiteral(DataTypes.DATETIME).value();
             Duration rhs = (Duration) randomLiteral(EsqlDataTypes.TIME_DURATION).value();
             TestCaseSupplier.TestCase testCase = new TestCaseSupplier.TestCase(
@@ -125,7 +119,8 @@ public class SubTests extends AbstractFunctionTestCase {
                 equalTo(asMillis(asDateTime(lhs).minus(rhs)))
             );
             return testCase;
-        }), new TestCaseSupplier("Duration - Duration", () -> {
+        }));
+        suppliers.add(new TestCaseSupplier("Duration - Duration", () -> {
             Duration lhs = (Duration) randomLiteral(EsqlDataTypes.TIME_DURATION).value();
             Duration rhs = (Duration) randomLiteral(EsqlDataTypes.TIME_DURATION).value();
             return new TestCaseSupplier.TestCase(
@@ -137,7 +132,8 @@ public class SubTests extends AbstractFunctionTestCase {
                 EsqlDataTypes.TIME_DURATION,
                 equalTo(lhs.minus(rhs))
             );
-        }), new TestCaseSupplier("MV", () -> {
+        }));
+        suppliers.add(new TestCaseSupplier("MV", () -> {
             // Ensure we don't have an overflow
             int rhs = randomIntBetween((Integer.MIN_VALUE >> 1) - 1, (Integer.MAX_VALUE >> 1) - 1);
             int lhs = randomIntBetween((Integer.MIN_VALUE >> 1) - 1, (Integer.MAX_VALUE >> 1) - 1);
@@ -152,39 +148,50 @@ public class SubTests extends AbstractFunctionTestCase {
                 is(nullValue())
             ).withWarning("Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.")
                 .withWarning("Line -1:-1: java.lang.IllegalArgumentException: single-value function encountered multi-value");
-        }),
-            // exact math arithmetic exceptions
+        }));
+        // exact math arithmetic exceptions
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.INTEGER,
                 () -> Integer.MIN_VALUE,
                 () -> randomIntBetween(1, Integer.MAX_VALUE),
                 "SubIntsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.INTEGER,
                 () -> randomIntBetween(Integer.MIN_VALUE, -2),
                 () -> Integer.MAX_VALUE,
                 "SubIntsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.LONG,
                 () -> Long.MIN_VALUE,
                 () -> randomLongBetween(1L, Long.MAX_VALUE),
                 "SubLongsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.LONG,
                 () -> randomLongBetween(Long.MIN_VALUE, -2L),
                 () -> Long.MAX_VALUE,
                 "SubLongsEvaluator"
-            ),
+            )
+        );
+        suppliers.add(
             arithmeticExceptionOverflowCase(
                 DataTypes.UNSIGNED_LONG,
                 () -> ZERO_AS_UNSIGNED_LONG,
                 () -> randomLongBetween(-Long.MAX_VALUE, Long.MAX_VALUE),
                 "SubUnsignedLongsEvaluator"
             )
-        ));
+        );
+
+        return parameterSuppliersFromTypedData(suppliers);
     }
 
     @Override