Kaynağa Gözat

[8.19] ES|QL Support for ST_GEOHASH, ST_GEOTILE and ST_GEOHEX (#125143) (#128938)

* ES|QL Support for ST_GEOHASH, ST_GEOTILE and ST_GEOHEX (#125143)

Added support for the three primary scalar grid functions:
* `ST_GEOHASH(geom, precision)`
* `ST_GEOTILE(geom, precision)`
* `ST_GEOHEX(geom, precision)`

As well as versions of these three that take an optional `geo_shape` boundary (must be a `BBOX` ie. `Rectangle`).

And also supporting conversion functions that convert the grid-id from long to string and back to long.

This work represents the core of the feature to support geo-grid aggregations in ES|QL.

* Remove license checking mechanism from tests (unsupported in 8.x)

* Add 8.x level generated docs

* Link new spatial functions into the docs

* Remove unused imports after removal of license level tests

* Fix list syntax

* Fix asciidoc links
Craig Taverner 4 ay önce
ebeveyn
işleme
c64a02fed9
100 değiştirilmiş dosya ile 2887 ekleme ve 162 silme
  1. 6 0
      docs/changelog/125143.yaml
  2. 2 3
      docs/reference/esql/functions/description/scalb.asciidoc
  3. 5 0
      docs/reference/esql/functions/description/st_geohash.asciidoc
  4. 5 0
      docs/reference/esql/functions/description/st_geohash_to_long.asciidoc
  5. 5 0
      docs/reference/esql/functions/description/st_geohash_to_string.asciidoc
  6. 5 0
      docs/reference/esql/functions/description/st_geohex.asciidoc
  7. 5 0
      docs/reference/esql/functions/description/st_geohex_to_long.asciidoc
  8. 5 0
      docs/reference/esql/functions/description/st_geohex_to_string.asciidoc
  9. 5 0
      docs/reference/esql/functions/description/st_geotile.asciidoc
  10. 5 0
      docs/reference/esql/functions/description/st_geotile_to_long.asciidoc
  11. 5 0
      docs/reference/esql/functions/description/st_geotile_to_string.asciidoc
  12. 13 0
      docs/reference/esql/functions/examples/scalb.asciidoc
  13. 0 13
      docs/reference/esql/functions/examples/scalb.md
  14. 13 0
      docs/reference/esql/functions/examples/st_geohash.asciidoc
  15. 13 0
      docs/reference/esql/functions/examples/st_geohash_to_long.asciidoc
  16. 13 0
      docs/reference/esql/functions/examples/st_geohash_to_string.asciidoc
  17. 13 0
      docs/reference/esql/functions/examples/st_geohex.asciidoc
  18. 13 0
      docs/reference/esql/functions/examples/st_geohex_to_long.asciidoc
  19. 13 0
      docs/reference/esql/functions/examples/st_geohex_to_string.asciidoc
  20. 13 0
      docs/reference/esql/functions/examples/st_geotile.asciidoc
  21. 13 0
      docs/reference/esql/functions/examples/st_geotile_to_long.asciidoc
  22. 13 0
      docs/reference/esql/functions/examples/st_geotile_to_string.asciidoc
  23. 2 2
      docs/reference/esql/functions/kibana/definition/scalb.json
  24. 55 0
      docs/reference/esql/functions/kibana/definition/st_geohash.json
  25. 37 0
      docs/reference/esql/functions/kibana/definition/st_geohash_to_long.json
  26. 37 0
      docs/reference/esql/functions/kibana/definition/st_geohash_to_string.json
  27. 55 0
      docs/reference/esql/functions/kibana/definition/st_geohex.json
  28. 37 0
      docs/reference/esql/functions/kibana/definition/st_geohex_to_long.json
  29. 37 0
      docs/reference/esql/functions/kibana/definition/st_geohex_to_string.json
  30. 55 0
      docs/reference/esql/functions/kibana/definition/st_geotile.json
  31. 37 0
      docs/reference/esql/functions/kibana/definition/st_geotile_to_long.json
  32. 37 0
      docs/reference/esql/functions/kibana/definition/st_geotile_to_string.json
  33. 4 2
      docs/reference/esql/functions/kibana/docs/scalb.md
  34. 23 0
      docs/reference/esql/functions/kibana/docs/st_geohash.md
  35. 11 0
      docs/reference/esql/functions/kibana/docs/st_geohash_to_long.md
  36. 11 0
      docs/reference/esql/functions/kibana/docs/st_geohash_to_string.md
  37. 23 0
      docs/reference/esql/functions/kibana/docs/st_geohex.md
  38. 11 0
      docs/reference/esql/functions/kibana/docs/st_geohex_to_long.md
  39. 11 0
      docs/reference/esql/functions/kibana/docs/st_geohex_to_string.md
  40. 22 0
      docs/reference/esql/functions/kibana/docs/st_geotile.md
  41. 11 0
      docs/reference/esql/functions/kibana/docs/st_geotile_to_long.md
  42. 11 0
      docs/reference/esql/functions/kibana/docs/st_geotile_to_string.md
  43. 15 0
      docs/reference/esql/functions/layout/scalb.asciidoc
  44. 15 0
      docs/reference/esql/functions/layout/st_geohash.asciidoc
  45. 15 0
      docs/reference/esql/functions/layout/st_geohash_to_long.asciidoc
  46. 15 0
      docs/reference/esql/functions/layout/st_geohash_to_string.asciidoc
  47. 15 0
      docs/reference/esql/functions/layout/st_geohex.asciidoc
  48. 15 0
      docs/reference/esql/functions/layout/st_geohex_to_long.asciidoc
  49. 15 0
      docs/reference/esql/functions/layout/st_geohex_to_string.asciidoc
  50. 15 0
      docs/reference/esql/functions/layout/st_geotile.asciidoc
  51. 15 0
      docs/reference/esql/functions/layout/st_geotile_to_long.asciidoc
  52. 15 0
      docs/reference/esql/functions/layout/st_geotile_to_string.asciidoc
  53. 9 0
      docs/reference/esql/functions/parameters/scalb.asciidoc
  54. 12 0
      docs/reference/esql/functions/parameters/st_geohash.asciidoc
  55. 6 0
      docs/reference/esql/functions/parameters/st_geohash_to_long.asciidoc
  56. 6 0
      docs/reference/esql/functions/parameters/st_geohash_to_string.asciidoc
  57. 12 0
      docs/reference/esql/functions/parameters/st_geohex.asciidoc
  58. 6 0
      docs/reference/esql/functions/parameters/st_geohex_to_long.asciidoc
  59. 6 0
      docs/reference/esql/functions/parameters/st_geohex_to_string.asciidoc
  60. 12 0
      docs/reference/esql/functions/parameters/st_geotile.asciidoc
  61. 6 0
      docs/reference/esql/functions/parameters/st_geotile_to_long.asciidoc
  62. 6 0
      docs/reference/esql/functions/parameters/st_geotile_to_string.asciidoc
  63. 1 0
      docs/reference/esql/functions/signature/scalb.svg
  64. 1 0
      docs/reference/esql/functions/signature/st_geohash.svg
  65. 1 0
      docs/reference/esql/functions/signature/st_geohash_to_long.svg
  66. 1 0
      docs/reference/esql/functions/signature/st_geohash_to_string.svg
  67. 1 0
      docs/reference/esql/functions/signature/st_geohex.svg
  68. 1 0
      docs/reference/esql/functions/signature/st_geohex_to_long.svg
  69. 1 0
      docs/reference/esql/functions/signature/st_geohex_to_string.svg
  70. 1 0
      docs/reference/esql/functions/signature/st_geotile.svg
  71. 1 0
      docs/reference/esql/functions/signature/st_geotile_to_long.svg
  72. 1 0
      docs/reference/esql/functions/signature/st_geotile_to_string.svg
  73. 18 0
      docs/reference/esql/functions/spatial-functions.asciidoc
  74. 16 0
      docs/reference/esql/functions/types/scalb.asciidoc
  75. 10 0
      docs/reference/esql/functions/types/st_geohash.asciidoc
  76. 10 0
      docs/reference/esql/functions/types/st_geohash_to_long.asciidoc
  77. 10 0
      docs/reference/esql/functions/types/st_geohash_to_string.asciidoc
  78. 10 0
      docs/reference/esql/functions/types/st_geohex.asciidoc
  79. 10 0
      docs/reference/esql/functions/types/st_geohex_to_long.asciidoc
  80. 10 0
      docs/reference/esql/functions/types/st_geohex_to_string.asciidoc
  81. 10 0
      docs/reference/esql/functions/types/st_geotile.asciidoc
  82. 10 0
      docs/reference/esql/functions/types/st_geotile_to_long.asciidoc
  83. 10 0
      docs/reference/esql/functions/types/st_geotile_to_string.asciidoc
  84. 0 23
      docs/reference/query-languages/esql/_snippets/functions/layout/round_to.md
  85. 0 23
      docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md
  86. 0 10
      docs/reference/query-languages/esql/_snippets/functions/parameters/round_to.md
  87. 0 10
      docs/reference/query-languages/esql/_snippets/functions/parameters/scalb.md
  88. 0 18
      docs/reference/query-languages/esql/_snippets/functions/types/round_to.md
  89. 0 15
      docs/reference/query-languages/esql/_snippets/functions/types/scalb.md
  90. 0 1
      docs/reference/query-languages/esql/images/functions/round_to.svg
  91. 0 1
      docs/reference/query-languages/esql/images/functions/scalb.svg
  92. 6 0
      x-pack/plugin/esql/build.gradle
  93. 475 0
      x-pack/plugin/esql/licenses/lucene-LICENSE.txt
  94. 192 0
      x-pack/plugin/esql/licenses/lucene-NOTICE.txt
  95. 1 1
      x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java
  96. 884 0
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/spatial-grid.csv-spec
  97. 1 40
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialExtentAggregationNoLicenseIT.java
  98. 142 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialGridLicenseTestCase.java
  99. 66 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialNoLicenseTestCase.java
  100. 45 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohashLicenseIT.java

+ 6 - 0
docs/changelog/125143.yaml

@@ -0,0 +1,6 @@
+pr: 125143
+summary: "ES|QL Support for ST_GEOHASH, ST_GEOTILE and ST_GEOHEX"
+area: "ES|QL"
+type: enhancement
+issues:
+ - 123903

+ 2 - 3
docs/reference/esql/functions/description/scalb.md → docs/reference/esql/functions/description/scalb.asciidoc

@@ -1,6 +1,5 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
 
-**Description**
+*Description*
 
 Returns the result of `d * 2 ^ scaleFactor`, Similar to Java's `scalb` function. Result is rounded as if performed by a single correctly rounded floating-point multiply to a member of the double value set.
-

+ 5 - 0
docs/reference/esql/functions/description/st_geohash.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*
+
+Calculates the `geohash` of the supplied geo_point at the specified precision. The result is long encoded. Use <<esql-st_geohash_to_string>> to convert the result to a string.  These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>> and the <<search-aggregations-bucket-geohashgrid-aggregation,`geohash_grid` aggregation>>.

+ 5 - 0
docs/reference/esql/functions/description/st_geohash_to_long.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*
+
+Converts an input value representing a geohash grid-ID in string format into a long.

+ 5 - 0
docs/reference/esql/functions/description/st_geohash_to_string.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*
+
+Converts an input value representing a geohash grid-ID in long format into a string.

+ 5 - 0
docs/reference/esql/functions/description/st_geohex.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*
+
+Calculates the `geohex`, the H3 cell-id, of the supplied geo_point at the specified precision. The result is long encoded. Use <<esql-st_geohex_to_string>> to convert the result to a string.  These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>> and the <<search-aggregations-bucket-geohexgrid-aggregation,`geohex_grid` aggregation>>.

+ 5 - 0
docs/reference/esql/functions/description/st_geohex_to_long.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*
+
+Converts an input value representing a geohex grid-ID in string format into a long.

+ 5 - 0
docs/reference/esql/functions/description/st_geohex_to_string.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*
+
+Converts an input value representing a Geohex grid-ID in long format into a string.

+ 5 - 0
docs/reference/esql/functions/description/st_geotile.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*
+
+Calculates the `geotile` of the supplied geo_point at the specified precision. The result is long encoded. Use <<esql-st_geotile_to_string>> to convert the result to a string.  These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>> and the <<search-aggregations-bucket-geotilegrid-aggregation,`geotile_grid` aggregation>>.

+ 5 - 0
docs/reference/esql/functions/description/st_geotile_to_long.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*
+
+Converts an input value representing a geotile grid-ID in string format into a long.

+ 5 - 0
docs/reference/esql/functions/description/st_geotile_to_string.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*
+
+Converts an input value representing a geotile grid-ID in long format into a string.

+ 13 - 0
docs/reference/esql/functions/examples/scalb.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}/floats.csv-spec[tag=scalb]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/floats.csv-spec[tag=scalb-result]
+|===
+

+ 0 - 13
docs/reference/esql/functions/examples/scalb.md

@@ -1,13 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Example**
-
-```esql
-row x = 3.0, y = 10 | eval z = scalb(x, y)
-```
-
-| x:double | y:integer | z:double |
-| --- | --- | --- |
-| 3.0 | 10 | 3072.0 |
-
-

+ 13 - 0
docs/reference/esql/functions/examples/st_geohash.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}/spatial-grid.csv-spec[tag=st_geohash-grid]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=st_geohash-grid-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geohash_to_long.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}/spatial-grid.csv-spec[tag=geohash_to_long]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geohash_to_long-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geohash_to_string.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}/spatial-grid.csv-spec[tag=geohash_to_string]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geohash_to_string-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geohex.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}/spatial-grid.csv-spec[tag=st_geohex-grid]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=st_geohex-grid-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geohex_to_long.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}/spatial-grid.csv-spec[tag=geohex_to_long]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geohex_to_long-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geohex_to_string.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}/spatial-grid.csv-spec[tag=geohex_to_string]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geohex_to_string-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geotile.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}/spatial-grid.csv-spec[tag=st_geotile-grid]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=st_geotile-grid-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geotile_to_long.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}/spatial-grid.csv-spec[tag=geotile_to_long]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geotile_to_long-result]
+|===
+

+ 13 - 0
docs/reference/esql/functions/examples/st_geotile_to_string.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}/spatial-grid.csv-spec[tag=geotile_to_string]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/spatial-grid.csv-spec[tag=geotile_to_string-result]
+|===
+

+ 2 - 2
docs/reference/esql/functions/kibana/definition/scalb.json

@@ -1,6 +1,6 @@
 {
-  "comment" : "This is generated by ESQLs AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
-  "type" : "scalar",
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
   "name" : "scalb",
   "description" : "Returns the result of `d * 2 ^ scaleFactor`,\nSimilar to Java's `scalb` function. Result is rounded as if\nperformed by a single correctly rounded floating-point multiply\nto a member of the double value set.",
   "signatures" : [

+ 55 - 0
docs/reference/esql/functions/kibana/definition/st_geohash.json

@@ -0,0 +1,55 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohash",
+  "description" : "Calculates the `geohash` of the supplied geo_point at the specified precision.\nThe result is long encoded. Use <<esql-st_geohash_to_string>> to convert the result to a string.\n\nThese functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>\nand the <<search-aggregations-bucket-geohashgrid-aggregation,`geohash_grid` aggregation>>.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [1 and 12](https://en.wikipedia.org/wiki/Geohash)."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [1 and 12](https://en.wikipedia.org/wiki/Geohash)."
+        },
+        {
+          "name" : "bounds",
+          "type" : "geo_shape",
+          "optional" : true,
+          "description" : "Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "FROM airports\n| EVAL geohash = ST_GEOHASH(location, 1)\n| STATS\n    count = COUNT(*),\n    centroid = ST_CENTROID_AGG(location)\n      BY geohash\n| WHERE count >= 10\n| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)\n| KEEP count, centroid, geohashString\n| SORT count DESC, geohashString ASC"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geohash_to_long.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohash_to_long",
+  "description" : "Converts an input value representing a geohash grid-ID in string format into a long.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input geohash grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input geohash grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "ROW geohash = \"u3bu\"\n| EVAL geohashLong = ST_GEOHASH_TO_LONG(geohash)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geohash_to_string.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohash_to_string",
+  "description" : "Converts an input value representing a geohash grid-ID in long format into a string.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input geohash grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input geohash grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    }
+  ],
+  "examples" : [
+    "ROW geohash = TO_LONG(13686180)\n| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 55 - 0
docs/reference/esql/functions/kibana/definition/st_geohex.json

@@ -0,0 +1,55 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohex",
+  "description" : "Calculates the `geohex`, the H3 cell-id, of the supplied geo_point at the specified precision.\nThe result is long encoded. Use <<esql-st_geohex_to_string>> to convert the result to a string.\n\nThese functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>\nand the <<search-aggregations-bucket-geohexgrid-aggregation,`geohex_grid` aggregation>>.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 15](https://h3geo.org/docs/core-library/restable/)."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 15](https://h3geo.org/docs/core-library/restable/)."
+        },
+        {
+          "name" : "bounds",
+          "type" : "geo_shape",
+          "optional" : true,
+          "description" : "Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "FROM airports\n| EVAL geohex = ST_GEOHEX(location, 1)\n| STATS\n    count = COUNT(*),\n    centroid = ST_CENTROID_AGG(location)\n      BY geohex\n| WHERE count >= 10\n| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)\n| KEEP count, centroid, geohexString\n| SORT count DESC, geohexString ASC"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geohex_to_long.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohex_to_long",
+  "description" : "Converts an input value representing a geohex grid-ID in string format into a long.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input geohex grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input geohex grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "ROW geohex = \"841f059ffffffff\"\n| EVAL geohexLong = ST_GEOHEX_TO_LONG(geohex)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geohex_to_string.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geohex_to_string",
+  "description" : "Converts an input value representing a Geohex grid-ID in long format into a string.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input Geohex grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input Geohex grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    }
+  ],
+  "examples" : [
+    "ROW geohex = 595020895127339007\n| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 55 - 0
docs/reference/esql/functions/kibana/definition/st_geotile.json

@@ -0,0 +1,55 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geotile",
+  "description" : "Calculates the `geotile` of the supplied geo_point at the specified precision.\nThe result is long encoded. Use <<esql-st_geotile_to_string>> to convert the result to a string.\n\nThese functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>\nand the <<search-aggregations-bucket-geotilegrid-aggregation,`geotile_grid` aggregation>>.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 29](https://wiki.openstreetmap.org/wiki/Zoom_levels)."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "geometry",
+          "type" : "geo_point",
+          "optional" : false,
+          "description" : "Expression of type `geo_point`. If `null`, the function returns `null`."
+        },
+        {
+          "name" : "precision",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 29](https://wiki.openstreetmap.org/wiki/Zoom_levels)."
+        },
+        {
+          "name" : "bounds",
+          "type" : "geo_shape",
+          "optional" : true,
+          "description" : "Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "FROM airports\n| EVAL geotile = ST_GEOTILE(location, 2)\n| STATS\n    count = COUNT(*),\n    centroid = ST_CENTROID_AGG(location)\n      BY geotile\n| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)\n| SORT count DESC, geotileString ASC\n| KEEP count, centroid, geotileString"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geotile_to_long.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geotile_to_long",
+  "description" : "Converts an input value representing a geotile grid-ID in string format into a long.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input geotile grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input geotile grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "examples" : [
+    "ROW geotile = \"4/8/5\"\n| EVAL geotileLong = ST_GEOTILE_TO_LONG(geotile)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 37 - 0
docs/reference/esql/functions/kibana/definition/st_geotile_to_string.json

@@ -0,0 +1,37 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "eval",
+  "name" : "st_geotile_to_string",
+  "description" : "Converts an input value representing a geotile grid-ID in long format into a string.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "keyword",
+          "optional" : false,
+          "description" : "Input geotile grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    },
+    {
+      "params" : [
+        {
+          "name" : "grid_id",
+          "type" : "long",
+          "optional" : false,
+          "description" : "Input geotile grid-id. The input can be a single- or multi-valued column or an expression."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "keyword"
+    }
+  ],
+  "examples" : [
+    "ROW geotile = 1152921508901814277\n| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)"
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}

+ 4 - 2
docs/reference/esql/functions/kibana/docs/scalb.md

@@ -1,4 +1,6 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
 
 ### SCALB
 Returns the result of `d * 2 ^ scaleFactor`,
@@ -6,6 +8,6 @@ Similar to Java's `scalb` function. Result is rounded as if
 performed by a single correctly rounded floating-point multiply
 to a member of the double value set.
 
-```esql
+```
 row x = 3.0, y = 10 | eval z = scalb(x, y)
 ```

+ 23 - 0
docs/reference/esql/functions/kibana/docs/st_geohash.md

@@ -0,0 +1,23 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHASH
+Calculates the `geohash` of the supplied geo_point at the specified precision.
+The result is long encoded. Use <<esql-st_geohash_to_string>> to convert the result to a string.
+
+These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>
+and the <<search-aggregations-bucket-geohashgrid-aggregation,`geohash_grid` aggregation>>.
+
+```
+FROM airports
+| EVAL geohash = ST_GEOHASH(location, 1)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| WHERE count >= 10
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geohash_to_long.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHASH_TO_LONG
+Converts an input value representing a geohash grid-ID in string format into a long.
+
+```
+ROW geohash = "u3bu"
+| EVAL geohashLong = ST_GEOHASH_TO_LONG(geohash)
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geohash_to_string.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHASH_TO_STRING
+Converts an input value representing a geohash grid-ID in long format into a string.
+
+```
+ROW geohash = TO_LONG(13686180)
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+```

+ 23 - 0
docs/reference/esql/functions/kibana/docs/st_geohex.md

@@ -0,0 +1,23 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHEX
+Calculates the `geohex`, the H3 cell-id, of the supplied geo_point at the specified precision.
+The result is long encoded. Use <<esql-st_geohex_to_string>> to convert the result to a string.
+
+These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>
+and the <<search-aggregations-bucket-geohexgrid-aggregation,`geohex_grid` aggregation>>.
+
+```
+FROM airports
+| EVAL geohex = ST_GEOHEX(location, 1)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| WHERE count >= 10
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP count, centroid, geohexString
+| SORT count DESC, geohexString ASC
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geohex_to_long.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHEX_TO_LONG
+Converts an input value representing a geohex grid-ID in string format into a long.
+
+```
+ROW geohex = "841f059ffffffff"
+| EVAL geohexLong = ST_GEOHEX_TO_LONG(geohex)
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geohex_to_string.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOHEX_TO_STRING
+Converts an input value representing a Geohex grid-ID in long format into a string.
+
+```
+ROW geohex = 595020895127339007
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+```

+ 22 - 0
docs/reference/esql/functions/kibana/docs/st_geotile.md

@@ -0,0 +1,22 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOTILE
+Calculates the `geotile` of the supplied geo_point at the specified precision.
+The result is long encoded. Use <<esql-st_geotile_to_string>> to convert the result to a string.
+
+These functions are related to the <<query-dsl-geo-grid-query,`geo_grid` query>>
+and the <<search-aggregations-bucket-geotilegrid-aggregation,`geotile_grid` aggregation>>.
+
+```
+FROM airports
+| EVAL geotile = ST_GEOTILE(location, 2)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| SORT count DESC, geotileString ASC
+| KEEP count, centroid, geotileString
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geotile_to_long.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOTILE_TO_LONG
+Converts an input value representing a geotile grid-ID in string format into a long.
+
+```
+ROW geotile = "4/8/5"
+| EVAL geotileLong = ST_GEOTILE_TO_LONG(geotile)
+```

+ 11 - 0
docs/reference/esql/functions/kibana/docs/st_geotile_to_string.md

@@ -0,0 +1,11 @@
+<!--
+This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+-->
+
+### ST_GEOTILE_TO_STRING
+Converts an input value representing a geotile grid-ID in long format into a string.
+
+```
+ROW geotile = 1152921508901814277
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+```

+ 15 - 0
docs/reference/esql/functions/layout/scalb.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-scalb]]
+=== `SCALB`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/scalb.svg[Embedded,opts=inline]
+
+include::../parameters/scalb.asciidoc[]
+include::../description/scalb.asciidoc[]
+include::../types/scalb.asciidoc[]
+include::../examples/scalb.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohash.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-st_geohash]]
+=== `ST_GEOHASH`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohash.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohash.asciidoc[]
+include::../description/st_geohash.asciidoc[]
+include::../types/st_geohash.asciidoc[]
+include::../examples/st_geohash.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohash_to_long.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-st_geohash_to_long]]
+=== `ST_GEOHASH_TO_LONG`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohash_to_long.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohash_to_long.asciidoc[]
+include::../description/st_geohash_to_long.asciidoc[]
+include::../types/st_geohash_to_long.asciidoc[]
+include::../examples/st_geohash_to_long.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohash_to_string.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-st_geohash_to_string]]
+=== `ST_GEOHASH_TO_STRING`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohash_to_string.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohash_to_string.asciidoc[]
+include::../description/st_geohash_to_string.asciidoc[]
+include::../types/st_geohash_to_string.asciidoc[]
+include::../examples/st_geohash_to_string.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohex.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-st_geohex]]
+=== `ST_GEOHEX`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohex.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohex.asciidoc[]
+include::../description/st_geohex.asciidoc[]
+include::../types/st_geohex.asciidoc[]
+include::../examples/st_geohex.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohex_to_long.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-st_geohex_to_long]]
+=== `ST_GEOHEX_TO_LONG`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohex_to_long.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohex_to_long.asciidoc[]
+include::../description/st_geohex_to_long.asciidoc[]
+include::../types/st_geohex_to_long.asciidoc[]
+include::../examples/st_geohex_to_long.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geohex_to_string.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-st_geohex_to_string]]
+=== `ST_GEOHEX_TO_STRING`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geohex_to_string.svg[Embedded,opts=inline]
+
+include::../parameters/st_geohex_to_string.asciidoc[]
+include::../description/st_geohex_to_string.asciidoc[]
+include::../types/st_geohex_to_string.asciidoc[]
+include::../examples/st_geohex_to_string.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geotile.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-st_geotile]]
+=== `ST_GEOTILE`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geotile.svg[Embedded,opts=inline]
+
+include::../parameters/st_geotile.asciidoc[]
+include::../description/st_geotile.asciidoc[]
+include::../types/st_geotile.asciidoc[]
+include::../examples/st_geotile.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geotile_to_long.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-st_geotile_to_long]]
+=== `ST_GEOTILE_TO_LONG`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geotile_to_long.svg[Embedded,opts=inline]
+
+include::../parameters/st_geotile_to_long.asciidoc[]
+include::../description/st_geotile_to_long.asciidoc[]
+include::../types/st_geotile_to_long.asciidoc[]
+include::../examples/st_geotile_to_long.asciidoc[]

+ 15 - 0
docs/reference/esql/functions/layout/st_geotile_to_string.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-st_geotile_to_string]]
+=== `ST_GEOTILE_TO_STRING`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/st_geotile_to_string.svg[Embedded,opts=inline]
+
+include::../parameters/st_geotile_to_string.asciidoc[]
+include::../description/st_geotile_to_string.asciidoc[]
+include::../types/st_geotile_to_string.asciidoc[]
+include::../examples/st_geotile_to_string.asciidoc[]

+ 9 - 0
docs/reference/esql/functions/parameters/scalb.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*
+
+`d`::
+Numeric expression for the multiplier. If `null`, the function returns `null`.
+
+`scaleFactor`::
+Numeric expression for the scale factor. If `null`, the function returns `null`.

+ 12 - 0
docs/reference/esql/functions/parameters/st_geohash.asciidoc

@@ -0,0 +1,12 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`geometry`::
+Expression of type `geo_point`. If `null`, the function returns `null`.
+
+`precision`::
+Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [1 and 12](https://en.wikipedia.org/wiki/Geohash).
+
+`bounds`::
+Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geohash_to_long.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input geohash grid-id. The input can be a single- or multi-valued column or an expression.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geohash_to_string.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input geohash grid-id. The input can be a single- or multi-valued column or an expression.

+ 12 - 0
docs/reference/esql/functions/parameters/st_geohex.asciidoc

@@ -0,0 +1,12 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`geometry`::
+Expression of type `geo_point`. If `null`, the function returns `null`.
+
+`precision`::
+Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 15](https://h3geo.org/docs/core-library/restable/).
+
+`bounds`::
+Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geohex_to_long.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input geohex grid-id. The input can be a single- or multi-valued column or an expression.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geohex_to_string.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input Geohex grid-id. The input can be a single- or multi-valued column or an expression.

+ 12 - 0
docs/reference/esql/functions/parameters/st_geotile.asciidoc

@@ -0,0 +1,12 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`geometry`::
+Expression of type `geo_point`. If `null`, the function returns `null`.
+
+`precision`::
+Expression of type `integer`. If `null`, the function returns `null`. Valid values are between [0 and 29](https://wiki.openstreetmap.org/wiki/Zoom_levels).
+
+`bounds`::
+Optional bounds to filter the grid tiles, a `geo_shape` of type `BBOX`. Use [`ST_ENVELOPE`](#esql-st_envelope) if the `geo_shape` is of any other type.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geotile_to_long.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input geotile grid-id. The input can be a single- or multi-valued column or an expression.

+ 6 - 0
docs/reference/esql/functions/parameters/st_geotile_to_string.asciidoc

@@ -0,0 +1,6 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Parameters*
+
+`grid_id`::
+Input geotile grid-id. The input can be a single- or multi-valued column or an expression.

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="420" height="46" viewbox="0 0 420 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 31h5m80 0h10m32 0h10m32 0h10m32 0h10m152 0h10m32 0h5"/><rect class="s" x="5" y="5" width="80" height="36"/><text class="k" x="15" y="31">SCALB</text><rect class="s" x="95" y="5" width="32" height="36" rx="7"/><text class="syn" x="105" y="31">(</text><rect class="s" x="137" y="5" width="32" height="36" rx="7"/><text class="k" x="147" y="31">d</text><rect class="s" x="179" y="5" width="32" height="36" rx="7"/><text class="syn" x="189" y="31">,</text><rect class="s" x="221" y="5" width="152" height="36" rx="7"/><text class="k" x="231" y="31">scaleFactor</text><rect class="s" x="383" y="5" width="32" height="36" rx="7"/><text class="syn" x="393" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="684" height="46" viewbox="0 0 684 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 0h10m116 0h10m32 0h10m128 0h10m32 0h10m92 0h10m32 0h5"/><rect class="s" x="5" y="5" width="140" height="36"/><text class="k" x="15" y="31">ST_GEOHASH</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="116" height="36" rx="7"/><text class="k" x="207" y="31">geometry</text><rect class="s" x="323" y="5" width="32" height="36" rx="7"/><text class="syn" x="333" y="31">,</text><rect class="s" x="365" y="5" width="128" height="36" rx="7"/><text class="k" x="375" y="31">precision</text><rect class="s" x="503" y="5" width="32" height="36" rx="7"/><text class="syn" x="513" y="31">,</text><rect class="s" x="545" y="5" width="92" height="36" rx="7"/><text class="k" x="555" y="31">bounds</text><rect class="s" x="647" y="5" width="32" height="36" rx="7"/><text class="syn" x="657" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="444" height="46" viewbox="0 0 444 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 31h5m236 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="236" height="36"/><text class="k" x="15" y="31">ST_GEOHASH_TO_LONG</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="104" height="36" rx="7"/><text class="k" x="303" y="31">grid_id</text><rect class="s" x="407" y="5" width="32" height="36" rx="7"/><text class="syn" x="417" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="468" height="46" viewbox="0 0 468 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 31h5m260 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="260" height="36"/><text class="k" x="15" y="31">ST_GEOHASH_TO_STRING</text><rect class="s" x="275" y="5" width="32" height="36" rx="7"/><text class="syn" x="285" y="31">(</text><rect class="s" x="317" y="5" width="104" height="36" rx="7"/><text class="k" x="327" y="31">grid_id</text><rect class="s" x="431" y="5" width="32" height="36" rx="7"/><text class="syn" x="441" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="672" height="46" viewbox="0 0 672 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 31h5m128 0h10m32 0h10m116 0h10m32 0h10m128 0h10m32 0h10m92 0h10m32 0h5"/><rect class="s" x="5" y="5" width="128" height="36"/><text class="k" x="15" y="31">ST_GEOHEX</text><rect class="s" x="143" y="5" width="32" height="36" rx="7"/><text class="syn" x="153" y="31">(</text><rect class="s" x="185" y="5" width="116" height="36" rx="7"/><text class="k" x="195" y="31">geometry</text><rect class="s" x="311" y="5" width="32" height="36" rx="7"/><text class="syn" x="321" y="31">,</text><rect class="s" x="353" y="5" width="128" height="36" rx="7"/><text class="k" x="363" y="31">precision</text><rect class="s" x="491" y="5" width="32" height="36" rx="7"/><text class="syn" x="501" y="31">,</text><rect class="s" x="533" y="5" width="92" height="36" rx="7"/><text class="k" x="543" y="31">bounds</text><rect class="s" x="635" y="5" width="32" height="36" rx="7"/><text class="syn" x="645" y="31">)</text></svg>

+ 1 - 0
docs/reference/esql/functions/signature/st_geohex_to_long.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 31h5m224 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="224" height="36"/><text class="k" x="15" y="31">ST_GEOHEX_TO_LONG</text><rect class="s" x="239" y="5" width="32" height="36" rx="7"/><text class="syn" x="249" y="31">(</text><rect class="s" x="281" y="5" width="104" height="36" rx="7"/><text class="k" x="291" y="31">grid_id</text><rect class="s" x="395" y="5" width="32" height="36" rx="7"/><text class="syn" x="405" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="456" height="46" viewbox="0 0 456 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 31h5m248 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="248" height="36"/><text class="k" x="15" y="31">ST_GEOHEX_TO_STRING</text><rect class="s" x="263" y="5" width="32" height="36" rx="7"/><text class="syn" x="273" y="31">(</text><rect class="s" x="305" y="5" width="104" height="36" rx="7"/><text class="k" x="315" y="31">grid_id</text><rect class="s" x="419" y="5" width="32" height="36" rx="7"/><text class="syn" x="429" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="684" height="46" viewbox="0 0 684 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 0h10m116 0h10m32 0h10m128 0h10m32 0h10m92 0h10m32 0h5"/><rect class="s" x="5" y="5" width="140" height="36"/><text class="k" x="15" y="31">ST_GEOTILE</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="116" height="36" rx="7"/><text class="k" x="207" y="31">geometry</text><rect class="s" x="323" y="5" width="32" height="36" rx="7"/><text class="syn" x="333" y="31">,</text><rect class="s" x="365" y="5" width="128" height="36" rx="7"/><text class="k" x="375" y="31">precision</text><rect class="s" x="503" y="5" width="32" height="36" rx="7"/><text class="syn" x="513" y="31">,</text><rect class="s" x="545" y="5" width="92" height="36" rx="7"/><text class="k" x="555" y="31">bounds</text><rect class="s" x="647" y="5" width="32" height="36" rx="7"/><text class="syn" x="657" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="444" height="46" viewbox="0 0 444 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 31h5m236 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="236" height="36"/><text class="k" x="15" y="31">ST_GEOTILE_TO_LONG</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="104" height="36" rx="7"/><text class="k" x="303" y="31">grid_id</text><rect class="s" x="407" y="5" width="32" height="36" rx="7"/><text class="syn" x="417" y="31">)</text></svg>

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

@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="468" height="46" viewbox="0 0 468 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 31h5m260 0h10m32 0h10m104 0h10m32 0h5"/><rect class="s" x="5" y="5" width="260" height="36"/><text class="k" x="15" y="31">ST_GEOTILE_TO_STRING</text><rect class="s" x="275" y="5" width="32" height="36" rx="7"/><text class="syn" x="285" y="31">(</text><rect class="s" x="317" y="5" width="104" height="36" rx="7"/><text class="k" x="327" y="31">grid_id</text><rect class="s" x="431" y="5" width="32" height="36" rx="7"/><text class="syn" x="441" y="31">)</text></svg>

+ 18 - 0
docs/reference/esql/functions/spatial-functions.asciidoc

@@ -20,6 +20,15 @@
 * experimental:[] <<esql-st_xmin>>
 * experimental:[] <<esql-st_ymax>>
 * experimental:[] <<esql-st_ymin>>
+* experimental:[] <<esql-st_geohash>>
+* experimental:[] <<esql-st_geohash_to_long>>
+* experimental:[] <<esql-st_geohash_to_string>>
+* experimental:[] <<esql-st_geotile>>
+* experimental:[] <<esql-st_geotile_to_long>>
+* experimental:[] <<esql-st_geotile_to_string>>
+* experimental:[] <<esql-st_geohex>>
+* experimental:[] <<esql-st_geohex_to_long>>
+* experimental:[] <<esql-st_geohex_to_string>>
 // end::spatial_list[]
 
 include::layout/st_distance.asciidoc[]
@@ -34,3 +43,12 @@ include::layout/st_xmax.asciidoc[]
 include::layout/st_xmin.asciidoc[]
 include::layout/st_ymax.asciidoc[]
 include::layout/st_ymin.asciidoc[]
+include::layout/st_geohash.asciidoc[]
+include::layout/st_geohash_to_long.asciidoc[]
+include::layout/st_geohash_to_string.asciidoc[]
+include::layout/st_geotile.asciidoc[]
+include::layout/st_geotile_to_long.asciidoc[]
+include::layout/st_geotile_to_string.asciidoc[]
+include::layout/st_geohex.asciidoc[]
+include::layout/st_geohex_to_long.asciidoc[]
+include::layout/st_geohex_to_string.asciidoc[]

+ 16 - 0
docs/reference/esql/functions/types/scalb.asciidoc

@@ -0,0 +1,16 @@
+// 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=|]
+|===
+d | scaleFactor | result
+double | integer | double
+double | long | double
+integer | integer | double
+integer | long | double
+long | integer | double
+long | long | double
+unsigned_long | integer | double
+unsigned_long | long | double
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohash.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=|]
+|===
+geometry | precision | bounds | result
+geo_point | integer | geo_shape | long
+geo_point | integer | | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohash_to_long.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=|]
+|===
+grid_id | result
+keyword | long
+long | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohash_to_string.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=|]
+|===
+grid_id | result
+keyword | keyword
+long | keyword
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohex.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=|]
+|===
+geometry | precision | bounds | result
+geo_point | integer | geo_shape | long
+geo_point | integer | | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohex_to_long.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=|]
+|===
+grid_id | result
+keyword | long
+long | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geohex_to_string.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=|]
+|===
+grid_id | result
+keyword | keyword
+long | keyword
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geotile.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=|]
+|===
+geometry | precision | bounds | result
+geo_point | integer | geo_shape | long
+geo_point | integer | | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geotile_to_long.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=|]
+|===
+grid_id | result
+keyword | long
+long | long
+|===

+ 10 - 0
docs/reference/esql/functions/types/st_geotile_to_string.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=|]
+|===
+grid_id | result
+keyword | keyword
+long | keyword
+|===

+ 0 - 23
docs/reference/query-languages/esql/_snippets/functions/layout/round_to.md

@@ -1,23 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-## `ROUND_TO` [esql-round_to]
-
-**Syntax**
-
-:::{image} ../../../images/functions/round_to.svg
-:alt: Embedded
-:class: text-center
-:::
-
-
-:::{include} ../parameters/round_to.md
-:::
-
-:::{include} ../description/round_to.md
-:::
-
-:::{include} ../types/round_to.md
-:::
-
-:::{include} ../examples/round_to.md
-:::

+ 0 - 23
docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md

@@ -1,23 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-## `SCALB` [esql-scalb]
-
-**Syntax**
-
-:::{image} ../../../images/functions/scalb.svg
-:alt: Embedded
-:class: text-center
-:::
-
-
-:::{include} ../parameters/scalb.md
-:::
-
-:::{include} ../description/scalb.md
-:::
-
-:::{include} ../types/scalb.md
-:::
-
-:::{include} ../examples/scalb.md
-:::

+ 0 - 10
docs/reference/query-languages/esql/_snippets/functions/parameters/round_to.md

@@ -1,10 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Parameters**
-
-`field`
-:   The numeric value to round. If `null`, the function returns `null`.
-
-`points`
-:   Remaining rounding points. Must be constants.
-

+ 0 - 10
docs/reference/query-languages/esql/_snippets/functions/parameters/scalb.md

@@ -1,10 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Parameters**
-
-`d`
-:   Numeric expression for the multiplier. If `null`, the function returns `null`.
-
-`scaleFactor`
-:   Numeric expression for the scale factor. If `null`, the function returns `null`.
-

+ 0 - 18
docs/reference/query-languages/esql/_snippets/functions/types/round_to.md

@@ -1,18 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Supported types**
-
-| field | points | result |
-| --- | --- | --- |
-| date | date | date |
-| date_nanos | date_nanos | date_nanos |
-| 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 |
-

+ 0 - 15
docs/reference/query-languages/esql/_snippets/functions/types/scalb.md

@@ -1,15 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Supported types**
-
-| d | scaleFactor | result |
-| --- | --- | --- |
-| double | integer | double |
-| double | long | double |
-| integer | integer | double |
-| integer | long | double |
-| long | integer | double |
-| long | long | double |
-| unsigned_long | integer | double |
-| unsigned_long | long | double |
-

+ 0 - 1
docs/reference/query-languages/esql/images/functions/round_to.svg

@@ -1 +0,0 @@
-<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="484" height="61" viewbox="0 0 484 61"><defs><style type="text/css">.c{fill:none;stroke:#222222;}.k{fill:#000000;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}.s{fill:#e4f4ff;stroke:#222222;}.syn{fill:#8D8D8D;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}</style></defs><path class="c" d="M0 46h5m116 0h10m32 0h10m80 0h30m-5 0q-5 0-5-5v-26q0-5 5-5h144q5 0 5 5v26q0 5-5 5m-107 0h10m92 0h30m32 0h5"/><rect class="s" x="5" y="20" width="116" height="36"/><text class="k" x="15" y="46">ROUND_TO</text><rect class="s" x="131" y="20" width="32" height="36" rx="7"/><text class="syn" x="141" y="46">(</text><rect class="s" x="173" y="20" width="80" height="36" rx="7"/><text class="k" x="183" y="46">field</text><rect class="s" x="283" y="20" width="32" height="36" rx="7"/><text class="syn" x="293" y="46">,</text><rect class="s" x="325" y="20" width="92" height="36" rx="7"/><text class="k" x="335" y="46">points</text><rect class="s" x="447" y="20" width="32" height="36" rx="7"/><text class="syn" x="457" y="46">)</text></svg>

+ 0 - 1
docs/reference/query-languages/esql/images/functions/scalb.svg

@@ -1 +0,0 @@
-<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="420" height="46" viewbox="0 0 420 46"><defs><style type="text/css">.c{fill:none;stroke:#222222;}.k{fill:#000000;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}.s{fill:#e4f4ff;stroke:#222222;}.syn{fill:#8D8D8D;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}</style></defs><path class="c" d="M0 31h5m80 0h10m32 0h10m32 0h10m32 0h10m152 0h10m32 0h5"/><rect class="s" x="5" y="5" width="80" height="36"/><text class="k" x="15" y="31">SCALB</text><rect class="s" x="95" y="5" width="32" height="36" rx="7"/><text class="syn" x="105" y="31">(</text><rect class="s" x="137" y="5" width="32" height="36" rx="7"/><text class="k" x="147" y="31">d</text><rect class="s" x="179" y="5" width="32" height="36" rx="7"/><text class="syn" x="189" y="31">,</text><rect class="s" x="221" y="5" width="152" height="36" rx="7"/><text class="k" x="231" y="31">scaleFactor</text><rect class="s" x="383" y="5" width="32" height="36" rx="7"/><text class="syn" x="393" y="31">)</text></svg>

+ 6 - 0
x-pack/plugin/esql/build.gradle

@@ -33,6 +33,8 @@ dependencies {
   implementation project('compute:ann')
   implementation project(':libs:dissect')
   implementation project(':libs:grok')
+  api "org.apache.lucene:lucene-spatial3d:${versions.lucene}"
+  api project(":libs:h3")
   implementation project('arrow')
 
   // Also contains a dummy processor to allow compilation with unused annotations.
@@ -62,6 +64,10 @@ dependencies {
   internalClusterTestImplementation project(":modules:mapper-extras")
 }
 
+tasks.named("dependencyLicenses").configure {
+  mapping from: /lucene-.*/, to: 'lucene'
+}
+
 def generatedPath = "src/main/generated"
 def projectDirectory = project.layout.projectDirectory
 def generatedSourceDir = projectDirectory.dir(generatedPath)

+ 475 - 0
x-pack/plugin/esql/licenses/lucene-LICENSE.txt

@@ -0,0 +1,475 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
+derived from unicode conversion examples available at
+http://www.unicode.org/Public/PROGRAMS/CVTUTF.  Here is the copyright
+from those sources:
+
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ * 
+ * Disclaimer
+ * 
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ * 
+ * Limitations on Rights to Redistribute This Code
+ * 
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+
+Some code in core/src/java/org/apache/lucene/util/ArrayUtil.java was
+derived from Python 2.4.2 sources available at
+http://www.python.org. Full license is here:
+
+  http://www.python.org/download/releases/2.4.2/license/
+
+Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
+derived from Python 3.1.2 sources available at
+http://www.python.org. Full license is here:
+
+  http://www.python.org/download/releases/3.1.2/license/
+
+Some code in core/src/java/org/apache/lucene/util/automaton was
+derived from Brics automaton sources available at
+www.brics.dk/automaton/. Here is the copyright from those sources:
+
+/*
+ * Copyright (c) 2001-2009 Anders Moeller
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+The levenshtein automata tables in core/src/java/org/apache/lucene/util/automaton 
+were automatically generated with the moman/finenight FSA package.
+Here is the copyright for those sources:
+
+# Copyright (c) 2010, Jean-Philippe Barrette-LaPierre, <jpb@rrette.com>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
+derived from ICU (http://www.icu-project.org)
+The full license is available here: 
+  http://source.icu-project.org/repos/icu/icu/trunk/license.html
+
+/*
+ * Copyright (C) 1999-2010, International Business Machines
+ * Corporation and others.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights 
+ * to use, copy, modify, merge, publish, distribute, and/or sell copies of the 
+ * Software, and to permit persons to whom the Software is furnished to do so, 
+ * provided that the above copyright notice(s) and this permission notice appear 
+ * in all copies of the Software and that both the above copyright notice(s) and
+ * this permission notice appear in supporting documentation.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE 
+ * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR 
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall not 
+ * be used in advertising or otherwise to promote the sale, use or other 
+ * dealings in this Software without prior written authorization of the 
+ * copyright holder.
+ */
+ 
+The following license applies to the Snowball stemmers:
+
+Copyright (c) 2001, Dr Martin Porter
+Copyright (c) 2002, Richard Boulton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    * notice, this list of conditions and the following disclaimer in the
+    * documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holders nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The following license applies to the KStemmer:
+
+Copyright © 2003,
+Center for Intelligent Information Retrieval,
+University of Massachusetts, Amherst.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. The names "Center for Intelligent Information Retrieval" and
+"University of Massachusetts" must not be used to endorse or promote products
+derived from this software without prior written permission. To obtain
+permission, contact info@ciir.cs.umass.edu.
+
+THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF MASSACHUSETTS AND OTHER CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The following license applies to the Morfologik project:
+
+Copyright (c) 2006 Dawid Weiss
+Copyright (c) 2007-2011 Dawid Weiss, Marcin Miłkowski
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+    this list of conditions and the following disclaimer.
+    
+    * Redistributions in binary form must reproduce the above copyright notice, 
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+    
+    * Neither the name of Morfologik nor the names of its contributors 
+    may be used to endorse or promote products derived from this software 
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---
+
+The dictionary comes from Morfologik project. Morfologik uses data from 
+Polish ispell/myspell dictionary hosted at http://www.sjp.pl/slownik/en/ and 
+is licenced on the terms of (inter alia) LGPL and Creative Commons 
+ShareAlike. The part-of-speech tags were added in Morfologik project and
+are not found in the data from sjp.pl. The tagset is similar to IPI PAN
+tagset.
+
+---
+
+The following license applies to the Morfeusz project,
+used by org.apache.lucene.analysis.morfologik.
+
+BSD-licensed dictionary of Polish (SGJP)
+http://sgjp.pl/morfeusz/
+
+Copyright © 2011 Zygmunt Saloni, Włodzimierz Gruszczyński, 
+             Marcin Woliński, Robert Wołosz
+
+All rights reserved.
+
+Redistribution and  use in  source and binary  forms, with  or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS “AS IS” AND ANY EXPRESS
+OR  IMPLIED WARRANTIES,  INCLUDING, BUT  NOT LIMITED  TO,  THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.  IN NO EVENT  SHALL COPYRIGHT  HOLDERS OR  CONTRIBUTORS BE
+LIABLE FOR  ANY DIRECT,  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES  (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF
+SUBSTITUTE  GOODS OR  SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON ANY THEORY OF LIABILITY,
+WHETHER IN  CONTRACT, STRICT LIABILITY, OR  TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 192 - 0
x-pack/plugin/esql/licenses/lucene-NOTICE.txt

@@ -0,0 +1,192 @@
+Apache Lucene
+Copyright 2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Includes software from other Apache Software Foundation projects,
+including, but not limited to:
+ - Apache Ant
+ - Apache Jakarta Regexp
+ - Apache Commons
+ - Apache Xerces
+
+ICU4J, (under analysis/icu) is licensed under an MIT styles license
+and Copyright (c) 1995-2008 International Business Machines Corporation and others
+
+Some data files (under analysis/icu/src/data) are derived from Unicode data such
+as the Unicode Character Database. See http://unicode.org/copyright.html for more
+details.
+
+Brics Automaton (under core/src/java/org/apache/lucene/util/automaton) is 
+BSD-licensed, created by Anders Møller. See http://www.brics.dk/automaton/
+
+The levenshtein automata tables (under core/src/java/org/apache/lucene/util/automaton) were
+automatically generated with the moman/finenight FSA library, created by
+Jean-Philippe Barrette-LaPierre. This library is available under an MIT license,
+see http://sites.google.com/site/rrettesite/moman and 
+http://bitbucket.org/jpbarrette/moman/overview/
+
+The class org.apache.lucene.util.WeakIdentityMap was derived from
+the Apache CXF project and is Apache License 2.0.
+
+The Google Code Prettify is Apache License 2.0.
+See http://code.google.com/p/google-code-prettify/
+
+JUnit (junit-4.10) is licensed under the Common Public License v. 1.0
+See http://junit.sourceforge.net/cpl-v10.html
+
+This product includes code (JaspellTernarySearchTrie) from Java Spelling Checkin
+g Package (jaspell): http://jaspell.sourceforge.net/
+License: The BSD License (http://www.opensource.org/licenses/bsd-license.php)
+
+The snowball stemmers in
+  analysis/common/src/java/net/sf/snowball
+were developed by Martin Porter and Richard Boulton.
+The snowball stopword lists in
+  analysis/common/src/resources/org/apache/lucene/analysis/snowball
+were developed by Martin Porter and Richard Boulton.
+The full snowball package is available from
+  http://snowball.tartarus.org/
+
+The KStem stemmer in
+  analysis/common/src/org/apache/lucene/analysis/en
+was developed by Bob Krovetz and Sergio Guzman-Lara (CIIR-UMass Amherst)
+under the BSD-license.
+
+The Arabic,Persian,Romanian,Bulgarian, Hindi and Bengali analyzers (common) come with a default
+stopword list that is BSD-licensed created by Jacques Savoy.  These files reside in:
+analysis/common/src/resources/org/apache/lucene/analysis/ar/stopwords.txt,
+analysis/common/src/resources/org/apache/lucene/analysis/fa/stopwords.txt,
+analysis/common/src/resources/org/apache/lucene/analysis/ro/stopwords.txt,
+analysis/common/src/resources/org/apache/lucene/analysis/bg/stopwords.txt,
+analysis/common/src/resources/org/apache/lucene/analysis/hi/stopwords.txt,
+analysis/common/src/resources/org/apache/lucene/analysis/bn/stopwords.txt
+See http://members.unine.ch/jacques.savoy/clef/index.html.
+
+The German,Spanish,Finnish,French,Hungarian,Italian,Portuguese,Russian and Swedish light stemmers
+(common) are based on BSD-licensed reference implementations created by Jacques Savoy and
+Ljiljana Dolamic. These files reside in:
+analysis/common/src/java/org/apache/lucene/analysis/de/GermanLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/de/GermanMinimalStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/es/SpanishLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/fi/FinnishLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/fr/FrenchLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/fr/FrenchMinimalStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/hu/HungarianLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/it/ItalianLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/pt/PortugueseLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLightStemmer.java
+analysis/common/src/java/org/apache/lucene/analysis/sv/SwedishLightStemmer.java
+
+The Stempel analyzer (stempel) includes BSD-licensed software developed 
+by the Egothor project http://egothor.sf.net/, created by Leo Galambos, Martin Kvapil,
+and Edmond Nolan.
+
+The Polish analyzer (stempel) comes with a default
+stopword list that is BSD-licensed created by the Carrot2 project. The file resides
+in stempel/src/resources/org/apache/lucene/analysis/pl/stopwords.txt.
+See http://project.carrot2.org/license.html.
+
+The SmartChineseAnalyzer source code (smartcn) was
+provided by Xiaoping Gao and copyright 2009 by www.imdict.net.
+
+WordBreakTestUnicode_*.java (under modules/analysis/common/src/test/) 
+is derived from Unicode data such as the Unicode Character Database. 
+See http://unicode.org/copyright.html for more details.
+
+The Morfologik analyzer (morfologik) includes BSD-licensed software
+developed by Dawid Weiss and Marcin Miłkowski (http://morfologik.blogspot.com/).
+
+Morfologik uses data from Polish ispell/myspell dictionary
+(http://www.sjp.pl/slownik/en/) licenced on the terms of (inter alia)
+LGPL and Creative Commons ShareAlike.
+
+Morfologic includes data from BSD-licensed dictionary of Polish (SGJP)
+(http://sgjp.pl/morfeusz/)
+
+Servlet-api.jar and javax.servlet-*.jar are under the CDDL license, the original
+source code for this can be found at http://www.eclipse.org/jetty/downloads.php
+
+===========================================================================
+Kuromoji Japanese Morphological Analyzer - Apache Lucene Integration
+===========================================================================
+
+This software includes a binary and/or source version of data from
+
+  mecab-ipadic-2.7.0-20070801
+
+which can be obtained from
+
+  http://atilika.com/releases/mecab-ipadic/mecab-ipadic-2.7.0-20070801.tar.gz
+
+or
+
+  http://jaist.dl.sourceforge.net/project/mecab/mecab-ipadic/2.7.0-20070801/mecab-ipadic-2.7.0-20070801.tar.gz
+
+===========================================================================
+mecab-ipadic-2.7.0-20070801 Notice
+===========================================================================
+
+Nara Institute of Science and Technology (NAIST),
+the copyright holders, disclaims all warranties with regard to this
+software, including all implied warranties of merchantability and
+fitness, in no event shall NAIST be liable for
+any special, indirect or consequential damages or any damages
+whatsoever resulting from loss of use, data or profits, whether in an
+action of contract, negligence or other tortuous action, arising out
+of or in connection with the use or performance of this software.
+
+A large portion of the dictionary entries
+originate from ICOT Free Software.  The following conditions for ICOT
+Free Software applies to the current dictionary as well.
+
+Each User may also freely distribute the Program, whether in its
+original form or modified, to any third party or parties, PROVIDED
+that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear
+on, or be attached to, the Program, which is distributed substantially
+in the same form as set out herein and that such intended
+distribution, if actually made, will neither violate or otherwise
+contravene any of the laws and regulations of the countries having
+jurisdiction over the User or the intended distribution itself.
+
+NO WARRANTY
+
+The program was produced on an experimental basis in the course of the
+research and development conducted during the project and is provided
+to users as so produced on an experimental basis.  Accordingly, the
+program is provided without any warranty whatsoever, whether express,
+implied, statutory or otherwise.  The term "warranty" used herein
+includes, but is not limited to, any warranty of the quality,
+performance, merchantability and fitness for a particular purpose of
+the program and the nonexistence of any infringement or violation of
+any right of any third party.
+
+Each user of the program will agree and understand, and be deemed to
+have agreed and understood, that there is no warranty whatsoever for
+the program and, accordingly, the entire risk arising from or
+otherwise connected with the program is assumed by the user.
+
+Therefore, neither ICOT, the copyright holder, or any other
+organization that participated in or was otherwise related to the
+development of the program and their respective officials, directors,
+officers and other employees shall be held liable for any and all
+damages, including, without limitation, general, special, incidental
+and consequential damages, arising out of or otherwise in connection
+with the use or inability to use the program or any product, material
+or result produced or otherwise obtained by using the program,
+regardless of whether they have been advised of, or otherwise had
+knowledge of, the possibility of such damages at any time during the
+project or thereafter.  Each user will be deemed to have agreed to the
+foregoing by his or her commencement of use of the program.  The term
+"use" as used herein includes, but is not limited to, the use,
+modification, copying and distribution of the program and the
+production of secondary products from the program.
+
+In the case where the program, whether in its original form or
+modified, was distributed or delivered to or received by a user from
+any person, organization or entity other than ICOT, unless it makes or
+grants independently of ICOT any specific warranty to the user in
+writing, such person, organization or entity, will also be exempted
+from and not be held liable to the user for any such damages as noted
+above as far as the program is concerned.

+ 1 - 1
x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java

@@ -327,7 +327,7 @@ public final class CsvAssert {
         if (values.size() > rows) {
             result.append("...").append(System.lineSeparator());
         }
-        return result.toString();
+        return result.toString().replaceAll("\\s+" + System.lineSeparator(), System.lineSeparator());
     }
 
     private static String header(String name, Type type) {

+ 884 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/resources/spatial-grid.csv-spec

@@ -0,0 +1,884 @@
+###############################################
+# Tests for geo_grid function: ST_GEOHASH
+###############################################
+
+geohashStringToLong
+required_capability: spatial_grid
+
+// tag::geohash_to_long[]
+ROW geohash = "u3bu"
+| EVAL geohashLong = ST_GEOHASH_TO_LONG(geohash)
+// end::geohash_to_long[]
+;
+
+// tag::geohash_to_long-result[]
+geohash:keyword | geohashLong:long
+u3bu            | 13686180
+// end::geohash_to_long-result[]
+;
+
+geohashLongToString
+required_capability: spatial_grid
+
+// tag::geohash_to_string[]
+ROW geohash = TO_LONG(13686180)
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+// end::geohash_to_string[]
+;
+
+// tag::geohash_to_string-result[]
+geohash:long | geohashString:keyword
+13686180     | u3bu
+// end::geohash_to_string-result[]
+;
+
+geohashLiteral
+required_capability: spatial_grid
+
+// tag::st_geohash-literal[]
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geohash4 = ST_GEOHASH(location, 4),
+       geohash3 = ST_GEOHASH(location, 3),
+       geohash2 = ST_GEOHASH(location, 2),
+       geohash1 = ST_GEOHASH(location, 1)
+// end::st_geohash-literal[]
+;
+
+// tag::st_geohash-literal-result[]
+location:geo_point                        | geohash4:long | geohash3:long | geohash2:long | geohash1:long
+POINT (12.6493508684508 55.6285017221528) | 13686180      | 427683        | 13362         | 417
+// end::st_geohash-literal-result[]
+;
+
+geohashLiteralString
+required_capability: spatial_grid
+
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geohash4 = ST_GEOHASH_TO_STRING(ST_GEOHASH(location, 4)),
+       geohash3 = ST_GEOHASH_TO_STRING(ST_GEOHASH(location, 3)),
+       geohash2 = ST_GEOHASH_TO_STRING(ST_GEOHASH(location, 2)),
+       geohash1 = ST_GEOHASH_TO_STRING(ST_GEOHASH(location, 1))
+;
+
+location:geo_point | geohash4:keyword | geohash3:keyword | geohash2:keyword | geohash1:keyword
+POINT(12.6493508684508 55.6285017221528) | u3bu | u3b | u3 | u
+;
+
+geohashField
+required_capability: spatial_grid
+
+FROM airports
+| WHERE abbrev == "CPH"
+| EVAL geohash = ST_GEOHASH(location, 7)
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP geohash, geohashString, abbrev, name, location
+;
+
+geohash:long | geohashString:keyword | abbrev:keyword | name:text  | location:geo_point
+448469007591 | u3buryf               | CPH            | Copenhagen | POINT (12.6493508684508 55.6285017221528)
+;
+
+gridGeohashStatsBy
+required_capability: spatial_grid
+
+// tag::st_geohash-grid[]
+FROM airports
+| EVAL geohash = ST_GEOHASH(location, 1)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| WHERE count >= 10
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+// end::st_geohash-grid[]
+;
+
+// tag::st_geohash-grid-result[]
+count:long | centroid:geo_point                             | geohashString:keyword
+118        | POINT (-77.41857436454018 26.96522968734409)   | d
+96         | POINT (23.181679135886952 27.295384635654045)  | s
+94         | POINT (70.94076107503807 25.691916451026547)   | t
+90         | POINT (-104.3941700803116 30.811849871650338)  | 9
+89         | POINT (18.71573683606942 53.165169130707305)   | u
+85         | POINT (114.3722876966657 24.908398092505248)   | w
+51         | POINT (-61.44522591713159 -22.87209844956284)  | 6
+38         | POINT (-9.429514887252529 25.497624435045413)  | e
+34         | POINT (-111.8071846965262 52.464381378993174)  | c
+30         | POINT (28.7045472683385 -14.706001980230212)   | k
+28         | POINT (159.52750137208827 -25.555616633001982) | r
+22         | POINT (-4.410395708612421 54.90304926367985)   | g
+21         | POINT (-69.40534970590046 50.93379438189523)   | f
+17         | POINT (114.05526293222519 -10.898114638950895) | q
+16         | POINT (147.40052131412085 21.054660080408212)  | x
+13         | POINT (63.64716878519035 54.37333276101317)    | v
+12         | POINT (-39.53510569408536 -11.72166372067295)  | 7
+// end::st_geohash-grid-result[]
+;
+
+gridGeohashQuery
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_GEOHASH(location, 1) == ST_GEOHASH_TO_LONG("7")
+| EVAL geohash = ST_GEOHASH(location, 2)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+;
+
+count:long | centroid:geo_point                             | geohashString:keyword
+4          | POINT (-35.22712387377396 -7.672965489327908)  | 7n
+3          | POINT (-41.86607404612005 -3.8085224060341716) | 7p
+2          | POINT (-42.66381660941988 -22.868987743277103) | 75
+2          | POINT (-42.12605922482908 -19.945099228061736) | 7h
+1          | POINT (-38.3347990270704 -12.91436152998358)   | 7j
+;
+
+gridGeohashStatsByBounds
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geohash = ST_GEOHASH(location, 2, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| WHERE geohash IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+;
+
+count:long | centroid:geo_point                            | geohashString:keyword
+19         | POINT (6.360728044651057 47.94084087577894)   | u0
+10         | POINT (15.350638423115015 47.80751353036612)  | u2
+9          | POINT (18.5217544157058 42.1394603792578)     | sr
+8          | POINT (6.351574736181647 51.8981519783847)    | u1
+7          | POINT (5.268637698941997 42.747250193330856)  | sp
+7          | POINT (17.092350951528974 53.365471504096476) | u3
+5          | POINT (16.2651440910995 58.812188878655434)   | u6
+4          | POINT (7.7012718468904495 36.39783004182391)  | sn
+3          | POINT (14.222751930356026 37.168446206487715) | sq
+3          | POINT (7.318722177296877 59.788265260867774)  | u4
+2          | POINT (16.706149326637387 32.37822346854955)  | sm
+;
+
+gridGeohashStatsByBoundsEnvelope
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geohash = ST_GEOHASH(location, 2, ST_ENVELOPE(TO_GEOSHAPE("POLYGON((0.0 30.0, 12.0 30.0, 12.0 60.0, 0.0 60.0, 0.0 30.0))")))
+| WHERE geohash IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+;
+
+count:long | centroid:geo_point                            | geohashString:keyword
+19         | POINT (6.360728044651057 47.94084087577894)   | u0
+10         | POINT (15.350638423115015 47.80751353036612)  | u2
+9          | POINT (18.5217544157058 42.1394603792578)     | sr
+8          | POINT (6.351574736181647 51.8981519783847)    | u1
+7          | POINT (5.268637698941997 42.747250193330856)  | sp
+7          | POINT (17.092350951528974 53.365471504096476) | u3
+5          | POINT (16.2651440910995 58.812188878655434)   | u6
+4          | POINT (7.7012718468904495 36.39783004182391)  | sn
+3          | POINT (14.222751930356026 37.168446206487715) | sq
+3          | POINT (7.318722177296877 59.788265260867774)  | u4
+2          | POINT (16.706149326637387 32.37822346854955)  | sm
+;
+
+gridGeohashStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geohash = ST_GEOHASH(location, 2)
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC
+;
+
+count:long | centroid:geo_point                            | geohashString:keyword
+14         | POINT (-2.5644131543646966 53.38093495994274) | gc
+3          | POINT (-2.7510103583335876 58.79020635969937) | gf
+;
+
+gridGeohashStatsByBoundsUK
+required_capability: spatial_grid
+
+FROM airports
+| EVAL bounds = ST_ENVELOPE(TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geohash = ST_GEOHASH(location, 2, bounds)
+| WHERE geohash IS NOT NULL
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohash
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+| KEEP count, centroid, geohashString
+| SORT count DESC, geohashString ASC
+;
+
+count:long | centroid:geo_point                            | geohashString:keyword
+19         | POINT (6.360728044651057 47.94084087577894)   | u0
+17         | POINT (-3.5034258844440473 53.25306422789307) | gc
+8          | POINT (6.351574736181647 51.8981519783847)    | u1
+3          | POINT (-2.7510103583335876 58.79020635969937) | gf
+3          | POINT (7.318722177296877 59.788265260867774)  | u4
+;
+
+gridGeohashInStatsBy
+required_capability: spatial_grid
+
+FROM airports
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOHASH(location, 1)
+| SORT count DESC
+| KEEP count, centroid
+| LIMIT 10
+;
+
+count:long | centroid:geo_point
+ 118        | POINT (-77.41857436454018 26.96522968734409)
+ 96         | POINT (23.181679135886952 27.295384635654045)
+ 94         | POINT (70.94076107503807 25.691916451026547)
+ 90         | POINT (-104.3941700803116 30.811849871650338)
+ 89         | POINT (18.71573683606942 53.165169130707305)
+ 85         | POINT (114.3722876966657 24.908398092505248)
+ 51         | POINT (-61.44522591713159 -22.87209844956284)
+ 38         | POINT (-9.429514887252529 25.497624435045413)
+ 34         | POINT (-111.8071846965262 52.464381378993174)
+ 30         | POINT (28.7045472683385 -14.706001980230212)
+;
+
+gridGeohashInStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOHASH(location, 2)
+| KEEP count, centroid
+| SORT count DESC
+;
+
+count:long | centroid:geo_point
+14         | POINT (-2.5644131543646966 53.38093495994274)
+3          | POINT (-2.7510103583335876 58.79020635969937)
+;
+
+###############################################
+# Tests for geo_grid function: ST_GEOTILE
+###############################################
+
+geotileStringToLong
+required_capability: spatial_grid
+
+// tag::geotile_to_long[]
+ROW geotile = "4/8/5"
+| EVAL geotileLong = ST_GEOTILE_TO_LONG(geotile)
+// end::geotile_to_long[]
+;
+
+// tag::geotile_to_long-result[]
+geotile:keyword | geotileLong:long
+4/8/5           | 1152921508901814277
+// end::geotile_to_long-result[]
+;
+
+geotileLongToString
+required_capability: spatial_grid
+
+// tag::geotile_to_string[]
+ROW geotile = 1152921508901814277
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+// end::geotile_to_string[]
+;
+
+// tag::geotile_to_string-result[]
+geotile:long        | geotileString:keyword
+1152921508901814277 | 4/8/5
+// end::geotile_to_string-result[]
+;
+
+geotileLiteral
+required_capability: spatial_grid
+
+// tag::st_geotile-literal[]
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geotile4 = ST_GEOTILE(location, 4),
+       geotile3 = ST_GEOTILE(location, 3),
+       geotile2 = ST_GEOTILE(location, 2),
+       geotile1 = ST_GEOTILE(location, 1)
+// end::st_geotile-literal[]
+;
+
+// tag::st_geotile-literal-result[]
+location:geo_point                        | geotile4:long       | geotile3:long      | geotile2:long      | geotile1:long
+POINT (12.6493508684508 55.6285017221528) | 1152921508901814277 | 864691130602618882 | 576460753377165313 | 288230376688582656
+// end::st_geotile-literal-result[]
+;
+
+geotileLiteralString
+required_capability: spatial_grid
+
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geotile4 = ST_GEOTILE_TO_STRING(ST_GEOTILE(location, 4)),
+       geotile3 = ST_GEOTILE_TO_STRING(ST_GEOTILE(location, 3)),
+       geotile2 = ST_GEOTILE_TO_STRING(ST_GEOTILE(location, 2)),
+       geotile1 = ST_GEOTILE_TO_STRING(ST_GEOTILE(location, 1))
+;
+
+location:geo_point                        | geotile4:keyword | geotile3:keyword | geotile2:keyword | geotile1:keyword
+POINT (12.6493508684508 55.6285017221528) | 4/8/5            | 3/4/2            | 2/2/1            | 1/1/0           
+;
+
+geotileField
+required_capability: spatial_grid
+
+FROM airports
+| WHERE abbrev == "CPH"
+| EVAL geotile = ST_GEOTILE(location, 7)
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| KEEP geotile, geotileString, abbrev, name, location
+;
+
+geotile:long        | geotileString:keyword | abbrev:keyword | name:text  | location:geo_point                       
+2017612669569204264 | 7/68/40               | CPH            | Copenhagen | POINT (12.6493508684508 55.6285017221528)
+;
+
+gridGeotileStatsBy
+required_capability: spatial_grid
+
+// tag::st_geotile-grid[]
+FROM airports
+| EVAL geotile = ST_GEOTILE(location, 2)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| SORT count DESC, geotileString ASC
+| KEEP count, centroid, geotileString
+// end::st_geotile-grid[]
+;
+
+// tag::st_geotile-grid-result[]
+count:long | centroid:geo_point                              | geotileString:keyword
+286        | POINT (39.31202001609169 35.149993664386415)    | 2/2/1          
+197        | POINT (-55.387361375756825 31.952955322292855)  | 2/1/1          
+136        | POINT (-110.97162496141048 36.87185255084734)   | 2/0/1          
+106        | POINT (119.35907618669827 25.46263281488791)    | 2/3/1          
+67         | POINT (-58.031108492373754 -22.624166105151065) | 2/1/2          
+46         | POINT (142.95455511274707 -20.581492295427978)  | 2/3/2          
+34         | POINT (31.38476753634784 -14.64374022804858)    | 2/2/2          
+8          | POINT (-160.0723083713092 -19.124013530672528)  | 2/0/2          
+6          | POINT (23.95813101902604 70.17537698848173)     | 2/2/0          
+3          | POINT (-133.4001641627401 72.06833167467266)    | 2/0/0          
+2          | POINT (-68.47209956031293 66.77569948369637)    | 2/1/0             
+// end::st_geotile-grid-result[]
+;
+
+gridGeotileQuery
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_GEOTILE(location, 2) == ST_GEOTILE_TO_LONG("2/0/2")
+| EVAL geotile = ST_GEOTILE(location, 3)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| SORT count DESC, geotileString ASC
+| KEEP count, centroid, geotileString
+;
+
+count:long | centroid:geo_point                             | geotileString:keyword
+7          | POINT (-167.3069146488394 -17.976190628084755) | 3/0/4
+1          | POINT (-109.43006442859769 -27.15877384878695) | 3/1/4
+;
+
+gridGeotileStatsByBounds
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geotile = ST_GEOTILE(location, 3, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| WHERE geotile IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| SORT count DESC, geotileString ASC
+| KEEP count, centroid, geotileString
+;
+
+count:long | centroid:geo_point                           | geotileString:keyword
+100        | POINT (18.10569669920951 50.40505832391791)  | 3/4/2
+79         | POINT (24.516750878736943 23.93036561181085) | 3/4/3
+;
+
+gridGeotileStatsByBoundsEnvelope
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geotile = ST_GEOTILE(location, 3, ST_ENVELOPE(TO_GEOSHAPE("POLYGON((0.0 30.0, 12.0 30.0, 12.0 60.0, 0.0 60.0, 0.0 30.0))")))
+| WHERE geotile IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| SORT count DESC, geotileString ASC
+| KEEP count, centroid, geotileString
+;
+
+count:long | centroid:geo_point                           | geotileString:keyword
+100        | POINT (18.10569669920951 50.40505832391791)  | 3/4/2
+79         | POINT (24.516750878736943 23.93036561181085) | 3/4/3
+;
+
+gridGeotileStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geotile = ST_GEOTILE(location, 4)
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| KEEP count, centroid, geotileString
+| SORT count DESC
+;
+
+count:long | centroid:geo_point                            | geotileString:keyword
+12         | POINT (-2.342151787597686 52.9600293841213)   | 4/7/5
+5          | POINT (-3.2097987569868565 57.63667118176818) | 4/7/4
+;
+
+gridGeotileStatsByBoundsUK
+required_capability: spatial_grid
+
+FROM airports
+| EVAL bounds = ST_ENVELOPE(TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geotile = ST_GEOTILE(location, 4, bounds)
+| WHERE geotile IS NOT NULL
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geotile
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+| KEEP count, centroid, geotileString
+| SORT count DESC
+;
+
+count:long | centroid:geo_point                            | geotileString:keyword
+56         | POINT (10.54233039047436 47.85997457644304)   | 4/8/5
+18         | POINT (-3.5578574100509286 51.27018998377025) | 4/7/5
+11         | POINT (14.310833624648778 59.85619530801407)  | 4/8/4
+7          | POINT (-6.466632609122565 59.19681839378817)  | 4/7/4
+;
+
+gridGeotileInStatsBy
+required_capability: spatial_grid
+
+FROM airports
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOTILE(location, 1)
+| SORT count DESC
+| KEEP count, centroid
+| LIMIT 10
+;
+
+count:long | centroid:geo_point                           
+398        | POINT (60.39961956408642 33.09796363900383)  
+338        | POINT (-78.52247301001411 34.49426195088267) 
+80         | POINT (95.5373953927774 -18.057947666791733) 
+75         | POINT (-68.91550314612687 -22.25081649720669)
+;
+
+gridGeotileInStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOTILE(location, 3)
+| KEEP count, centroid
+| SORT count DESC
+;
+
+count:long | centroid:geo_point                          
+17         | POINT (-2.597342072712148 54.33551226578214)
+;
+
+###############################################
+# Tests for geo_grid function: ST_GEOHEX
+###############################################
+
+geohexStringToLong
+required_capability: spatial_grid
+
+// tag::geohex_to_long[]
+ROW geohex = "841f059ffffffff"
+| EVAL geohexLong = ST_GEOHEX_TO_LONG(geohex)
+// end::geohex_to_long[]
+;
+
+// tag::geohex_to_long-result[]
+geohex:keyword  | geohexLong:long
+841f059ffffffff | 595020895127339007
+// end::geohex_to_long-result[]
+;
+
+geohexLongToString
+required_capability: spatial_grid
+
+// tag::geohex_to_string[]
+ROW geohex = 595020895127339007
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+// end::geohex_to_string[]
+;
+
+// tag::geohex_to_string-result[]
+geohex:long        | geohexString:keyword
+595020895127339007 | 841f059ffffffff
+// end::geohex_to_string-result[]
+;
+
+geohexLiteral
+required_capability: spatial_grid
+
+// tag::st_geohex-literal[]
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geohex4 = ST_GEOHEX(location, 4),
+       geohex3 = ST_GEOHEX(location, 3),
+       geohex2 = ST_GEOHEX(location, 2),
+       geohex1 = ST_GEOHEX(location, 1)
+// end::st_geohex-literal[]
+;
+
+// tag::st_geohex-literal-result[]
+location:geo_point                        | geohex4:long       | geohex3:long       | geohex2:long       | geohex1:long
+POINT (12.6493508684508 55.6285017221528) | 595020895127339007 | 590517321269772287 | 586013859081355263 | 581514107744681983
+// end::st_geohex-literal-result[]
+;
+
+geohexLiteralString
+required_capability: spatial_grid
+
+ROW location = TO_GEOPOINT("POINT(12.6493508684508 55.6285017221528)")
+| EVAL geohex4 = ST_GEOHEX_TO_STRING(ST_GEOHEX(location, 4)),
+       geohex3 = ST_GEOHEX_TO_STRING(ST_GEOHEX(location, 3)),
+       geohex2 = ST_GEOHEX_TO_STRING(ST_GEOHEX(location, 2)),
+       geohex1 = ST_GEOHEX_TO_STRING(ST_GEOHEX(location, 1))
+;
+
+location:geo_point                        | geohex4:keyword | geohex3:keyword | geohex2:keyword | geohex1:keyword
+POINT (12.6493508684508 55.6285017221528) | 841f059ffffffff | 831f05fffffffff | 821f07fffffffff | 811f3ffffffffff
+;
+
+geohexField
+required_capability: spatial_grid
+
+FROM airports
+| WHERE abbrev == "CPH"
+| EVAL geohex = ST_GEOHEX(location, 7)
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP geohex, geohexString, abbrev, name, location
+;
+
+geohex:long        | geohexString:keyword | abbrev:keyword | name:text  | location:geo_point
+608531685838946303 | 871f05818ffffff      | CPH            | Copenhagen | POINT (12.6493508684508 55.6285017221528)
+;
+
+gridGeohexStatsBy
+required_capability: spatial_grid
+
+// tag::st_geohex-grid[]
+FROM airports
+| EVAL geohex = ST_GEOHEX(location, 1)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| WHERE count >= 10
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP count, centroid, geohexString
+| SORT count DESC, geohexString ASC
+// end::st_geohex-grid[]
+;
+
+// tag::st_geohex-grid-result[]
+count:long | centroid:geo_point                             | geohexString:keyword 
+22         | POINT (7.250850197689777 48.21363834643059)    | 811fbffffffffff
+18         | POINT (-80.64959161449224 40.04119813675061)   | 812abffffffffff
+17         | POINT (-0.7606179875266903 52.86413913565304)  | 81197ffffffffff
+13         | POINT (22.53157936179867 41.98255742864254)    | 811efffffffffff
+13         | POINT (78.30096947387435 26.073904778951636)   | 813dbffffffffff
+12         | POINT (-76.39781514415517 45.16300531569868)   | 812bbffffffffff
+12         | POINT (-100.30120467301458 20.114154297625646) | 8149bffffffffff
+11         | POINT (18.037187419831753 48.66540593306788)   | 811e3ffffffffff
+11         | POINT (-83.42379064553164 33.18388901439241)   | 8144fffffffffff
+11         | POINT (-99.4237939513881 27.100012352774765)   | 8148bffffffffff
+10         | POINT (128.01009018346667 35.8699960866943)    | 8130fffffffffff
+// end::st_geohex-grid-result[]
+;
+
+gridGeohexQuery
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_GEOHEX(location, 1) == ST_GEOHEX_TO_LONG("812bbffffffffff")
+| EVAL geohex = ST_GEOHEX(location, 2)
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP count, centroid, geohexString
+| SORT count DESC, geohexString ASC
+;
+
+count:long | centroid:geo_point                            | geohexString:keyword
+3          | POINT (-74.35916994698346 43.44888433814049)  | 822b8ffffffffff
+2          | POINT (-74.84681587200612 45.50167993409559)  | 822b87fffffffff
+2          | POINT (-80.11034240014851 46.490730887744576) | 822b97fffffffff
+2          | POINT (-78.6383319273591 43.40425574686378)   | 822b9ffffffffff
+2          | POINT (-72.56662221159786 46.1249598255381)   | 822baffffffffff
+1          | POINT (-81.37204706668854 48.56615798547864)  | 820ecffffffffff
+;
+
+gridGeohexStatsByBounds
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geohex = ST_GEOHEX(location, 1, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| WHERE geohex IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| SORT count DESC, geohexString ASC
+| KEEP count, centroid, geohexString
+;
+
+count:long | centroid:geo_point                            | geohexString:keyword
+22         | POINT (7.250850197689777 48.21363834643059)   | 811fbffffffffff
+17         | POINT (-0.7606179875266903 52.86413913565304) | 81197ffffffffff
+7          | POINT (2.475211258445467 41.32352174592337)   | 81397ffffffffff
+6          | POINT (11.75047050230205 42.351422344800085)  | 811ebffffffffff
+5          | POINT (18.766171680763364 59.15833930950612)  | 8108bffffffffff
+5          | POINT (11.404999259859324 54.510593589395285) | 811f3ffffffffff
+4          | POINT (5.167026452254504 59.81037143385038)   | 8109bffffffffff
+4          | POINT (-1.1871178611181676 35.77457194332965) | 81383ffffffffff
+3          | POINT (-1.1497433669865131 45.83295159973204) | 81187ffffffffff
+3          | POINT (9.197671310976148 36.29719984252006)   | 81387ffffffffff
+1          | POINT (13.144258903339505 32.66916951164603)  | 813fbffffffffff
+;
+
+gridGeohexStatsByBoundsEnvelope
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geohex = ST_GEOHEX(location, 1, ST_ENVELOPE(TO_GEOSHAPE("POLYGON((0.0 30.0, 12.0 30.0, 12.0 60.0, 0.0 60.0, 0.0 30.0))")))
+| WHERE geohex IS NOT NULL
+| STATS
+    count = COUNT(*),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| SORT count DESC, geohexString ASC
+| KEEP count, centroid, geohexString
+;
+
+count:long | centroid:geo_point                            | geohexString:keyword
+22         | POINT (7.250850197689777 48.21363834643059)   | 811fbffffffffff
+17         | POINT (-0.7606179875266903 52.86413913565304) | 81197ffffffffff
+7          | POINT (2.475211258445467 41.32352174592337)   | 81397ffffffffff
+6          | POINT (11.75047050230205 42.351422344800085)  | 811ebffffffffff
+5          | POINT (18.766171680763364 59.15833930950612)  | 8108bffffffffff
+5          | POINT (11.404999259859324 54.510593589395285) | 811f3ffffffffff
+4          | POINT (5.167026452254504 59.81037143385038)   | 8109bffffffffff
+4          | POINT (-1.1871178611181676 35.77457194332965) | 81383ffffffffff
+3          | POINT (-1.1497433669865131 45.83295159973204) | 81187ffffffffff
+3          | POINT (9.197671310976148 36.29719984252006)   | 81387ffffffffff
+1          | POINT (13.144258903339505 32.66916951164603)  | 813fbffffffffff
+;
+
+gridGeohexQueryBounds
+required_capability: spatial_grid
+
+FROM airports
+| EVAL geohex = ST_GEOHEX(location, 1, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| WHERE ST_GEOHEX_TO_STRING(geohex) == "8108bffffffffff"
+| EVAL geohexString = ST_GEOHEX_TO_STRING(ST_GEOHEX(location, 1))
+| KEEP abbrev, location, geohexString
+| SORT abbrev ASC
+;
+
+abbrev:keyword | location:geo_point                        | geohexString:keyword
+ARN            | POINT (17.9307299016916 59.6511203397372) | 8108bffffffffff
+BMA            | POINT (17.9456175406145 59.3555902065112) | 8108bffffffffff
+NRK            | POINT (16.2339407695814 58.5833805017541) | 8108bffffffffff
+NYO            | POINT (16.9216055584254 58.7851041303448) | 8108bffffffffff
+TLL            | POINT (24.798964869983 59.4165014697451)  | 8108bffffffffff
+;
+
+gridGeohexByBounds
+required_capability: spatial_grid
+
+FROM airports
+| WHERE abbrev IN ("RTW", "TIP", "XMN")
+| EVAL geohex = ST_GEOHEX(location, 1, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP abbrev, location, geohex, geohexString
+| SORT abbrev ASC
+;
+
+abbrev:keyword | location:geo_point                        | geohex:long        | geohexString:keyword
+RTW            | POINT (46.035023249891 51.5606456508842)  | null               | null
+TIP            | POINT (13.1442589810713 32.6691695504993) | 582085853791125503 | 813fbffffffffff
+XMN            | POINT (118.12696884672 24.537192570557)   | null               | null
+;
+
+literalGridGeohexByBounds
+required_capability: spatial_grid
+
+ROW location = ["POINT (46.035023249891 51.5606456508842)", "POINT (13.1442589810713 32.6691695504993)", "POINT (118.12696884672 24.537192570557)"]
+| MV_EXPAND location
+| EVAL location = TO_GEOPOINT(location)
+| EVAL geohex = ST_GEOHEX(location, 1)
+| EVAL geohexBounded = ST_GEOHEX(location, 1, TO_GEOSHAPE("BBOX(0.0, 12.0, 60.0, 30.0)"))
+| EVAL geohex = ST_GEOHEX_TO_STRING(geohex)
+| EVAL geohexBounded = ST_GEOHEX_TO_STRING(geohexBounded)
+| KEEP location, geohex, geohexBounded
+| SORT geohex ASC
+;
+
+location:geo_point                        | geohex:keyword  | geohexBounded:keyword
+POINT (46.035023249891 51.5606456508842)  | 8110bffffffffff | null
+POINT (13.1442589810713 32.6691695504993) | 813fbffffffffff | 813fbffffffffff
+POINT (118.12696884672 24.537192570557)   | 8141bffffffffff | null
+;
+
+gridGeohexStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geohex = ST_GEOHEX(location, 1)
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP count, centroid, geohexString
+| SORT count DESC, geohexString ASC
+;
+
+count:long | centroid:geo_point                            | geohexString:keyword
+13         | POINT (-2.283508819169723 53.28242553254733)  | 81197ffffffffff
+2          | POINT (-3.482485176064074 58.24696456314996)  | 81193ffffffffff
+1          | POINT (-1.2880607228726149 59.87668995279819) | 8109bffffffffff
+1          | POINT (-6.216169511899352 54.66155751608312)  | 81183ffffffffff
+;
+
+gridGeohexStatsByBoundsUK
+required_capability: spatial_grid
+
+FROM airports
+| EVAL bounds = ST_ENVELOPE(TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| EVAL geohex = ST_GEOHEX(location, 2, bounds)
+| WHERE geohex IS NOT NULL
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY geohex
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+| KEEP count, centroid, geohexString
+| SORT count DESC, geohexString ASC
+;
+
+count:long | centroid:geo_point                             | geohexString:keyword
+5          | POINT (-1.7227098606526852 51.717823022045195) | 82195ffffffffff
+4          | POINT (-3.9897833741270006 54.21732849790715)  | 821957fffffffff
+3          | POINT (-7.885485291481018 52.65633414499462)   | 82182ffffffffff
+3          | POINT (3.0334555450826883 48.842039234004915)  | 821fb7fffffffff
+2          | POINT (5.428531668148935 59.585608751513064)   | 820987fffffffff
+2          | POINT (-4.2476349184289575 56.70184155693278)  | 82190ffffffffff
+2          | POINT (1.4715016074478626 50.863699545152485)  | 82194ffffffffff
+2          | POINT (4.5991105819121 52.129031270742416)     | 82196ffffffffff
+2          | POINT (-2.5373152876272798 55.49281941493973)  | 821977fffffffff
+1          | POINT (-1.2880607228726149 59.87668995279819)  | 8209a7fffffffff
+1          | POINT (0.15865350142121315 49.36166098807007)  | 821867fffffffff
+1          | POINT (-7.270800014957786 62.06249998882413)   | 821927fffffffff
+1          | POINT (-2.9013785161077976 58.95442885346711)  | 82192ffffffffff
+1          | POINT (-1.6598310694098473 53.8690819311887)   | 821947fffffffff
+;
+
+gridGeohexInStatsByBounds
+required_capability: spatial_grid
+
+FROM airports
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOHEX(location, 2, ST_ENVELOPE(TO_GEOSHAPE("POLYGON((0.0 30.0, 12.0 30.0, 12.0 60.0, 0.0 60.0, 0.0 30.0))")))
+| WHERE count > 3
+| SORT count DESC
+| KEEP count, centroid
+| LIMIT 10
+;
+
+count:long | centroid:geo_point
+827        | POINT (-0.5615898292227913 22.56591850424922)
+6          | POINT (5.582276992499828 50.72238312335685)
+5          | POINT (8.6918301936239 45.19817395694554)
+;
+
+gridGeohexInStatsByWhereUK
+required_capability: spatial_grid
+
+FROM airports
+| WHERE ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
+| STATS
+    count = COUNT(location),
+    centroid = ST_CENTROID_AGG(location)
+      BY ST_GEOHEX(location, 1)
+| WHERE count > 1
+| KEEP count, centroid
+| SORT count DESC
+;
+
+count:long | centroid:geo_point 
+13         | POINT (-2.283508819169723 53.28242553254733)
+2          | POINT (-3.482485176064074 58.24696456314996)
+;

+ 1 - 40
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialExtentAggregationNoLicenseIT.java

@@ -7,12 +7,7 @@
 
 package org.elasticsearch.xpack.esql.spatial;
 
-import org.elasticsearch.license.License;
-import org.elasticsearch.license.XPackLicenseState;
-import org.elasticsearch.license.internal.XPackLicenseStatus;
 import org.elasticsearch.plugins.Plugin;
-import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
-import org.elasticsearch.xpack.spatial.SpatialPlugin;
 
 import java.util.Collection;
 import java.util.List;
@@ -21,45 +16,11 @@ public class SpatialExtentAggregationNoLicenseIT extends SpatialExtentAggregatio
 
     @Override
     protected Collection<Class<? extends Plugin>> nodePlugins() {
-        return List.of(TestSpatialPlugin.class, TestEsqlPlugin.class);
+        return List.of(SpatialNoLicenseTestCase.TestSpatialPlugin.class, SpatialNoLicenseTestCase.TestEsqlPlugin.class);
     }
 
     @Override
     public void testStExtentAggregationWithShapes() {
         assertStExtentFailsWith("index_geo_shape");
     }
-
-    private static XPackLicenseState getLicenseState() {
-        License.OperationMode operationMode;
-        boolean active;
-        if (randomBoolean()) {
-            operationMode = randomFrom(
-                License.OperationMode.GOLD,
-                License.OperationMode.BASIC,
-                License.OperationMode.MISSING,
-                License.OperationMode.STANDARD
-            );
-            active = true;
-        } else {
-            operationMode = randomFrom(License.OperationMode.PLATINUM, License.OperationMode.ENTERPRISE, License.OperationMode.TRIAL);
-            active = false;  // expired
-        }
-
-        return new XPackLicenseState(
-            () -> System.currentTimeMillis(),
-            new XPackLicenseStatus(operationMode, active, "Test license expired")
-        );
-    }
-
-    public static class TestEsqlPlugin extends EsqlPlugin {
-        protected XPackLicenseState getLicenseState() {
-            return SpatialExtentAggregationNoLicenseIT.getLicenseState();
-        }
-    }
-
-    public static class TestSpatialPlugin extends SpatialPlugin {
-        protected XPackLicenseState getLicenseState() {
-            return SpatialExtentAggregationNoLicenseIT.getLicenseState();
-        }
-    }
 }

+ 142 - 0
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialGridLicenseTestCase.java

@@ -0,0 +1,142 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.spatial;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.bulk.BulkRequestBuilder;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.support.WriteRequest;
+import org.elasticsearch.geometry.Point;
+import org.elasticsearch.xpack.esql.VerificationException;
+import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
+import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
+import org.junit.Before;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+public abstract class SpatialGridLicenseTestCase extends AbstractEsqlIntegTestCase {
+
+    @Before
+    public void setupIndex() throws Exception {
+        assumeTrue("requires SPATIAL_GRID capability", EsqlCapabilities.Cap.SPATIAL_GRID.isEnabled());
+        createAndPopulateIndexes(10);
+    }
+
+    protected List<Point> testData = new ArrayList<>();
+
+    protected abstract String gridFunction();
+
+    protected abstract Map<Long, Long> expectedValues();
+
+    protected int precision() {
+        return 1; // Default precision for grid function tests, can be overridden in subclasses
+    }
+
+    /**
+     * This test will fail without a platinum license
+     */
+    public abstract void testGeoGridWithShapes();
+
+    /**
+     * This test should pass with and without platinum licenses.
+     * This should only be overridden for ST_GEOHEX which also licenses geo_point use cases.
+     */
+    public void testGeoGridWithPoints() {
+        assertGeoGridFromIndex("index_geo_point");
+    }
+
+    protected void assertGeoGridFromIndex(String index) {
+        assumeTrue("geo_shape capability not yet implemented", index.equals("index_geo_point"));
+        var query = String.format(Locale.ROOT, """
+            FROM %s
+            | EVAL gridId = %s(location, %s)
+            | STATS count=COUNT() BY gridId
+            | KEEP gridId, count
+            """, index, gridFunction(), precision());
+        try (var resp = run(query)) {
+            assertColumnNames(resp.columns(), List.of("gridId", "count"));
+            assertColumnTypes(resp.columns(), List.of("long", "long"));
+            Map<Long, Long> values = getValuesMap(resp.values());
+            Map<Long, Long> expected = expectedValues();
+            assertThat(values.size(), equalTo(expected.size()));
+            for (Long gridId : expected.keySet()) {
+                assertThat("Missing grid-id: " + gridId, values.containsKey(gridId), equalTo(true));
+                assertThat("Unexpected count for grid-id: " + gridId, values.get(gridId), equalTo(expected.get(gridId)));
+            }
+        }
+    }
+
+    protected void assertGeoGridFailsWith(String index) {
+        assumeTrue("geo_shape capability not yet implemented", index.equals("index_geo_point"));
+        var query = String.format(Locale.ROOT, """
+            FROM %s
+            | EVAL gridId = %s(location, %d)
+            | STATS count=COUNT() BY gridId
+            """, index, gridFunction(), precision());
+        var expectedError = String.format(
+            Locale.ROOT,
+            "current license is non-compliant for [%s(location, %d)]",
+            gridFunction(),
+            precision()
+        );
+        ElasticsearchException e = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(e.getMessage(), containsString(expectedError));
+    }
+
+    public static Map<Long, Long> getValuesMap(Iterator<Iterator<Object>> values) {
+        var valuesMap = new LinkedHashMap<Long, Long>();
+        values.forEachRemaining(row -> { valuesMap.put(((Number) row.next()).longValue(), ((Number) row.next()).longValue()); });
+        return valuesMap;
+    }
+
+    private void createAndPopulateIndexes(int count) throws Exception {
+        initIndex("index_", "geo_point");
+        initIndex("index_", "geo_shape");
+        BulkRequestBuilder points = client().prepareBulk();
+        BulkRequestBuilder shapes = client().prepareBulk();
+        StringBuilder coords = new StringBuilder();
+        for (int i = 0; i < count; i++) {
+            double x = randomDoubleBetween(-10.0, 10.0, true);
+            double y = randomDoubleBetween(-10.0, 10.0, true);
+            Point point = new Point(x, y);
+            testData.add(point);
+            points.add(new IndexRequest("index_geo_point").id(x + ":" + y).source("location", point.toString()));
+            if (coords.length() > 0) {
+                coords.append(", ");
+            }
+            coords.append(x).append(" ").append(y);
+        }
+        if (coords.length() > 0) {
+            String lineString = "LINESTRING (" + coords + ")";
+            shapes.add(new IndexRequest("index_geo_shape").id("polygon").source("location", lineString));
+        }
+        points.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
+        shapes.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
+        ensureYellow("index_geo_point");
+        ensureYellow("index_geo_shape");
+    }
+
+    protected void initIndex(String prefix, String fieldType) {
+        assertAcked(prepareCreate(prefix + fieldType).setMapping(String.format(Locale.ROOT, """
+            {
+              "properties" : {
+                "location": { "type" : "%s" }
+              }
+            }
+            """, fieldType)));
+    }
+}

+ 66 - 0
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialNoLicenseTestCase.java

@@ -0,0 +1,66 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.spatial;
+
+import org.elasticsearch.license.License;
+import org.elasticsearch.license.XPackLicenseState;
+import org.elasticsearch.license.internal.XPackLicenseStatus;
+import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
+import org.elasticsearch.xpack.spatial.SpatialPlugin;
+
+/**
+ * Utility class to provide a license state that does not allow spatial features.
+ * This is used in tests to ensure that spatial functions behave correctly when no valid license is present.
+ */
+public abstract class SpatialNoLicenseTestCase extends ESIntegTestCase {
+
+    private static XPackLicenseState getLicenseState() {
+        License.OperationMode operationMode;
+        boolean active;
+        if (randomBoolean()) {
+            // Randomly chosen licenses that are not Platinum, Enterprise, or Trial
+            operationMode = randomFrom(
+                License.OperationMode.GOLD,
+                License.OperationMode.BASIC,
+                License.OperationMode.MISSING,
+                License.OperationMode.STANDARD
+            );
+            active = true;
+        } else {
+            // Randomly chosen licenses that are Platinum, Enterprise, or Trial but marked as expired
+            operationMode = randomFrom(License.OperationMode.PLATINUM, License.OperationMode.ENTERPRISE, License.OperationMode.TRIAL);
+            active = false;  // expired
+        }
+
+        return new XPackLicenseState(
+            () -> System.currentTimeMillis(),
+            new XPackLicenseStatus(operationMode, active, "Test license expired")
+        );
+    }
+
+    /**
+     * Test plugin that provides a license state that does not allow spatial features.
+     * This is used to test the behavior of spatial functions when no valid license is present.
+     */
+    public static class TestEsqlPlugin extends EsqlPlugin {
+        protected XPackLicenseState getLicenseState() {
+            return SpatialNoLicenseTestCase.getLicenseState();
+        }
+    }
+
+    /**
+     * Test plugin that provides a license state that does not allow spatial features.
+     * This is used to test the behavior of spatial functions when no valid license is present.
+     */
+    public static class TestSpatialPlugin extends SpatialPlugin {
+        protected XPackLicenseState getLicenseState() {
+            return SpatialNoLicenseTestCase.getLicenseState();
+        }
+    }
+}

+ 45 - 0
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohashLicenseIT.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.spatial;
+
+import org.elasticsearch.geometry.Point;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.xpack.esql.action.EsqlPluginWithEnterpriseOrTrialLicense;
+import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.StGeohash;
+import org.elasticsearch.xpack.spatial.SpatialPlugin;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StGeohashLicenseIT extends SpatialGridLicenseTestCase {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialPlugin.class, EsqlPluginWithEnterpriseOrTrialLicense.class);
+    }
+
+    @Override
+    protected String gridFunction() {
+        return "ST_GEOHASH";
+    }
+
+    @Override
+    protected Map<Long, Long> expectedValues() {
+        Map<Long, Long> expected = new HashMap<>();
+        for (Point point : testData) {
+            long gridId = StGeohash.unboundedGrid.calculateGridId(point, precision());
+            expected.compute(gridId, (k, v) -> v == null ? 1 : v + 1);
+        }
+        return expected;
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFromIndex("index_geo_shape");
+    }
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor