瀏覽代碼

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.
Craig Taverner 4 月之前
父節點
當前提交
11f0c5526a
共有 100 個文件被更改,包括 4463 次插入41 次删除
  1. 6 0
      docs/changelog/125143.yaml
  2. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohash.md
  3. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohash_to_long.md
  4. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohash_to_string.md
  5. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohex.md
  6. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohex_to_long.md
  7. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geohex_to_string.md
  8. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geotile.md
  9. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geotile_to_long.md
  10. 6 0
      docs/reference/query-languages/esql/_snippets/functions/description/st_geotile_to_string.md
  11. 38 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash.md
  12. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash_to_long.md
  13. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash_to_string.md
  14. 32 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex.md
  15. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex_to_long.md
  16. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex_to_string.md
  17. 31 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile.md
  18. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile_to_long.md
  19. 14 0
      docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile_to_string.md
  20. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohash.md
  21. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohash_to_long.md
  22. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohash_to_string.md
  23. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohex.md
  24. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohex_to_long.md
  25. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geohex_to_string.md
  26. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile.md
  27. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile_to_long.md
  28. 23 0
      docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile_to_string.md
  29. 13 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash.md
  30. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash_to_long.md
  31. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash_to_string.md
  32. 13 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex.md
  33. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex_to_long.md
  34. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex_to_string.md
  35. 13 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile.md
  36. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile_to_long.md
  37. 7 0
      docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile_to_string.md
  38. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohash.md
  39. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohash_to_long.md
  40. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohash_to_string.md
  41. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohex.md
  42. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohex_to_long.md
  43. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geohex_to_string.md
  44. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geotile.md
  45. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geotile_to_long.md
  46. 9 0
      docs/reference/query-languages/esql/_snippets/functions/types/st_geotile_to_string.md
  47. 9 0
      docs/reference/query-languages/esql/_snippets/lists/spatial-functions.md
  48. 26 0
      docs/reference/query-languages/esql/functions-operators/spatial-functions.md
  49. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohash.svg
  50. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohash_to_long.svg
  51. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohash_to_string.svg
  52. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohex.svg
  53. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohex_to_long.svg
  54. 1 0
      docs/reference/query-languages/esql/images/functions/st_geohex_to_string.svg
  55. 1 0
      docs/reference/query-languages/esql/images/functions/st_geotile.svg
  56. 1 0
      docs/reference/query-languages/esql/images/functions/st_geotile_to_long.svg
  57. 1 0
      docs/reference/query-languages/esql/images/functions/st_geotile_to_string.svg
  58. 55 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohash.json
  59. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohash_to_long.json
  60. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohash_to_string.json
  61. 58 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json
  62. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_long.json
  63. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_string.json
  64. 55 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geotile.json
  65. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_long.json
  66. 37 0
      docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_string.json
  67. 21 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohash.md
  68. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohash_to_long.md
  69. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohash_to_string.md
  70. 21 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohex.md
  71. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohex_to_long.md
  72. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geohex_to_string.md
  73. 20 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geotile.md
  74. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geotile_to_long.md
  75. 9 0
      docs/reference/query-languages/esql/kibana/docs/functions/st_geotile_to_string.md
  76. 6 0
      x-pack/plugin/esql/build.gradle
  77. 475 0
      x-pack/plugin/esql/licenses/lucene-LICENSE.txt
  78. 192 0
      x-pack/plugin/esql/licenses/lucene-NOTICE.txt
  79. 1 1
      x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java
  80. 884 0
      x-pack/plugin/esql/qa/testFixtures/src/main/resources/spatial-grid.csv-spec
  81. 1 40
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialExtentAggregationNoLicenseIT.java
  82. 142 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialGridLicenseTestCase.java
  83. 66 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/SpatialNoLicenseTestCase.java
  84. 45 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohashLicenseIT.java
  85. 24 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohashNoLicenseIT.java
  86. 45 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohexLicenseIT.java
  87. 31 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohexNoLicenseIT.java
  88. 45 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeotileLicenseIT.java
  89. 24 0
      x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeotileNoLicenseIT.java
  90. 119 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldAndLiteralAndLiteralEvaluator.java
  91. 118 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldAndLiteralEvaluator.java
  92. 118 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator.java
  93. 116 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldDocValuesAndLiteralEvaluator.java
  94. 126 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashToLongFromStringEvaluator.java
  95. 124 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashToStringFromLongEvaluator.java
  96. 119 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldAndLiteralAndLiteralEvaluator.java
  97. 118 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldAndLiteralEvaluator.java
  98. 118 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator.java
  99. 116 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldDocValuesAndLiteralEvaluator.java
  100. 126 0
      x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexToLongFromStringEvaluator.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

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohash.md

@@ -0,0 +1,6 @@
+% 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 [ST_GEOHASH_TO_STRING](#esql-st_geohash_to_string) to convert the result to a string.  These functions are related to the [`geo_grid` query](/reference/query-languages/query-dsl/query-dsl-geo-grid-query.md) and the [`geohash_grid` aggregation](/reference/aggregations/search-aggregations-bucket-geohashgrid-aggregation.md).
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohash_to_long.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohash_to_string.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohex.md

@@ -0,0 +1,6 @@
+% 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 [ST_GEOHEX_TO_STRING](#esql-st_geohex_to_string) to convert the result to a string.  These functions are related to the [`geo_grid` query](/reference/query-languages/query-dsl/query-dsl-geo-grid-query.md) and the [`geohex_grid` aggregation](/reference/aggregations/search-aggregations-bucket-geohexgrid-aggregation.md).
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohex_to_long.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geohex_to_string.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geotile.md

@@ -0,0 +1,6 @@
+% 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 [ST_GEOTILE_TO_STRING](#esql-st_geotile_to_string) to convert the result to a string.  These functions are related to the [`geo_grid` query](/reference/query-languages/query-dsl/query-dsl-geo-grid-query.md) and the [`geotile_grid` aggregation](/reference/aggregations/search-aggregations-bucket-geotilegrid-aggregation.md).
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geotile_to_long.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 6 - 0
docs/reference/query-languages/esql/_snippets/functions/description/st_geotile_to_string.md

@@ -0,0 +1,6 @@
+% 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.
+

+ 38 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash.md

@@ -0,0 +1,38 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+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
+```
+
+| 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 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash_to_long.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geohash = "u3bu"
+| EVAL geohashLong = ST_GEOHASH_TO_LONG(geohash)
+```
+
+| geohash:keyword | geohashLong:long |
+| --- | --- |
+| u3bu | 13686180 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohash_to_string.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geohash = TO_LONG(13686180)
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+```
+
+| geohash:long | geohashString:keyword |
+| --- | --- |
+| 13686180 | u3bu |
+
+

+ 32 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex.md

@@ -0,0 +1,32 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+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
+```
+
+| 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 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex_to_long.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geohex = "841f059ffffffff"
+| EVAL geohexLong = ST_GEOHEX_TO_LONG(geohex)
+```
+
+| geohex:keyword | geohexLong:long |
+| --- | --- |
+| 841f059ffffffff | 595020895127339007 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geohex_to_string.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geohex = 595020895127339007
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+```
+
+| geohex:long | geohexString:keyword |
+| --- | --- |
+| 595020895127339007 | 841f059ffffffff |
+
+

+ 31 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile.md

@@ -0,0 +1,31 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+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
+```
+
+| 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 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile_to_long.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geotile = "4/8/5"
+| EVAL geotileLong = ST_GEOTILE_TO_LONG(geotile)
+```
+
+| geotile:keyword | geotileLong:long |
+| --- | --- |
+| 4/8/5 | 1152921508901814277 |
+
+

+ 14 - 0
docs/reference/query-languages/esql/_snippets/functions/examples/st_geotile_to_string.md

@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Example**
+
+```esql
+ROW geotile = 1152921508901814277
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+```
+
+| geotile:long | geotileString:keyword |
+| --- | --- |
+| 1152921508901814277 | 4/8/5 |
+
+

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/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` [esql-st_geohash]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohash.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohash.md
+:::
+
+:::{include} ../description/st_geohash.md
+:::
+
+:::{include} ../types/st_geohash.md
+:::
+
+:::{include} ../examples/st_geohash.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geohash_to_long.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_TO_LONG` [esql-st_geohash_to_long]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohash_to_long.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohash_to_long.md
+:::
+
+:::{include} ../description/st_geohash_to_long.md
+:::
+
+:::{include} ../types/st_geohash_to_long.md
+:::
+
+:::{include} ../examples/st_geohash_to_long.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geohash_to_string.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_TO_STRING` [esql-st_geohash_to_string]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohash_to_string.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohash_to_string.md
+:::
+
+:::{include} ../description/st_geohash_to_string.md
+:::
+
+:::{include} ../types/st_geohash_to_string.md
+:::
+
+:::{include} ../examples/st_geohash_to_string.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/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` [esql-st_geohex]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohex.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohex.md
+:::
+
+:::{include} ../description/st_geohex.md
+:::
+
+:::{include} ../types/st_geohex.md
+:::
+
+:::{include} ../examples/st_geohex.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geohex_to_long.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_TO_LONG` [esql-st_geohex_to_long]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohex_to_long.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohex_to_long.md
+:::
+
+:::{include} ../description/st_geohex_to_long.md
+:::
+
+:::{include} ../types/st_geohex_to_long.md
+:::
+
+:::{include} ../examples/st_geohex_to_long.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geohex_to_string.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_TO_STRING` [esql-st_geohex_to_string]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geohex_to_string.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geohex_to_string.md
+:::
+
+:::{include} ../description/st_geohex_to_string.md
+:::
+
+:::{include} ../types/st_geohex_to_string.md
+:::
+
+:::{include} ../examples/st_geohex_to_string.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile.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_GEOTILE` [esql-st_geotile]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geotile.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geotile.md
+:::
+
+:::{include} ../description/st_geotile.md
+:::
+
+:::{include} ../types/st_geotile.md
+:::
+
+:::{include} ../examples/st_geotile.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile_to_long.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_GEOTILE_TO_LONG` [esql-st_geotile_to_long]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geotile_to_long.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geotile_to_long.md
+:::
+
+:::{include} ../description/st_geotile_to_long.md
+:::
+
+:::{include} ../types/st_geotile_to_long.md
+:::
+
+:::{include} ../examples/st_geotile_to_long.md
+:::

+ 23 - 0
docs/reference/query-languages/esql/_snippets/functions/layout/st_geotile_to_string.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_GEOTILE_TO_STRING` [esql-st_geotile_to_string]
+
+**Syntax**
+
+:::{image} ../../../images/functions/st_geotile_to_string.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/st_geotile_to_string.md
+:::
+
+:::{include} ../description/st_geotile_to_string.md
+:::
+
+:::{include} ../types/st_geotile_to_string.md
+:::
+
+:::{include} ../examples/st_geotile_to_string.md
+:::

+ 13 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash.md

@@ -0,0 +1,13 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash_to_long.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohash_to_string.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 13 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex.md

@@ -0,0 +1,13 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex_to_long.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geohex_to_string.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 13 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile.md

@@ -0,0 +1,13 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile_to_long.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 7 - 0
docs/reference/query-languages/esql/_snippets/functions/parameters/st_geotile_to_string.md

@@ -0,0 +1,7 @@
+% 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.
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohash.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| geometry | precision | bounds | result |
+| --- | --- | --- | --- |
+| geo_point | integer | geo_shape | long |
+| geo_point | integer | | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohash_to_long.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | long |
+| long | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohash_to_string.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | keyword |
+| long | keyword |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohex.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| geometry | precision | bounds | result |
+| --- | --- | --- | --- |
+| geo_point | integer | geo_shape | long |
+| geo_point | integer | | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohex_to_long.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | long |
+| long | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geohex_to_string.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | keyword |
+| long | keyword |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geotile.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| geometry | precision | bounds | result |
+| --- | --- | --- | --- |
+| geo_point | integer | geo_shape | long |
+| geo_point | integer | | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geotile_to_long.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | long |
+| long | long |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/functions/types/st_geotile_to_string.md

@@ -0,0 +1,9 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| grid_id | result |
+| --- | --- |
+| keyword | keyword |
+| long | keyword |
+

+ 9 - 0
docs/reference/query-languages/esql/_snippets/lists/spatial-functions.md

@@ -10,3 +10,12 @@
   * [preview] [`ST_XMIN`](../../functions-operators/spatial-functions.md#esql-st_xmin)
   * [preview] [`ST_YMAX`](../../functions-operators/spatial-functions.md#esql-st_ymax)
   * [preview] [`ST_YMIN`](../../functions-operators/spatial-functions.md#esql-st_ymin)
+* [preview] [`ST_GEOTILE`](../../functions-operators/spatial-functions.md#esql-st_geotile)
+  * [preview] [`ST_GEOTILE_TO_STRING`](../../functions-operators/spatial-functions.md#esql-st_geotile_to_string)
+  * [preview] [`ST_GEOTILE_TO_LONG`](../../functions-operators/spatial-functions.md#esql-st_geotile_to_long)
+* [preview] [`ST_GEOHEX`](../../functions-operators/spatial-functions.md#esql-st_geohex)
+  * [preview] [`ST_GEOHEX_TO_STRING`](../../functions-operators/spatial-functions.md#esql-st_geohex_to_string)
+  * [preview] [`ST_GEOHEX_TO_LONG`](../../functions-operators/spatial-functions.md#esql-st_geohex_to_long)
+* [preview] [`ST_GEOHASH`](../../functions-operators/spatial-functions.md#esql-st_geohash)
+  * [preview] [`ST_GEOHASH_TO_STRING`](../../functions-operators/spatial-functions.md#esql-st_geohash_to_string)
+  * [preview] [`ST_GEOHASH_TO_LONG`](../../functions-operators/spatial-functions.md#esql-st_geohash_to_long)

+ 26 - 0
docs/reference/query-languages/esql/functions-operators/spatial-functions.md

@@ -48,3 +48,29 @@ mapped_pages:
 :::{include} ../_snippets/functions/layout/st_ymin.md
 :::
 
+:::{include} ../_snippets/functions/layout/st_geotile.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geotile_to_string.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geotile_to_long.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohex.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohex_to_string.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohex_to_long.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohash.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohash_to_string.md
+:::
+
+:::{include} ../_snippets/functions/layout/st_geohash_to_long.md
+:::

+ 1 - 0
docs/reference/query-languages/esql/images/functions/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="724" height="61" viewbox="0 0 724 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 31h5m140 0h10m32 0h10m116 0h10m32 0h10m128 0h10m32 0h30m92 0h20m-127 0q5 0 5 5v10q0 5 5 5h102q5 0 5-5v-10q0-5 5-5m5 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="565" y="5" width="92" height="36" rx="7"/><text class="k" x="575" y="31">bounds</text><rect class="s" x="687" y="5" width="32" height="36" rx="7"/><text class="syn" x="697" y="31">)</text></svg>

+ 1 - 0
docs/reference/query-languages/esql/images/functions/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">.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 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/query-languages/esql/images/functions/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">.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 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/query-languages/esql/images/functions/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="712" height="61" viewbox="0 0 712 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 31h5m128 0h10m32 0h10m116 0h10m32 0h10m128 0h10m32 0h30m92 0h20m-127 0q5 0 5 5v10q0 5 5 5h102q5 0 5-5v-10q0-5 5-5m5 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="553" y="5" width="92" height="36" rx="7"/><text class="k" x="563" y="31">bounds</text><rect class="s" x="675" y="5" width="32" height="36" rx="7"/><text class="syn" x="685" y="31">)</text></svg>

+ 1 - 0
docs/reference/query-languages/esql/images/functions/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">.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 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/query-languages/esql/images/functions/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">.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 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/query-languages/esql/images/functions/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="724" height="61" viewbox="0 0 724 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 31h5m140 0h10m32 0h10m116 0h10m32 0h10m128 0h10m32 0h30m92 0h20m-127 0q5 0 5 5v10q0 5 5 5h102q5 0 5-5v-10q0-5 5-5m5 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="565" y="5" width="92" height="36" rx="7"/><text class="k" x="575" y="31">bounds</text><rect class="s" x="687" y="5" width="32" height="36" rx="7"/><text class="syn" x="697" y="31">)</text></svg>

+ 1 - 0
docs/reference/query-languages/esql/images/functions/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">.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 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/query-languages/esql/images/functions/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">.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 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>

+ 55 - 0
docs/reference/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "name" : "st_geohash",
+  "description" : "Calculates the `geohash` of the supplied geo_point at the specified precision.\nThe result is long encoded. Use ST_GEOHASH_TO_STRING to convert the result to a string.\n\nThese functions are related to the `geo_grid` query\nand the `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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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
+}

+ 58 - 0
docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json

@@ -0,0 +1,58 @@
+{
+  "comment" : "This is generated by ESQL’s AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
+  "type" : "scalar",
+  "name" : "st_geohex",
+  "license" : "PLATINUM",
+  "description" : "Calculates the `geohex`, the H3 cell-id, of the supplied geo_point at the specified precision.\nThe result is long encoded. Use ST_GEOHEX_TO_STRING to convert the result to a string.\n\nThese functions are related to the `geo_grid` query\nand the `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/)."
+        }
+      ],
+      "license" : "PLATINUM",
+      "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."
+        }
+      ],
+      "license" : "PLATINUM",
+      "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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "name" : "st_geotile",
+  "description" : "Calculates the `geotile` of the supplied geo_point at the specified precision.\nThe result is long encoded. Use ST_GEOTILE_TO_STRING to convert the result to a string.\n\nThese functions are related to the `geo_grid` query\nand the `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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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/query-languages/esql/kibana/definition/functions/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" : "scalar",
+  "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
+}

+ 21 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohash.md

@@ -0,0 +1,21 @@
+% 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 [ST_GEOHASH_TO_STRING](#esql-st_geohash_to_string) to convert the result to a string.
+
+These functions are related to the [`geo_grid` query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-geo-grid-query)
+and the [`geohash_grid` aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-geohashgrid-aggregation).
+
+```esql
+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
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohash_to_long.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geohash = "u3bu"
+| EVAL geohashLong = ST_GEOHASH_TO_LONG(geohash)
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohash_to_string.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geohash = TO_LONG(13686180)
+| EVAL geohashString = ST_GEOHASH_TO_STRING(geohash)
+```

+ 21 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohex.md

@@ -0,0 +1,21 @@
+% 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 [ST_GEOHEX_TO_STRING](#esql-st_geohex_to_string) to convert the result to a string.
+
+These functions are related to the [`geo_grid` query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-geo-grid-query)
+and the [`geohex_grid` aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-geohexgrid-aggregation).
+
+```esql
+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
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohex_to_long.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geohex = "841f059ffffffff"
+| EVAL geohexLong = ST_GEOHEX_TO_LONG(geohex)
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geohex_to_string.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geohex = 595020895127339007
+| EVAL geohexString = ST_GEOHEX_TO_STRING(geohex)
+```

+ 20 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geotile.md

@@ -0,0 +1,20 @@
+% 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 [ST_GEOTILE_TO_STRING](#esql-st_geotile_to_string) to convert the result to a string.
+
+These functions are related to the [`geo_grid` query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-geo-grid-query)
+and the [`geotile_grid` aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-geotilegrid-aggregation).
+
+```esql
+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
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geotile_to_long.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geotile = "4/8/5"
+| EVAL geotileLong = ST_GEOTILE_TO_LONG(geotile)
+```

+ 9 - 0
docs/reference/query-languages/esql/kibana/docs/functions/st_geotile_to_string.md

@@ -0,0 +1,9 @@
+% 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.
+
+```esql
+ROW geotile = 1152921508901814277
+| EVAL geotileString = ST_GEOTILE_TO_STRING(geotile)
+```

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

@@ -40,6 +40,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.
@@ -69,6 +71,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

@@ -328,7 +328,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");
+    }
+}

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

@@ -0,0 +1,24 @@
+/*
+ * 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.plugins.Plugin;
+
+import java.util.Collection;
+import java.util.List;
+
+public class StGeohashNoLicenseIT extends StGeohashLicenseIT {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialNoLicenseTestCase.TestSpatialPlugin.class, SpatialNoLicenseTestCase.TestEsqlPlugin.class);
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFailsWith("index_geo_shape");
+    }
+}

+ 45 - 0
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeohexLicenseIT.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.StGeohex;
+import org.elasticsearch.xpack.spatial.SpatialPlugin;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StGeohexLicenseIT extends SpatialGridLicenseTestCase {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialPlugin.class, EsqlPluginWithEnterpriseOrTrialLicense.class);
+    }
+
+    @Override
+    protected String gridFunction() {
+        return "ST_GEOHEX";
+    }
+
+    @Override
+    protected Map<Long, Long> expectedValues() {
+        Map<Long, Long> expected = new HashMap<>();
+        for (Point point : testData) {
+            long gridId = StGeohex.unboundedGrid.calculateGridId(point, precision());
+            expected.compute(gridId, (k, v) -> v == null ? 1 : v + 1);
+        }
+        return expected;
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFromIndex("index_geo_shape");
+    }
+}

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

@@ -0,0 +1,31 @@
+/*
+ * 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.plugins.Plugin;
+
+import java.util.Collection;
+import java.util.List;
+
+public class StGeohexNoLicenseIT extends StGeohexLicenseIT {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialNoLicenseTestCase.TestSpatialPlugin.class, SpatialNoLicenseTestCase.TestEsqlPlugin.class);
+    }
+
+    /**
+     * The ST_GEOHEX function is not available without a license, so we override the test to ensure it fails.
+     */
+    public void testGeoGridWithPoints() {
+        assertGeoGridFailsWith("index_geo_point");
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFailsWith("index_geo_shape");
+    }
+}

+ 45 - 0
x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/spatial/StGeotileLicenseIT.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.StGeotile;
+import org.elasticsearch.xpack.spatial.SpatialPlugin;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StGeotileLicenseIT extends SpatialGridLicenseTestCase {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialPlugin.class, EsqlPluginWithEnterpriseOrTrialLicense.class);
+    }
+
+    @Override
+    protected String gridFunction() {
+        return "ST_GEOTILE";
+    }
+
+    @Override
+    protected Map<Long, Long> expectedValues() {
+        Map<Long, Long> expected = new HashMap<>();
+        for (Point point : testData) {
+            long gridId = StGeotile.unboundedGrid.calculateGridId(point, precision());
+            expected.compute(gridId, (k, v) -> v == null ? 1 : v + 1);
+        }
+        return expected;
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFromIndex("index_geo_shape");
+    }
+}

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

@@ -0,0 +1,24 @@
+/*
+ * 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.plugins.Plugin;
+
+import java.util.Collection;
+import java.util.List;
+
+public class StGeotileNoLicenseIT extends StGeotileLicenseIT {
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(SpatialNoLicenseTestCase.TestSpatialPlugin.class, SpatialNoLicenseTestCase.TestEsqlPlugin.class);
+    }
+
+    public void testGeoGridWithShapes() {
+        assertGeoGridFailsWith("index_geo_shape");
+    }
+}

+ 119 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldAndLiteralAndLiteralEvaluator.java

@@ -0,0 +1,119 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohash}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohashFromFieldAndLiteralAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator in;
+
+  private final StGeohash.GeoHashBoundedGrid bounds;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohashFromFieldAndLiteralAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator in, StGeohash.GeoHashBoundedGrid bounds,
+      DriverContext driverContext) {
+    this.source = source;
+    this.in = in;
+    this.bounds = bounds;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (BytesRefBlock inBlock = (BytesRefBlock) in.eval(page)) {
+      return eval(page.getPositionCount(), inBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, BytesRefBlock inBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!inBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohash.fromFieldAndLiteralAndLiteral(result, p, inBlock, this.bounds);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashFromFieldAndLiteralAndLiteralEvaluator[" + "in=" + in + ", bounds=" + bounds + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(in);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory in;
+
+    private final StGeohash.GeoHashBoundedGrid bounds;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory in,
+        StGeohash.GeoHashBoundedGrid bounds) {
+      this.source = source;
+      this.in = in;
+      this.bounds = bounds;
+    }
+
+    @Override
+    public StGeohashFromFieldAndLiteralAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohashFromFieldAndLiteralAndLiteralEvaluator(source, in.get(context), bounds, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashFromFieldAndLiteralAndLiteralEvaluator[" + "in=" + in + ", bounds=" + bounds + "]";
+    }
+  }
+}

+ 118 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldAndLiteralEvaluator.java

@@ -0,0 +1,118 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohash}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohashFromFieldAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator wkbBlock;
+
+  private final int precision;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohashFromFieldAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator wkbBlock, int precision, DriverContext driverContext) {
+    this.source = source;
+    this.wkbBlock = wkbBlock;
+    this.precision = precision;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (BytesRefBlock wkbBlockBlock = (BytesRefBlock) wkbBlock.eval(page)) {
+      return eval(page.getPositionCount(), wkbBlockBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, BytesRefBlock wkbBlockBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!wkbBlockBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohash.fromFieldAndLiteral(result, p, wkbBlockBlock, this.precision);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashFromFieldAndLiteralEvaluator[" + "wkbBlock=" + wkbBlock + ", precision=" + precision + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(wkbBlock);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory wkbBlock;
+
+    private final int precision;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory wkbBlock,
+        int precision) {
+      this.source = source;
+      this.wkbBlock = wkbBlock;
+      this.precision = precision;
+    }
+
+    @Override
+    public StGeohashFromFieldAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohashFromFieldAndLiteralEvaluator(source, wkbBlock.get(context), precision, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashFromFieldAndLiteralEvaluator[" + "wkbBlock=" + wkbBlock + ", precision=" + precision + "]";
+    }
+  }
+}

+ 118 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator.java

@@ -0,0 +1,118 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohash}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator encoded;
+
+  private final StGeohash.GeoHashBoundedGrid bounds;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator encoded, StGeohash.GeoHashBoundedGrid bounds,
+      DriverContext driverContext) {
+    this.source = source;
+    this.encoded = encoded;
+    this.bounds = bounds;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (LongBlock encodedBlock = (LongBlock) encoded.eval(page)) {
+      return eval(page.getPositionCount(), encodedBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, LongBlock encodedBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!encodedBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohash.fromFieldDocValuesAndLiteralAndLiteral(result, p, encodedBlock, this.bounds);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator[" + "encoded=" + encoded + ", bounds=" + bounds + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(encoded);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory encoded;
+
+    private final StGeohash.GeoHashBoundedGrid bounds;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory encoded,
+        StGeohash.GeoHashBoundedGrid bounds) {
+      this.source = source;
+      this.encoded = encoded;
+      this.bounds = bounds;
+    }
+
+    @Override
+    public StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator(source, encoded.get(context), bounds, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashFromFieldDocValuesAndLiteralAndLiteralEvaluator[" + "encoded=" + encoded + ", bounds=" + bounds + "]";
+    }
+  }
+}

+ 116 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashFromFieldDocValuesAndLiteralEvaluator.java

@@ -0,0 +1,116 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohash}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohashFromFieldDocValuesAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator encoded;
+
+  private final int precision;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohashFromFieldDocValuesAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator encoded, int precision, DriverContext driverContext) {
+    this.source = source;
+    this.encoded = encoded;
+    this.precision = precision;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (LongBlock encodedBlock = (LongBlock) encoded.eval(page)) {
+      return eval(page.getPositionCount(), encodedBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, LongBlock encodedBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!encodedBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohash.fromFieldDocValuesAndLiteral(result, p, encodedBlock, this.precision);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashFromFieldDocValuesAndLiteralEvaluator[" + "encoded=" + encoded + ", precision=" + precision + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(encoded);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory encoded;
+
+    private final int precision;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory encoded, int precision) {
+      this.source = source;
+      this.encoded = encoded;
+      this.precision = precision;
+    }
+
+    @Override
+    public StGeohashFromFieldDocValuesAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohashFromFieldDocValuesAndLiteralEvaluator(source, encoded.get(context), precision, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashFromFieldDocValuesAndLiteralEvaluator[" + "encoded=" + encoded + ", precision=" + precision + "]";
+    }
+  }
+}

+ 126 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashToLongFromStringEvaluator.java

@@ -0,0 +1,126 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.BytesRefVector;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Vector;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohashToLong}.
+ * This class is generated. Edit {@code ConvertEvaluatorImplementer} instead.
+ */
+public final class StGeohashToLongFromStringEvaluator extends AbstractConvertFunction.AbstractEvaluator {
+  private final EvalOperator.ExpressionEvaluator gridId;
+
+  public StGeohashToLongFromStringEvaluator(Source source, EvalOperator.ExpressionEvaluator gridId,
+      DriverContext driverContext) {
+    super(driverContext, source);
+    this.gridId = gridId;
+  }
+
+  @Override
+  public EvalOperator.ExpressionEvaluator next() {
+    return gridId;
+  }
+
+  @Override
+  public Block evalVector(Vector v) {
+    BytesRefVector vector = (BytesRefVector) v;
+    int positionCount = v.getPositionCount();
+    BytesRef scratchPad = new BytesRef();
+    if (vector.isConstant()) {
+      return driverContext.blockFactory().newConstantLongBlockWith(evalValue(vector, 0, scratchPad), positionCount);
+    }
+    try (LongBlock.Builder builder = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      for (int p = 0; p < positionCount; p++) {
+        builder.appendLong(evalValue(vector, p, scratchPad));
+      }
+      return builder.build();
+    }
+  }
+
+  private long evalValue(BytesRefVector container, int index, BytesRef scratchPad) {
+    BytesRef value = container.getBytesRef(index, scratchPad);
+    return StGeohashToLong.fromString(value);
+  }
+
+  @Override
+  public Block evalBlock(Block b) {
+    BytesRefBlock block = (BytesRefBlock) b;
+    int positionCount = block.getPositionCount();
+    try (LongBlock.Builder builder = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      BytesRef scratchPad = new BytesRef();
+      for (int p = 0; p < positionCount; p++) {
+        int valueCount = block.getValueCount(p);
+        int start = block.getFirstValueIndex(p);
+        int end = start + valueCount;
+        boolean positionOpened = false;
+        boolean valuesAppended = false;
+        for (int i = start; i < end; i++) {
+          long value = evalValue(block, i, scratchPad);
+          if (positionOpened == false && valueCount > 1) {
+            builder.beginPositionEntry();
+            positionOpened = true;
+          }
+          builder.appendLong(value);
+          valuesAppended = true;
+        }
+        if (valuesAppended == false) {
+          builder.appendNull();
+        } else if (positionOpened) {
+          builder.endPositionEntry();
+        }
+      }
+      return builder.build();
+    }
+  }
+
+  private long evalValue(BytesRefBlock container, int index, BytesRef scratchPad) {
+    BytesRef value = container.getBytesRef(index, scratchPad);
+    return StGeohashToLong.fromString(value);
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashToLongFromStringEvaluator[" + "gridId=" + gridId + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(gridId);
+  }
+
+  public static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory gridId;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory gridId) {
+      this.source = source;
+      this.gridId = gridId;
+    }
+
+    @Override
+    public StGeohashToLongFromStringEvaluator get(DriverContext context) {
+      return new StGeohashToLongFromStringEvaluator(source, gridId.get(context), context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashToLongFromStringEvaluator[" + "gridId=" + gridId + "]";
+    }
+  }
+}

+ 124 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohashToStringFromLongEvaluator.java

@@ -0,0 +1,124 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.LongVector;
+import org.elasticsearch.compute.data.Vector;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohashToString}.
+ * This class is generated. Edit {@code ConvertEvaluatorImplementer} instead.
+ */
+public final class StGeohashToStringFromLongEvaluator extends AbstractConvertFunction.AbstractEvaluator {
+  private final EvalOperator.ExpressionEvaluator gridId;
+
+  public StGeohashToStringFromLongEvaluator(Source source, EvalOperator.ExpressionEvaluator gridId,
+      DriverContext driverContext) {
+    super(driverContext, source);
+    this.gridId = gridId;
+  }
+
+  @Override
+  public EvalOperator.ExpressionEvaluator next() {
+    return gridId;
+  }
+
+  @Override
+  public Block evalVector(Vector v) {
+    LongVector vector = (LongVector) v;
+    int positionCount = v.getPositionCount();
+    if (vector.isConstant()) {
+      return driverContext.blockFactory().newConstantBytesRefBlockWith(evalValue(vector, 0), positionCount);
+    }
+    try (BytesRefBlock.Builder builder = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) {
+      for (int p = 0; p < positionCount; p++) {
+        builder.appendBytesRef(evalValue(vector, p));
+      }
+      return builder.build();
+    }
+  }
+
+  private BytesRef evalValue(LongVector container, int index) {
+    long value = container.getLong(index);
+    return StGeohashToString.fromLong(value);
+  }
+
+  @Override
+  public Block evalBlock(Block b) {
+    LongBlock block = (LongBlock) b;
+    int positionCount = block.getPositionCount();
+    try (BytesRefBlock.Builder builder = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) {
+      for (int p = 0; p < positionCount; p++) {
+        int valueCount = block.getValueCount(p);
+        int start = block.getFirstValueIndex(p);
+        int end = start + valueCount;
+        boolean positionOpened = false;
+        boolean valuesAppended = false;
+        for (int i = start; i < end; i++) {
+          BytesRef value = evalValue(block, i);
+          if (positionOpened == false && valueCount > 1) {
+            builder.beginPositionEntry();
+            positionOpened = true;
+          }
+          builder.appendBytesRef(value);
+          valuesAppended = true;
+        }
+        if (valuesAppended == false) {
+          builder.appendNull();
+        } else if (positionOpened) {
+          builder.endPositionEntry();
+        }
+      }
+      return builder.build();
+    }
+  }
+
+  private BytesRef evalValue(LongBlock container, int index) {
+    long value = container.getLong(index);
+    return StGeohashToString.fromLong(value);
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohashToStringFromLongEvaluator[" + "gridId=" + gridId + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(gridId);
+  }
+
+  public static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory gridId;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory gridId) {
+      this.source = source;
+      this.gridId = gridId;
+    }
+
+    @Override
+    public StGeohashToStringFromLongEvaluator get(DriverContext context) {
+      return new StGeohashToStringFromLongEvaluator(source, gridId.get(context), context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohashToStringFromLongEvaluator[" + "gridId=" + gridId + "]";
+    }
+  }
+}

+ 119 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldAndLiteralAndLiteralEvaluator.java

@@ -0,0 +1,119 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohex}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohexFromFieldAndLiteralAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator in;
+
+  private final StGeohex.GeoHexBoundedGrid bounds;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohexFromFieldAndLiteralAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator in, StGeohex.GeoHexBoundedGrid bounds,
+      DriverContext driverContext) {
+    this.source = source;
+    this.in = in;
+    this.bounds = bounds;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (BytesRefBlock inBlock = (BytesRefBlock) in.eval(page)) {
+      return eval(page.getPositionCount(), inBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, BytesRefBlock inBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!inBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohex.fromFieldAndLiteralAndLiteral(result, p, inBlock, this.bounds);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohexFromFieldAndLiteralAndLiteralEvaluator[" + "in=" + in + ", bounds=" + bounds + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(in);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory in;
+
+    private final StGeohex.GeoHexBoundedGrid bounds;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory in,
+        StGeohex.GeoHexBoundedGrid bounds) {
+      this.source = source;
+      this.in = in;
+      this.bounds = bounds;
+    }
+
+    @Override
+    public StGeohexFromFieldAndLiteralAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohexFromFieldAndLiteralAndLiteralEvaluator(source, in.get(context), bounds, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohexFromFieldAndLiteralAndLiteralEvaluator[" + "in=" + in + ", bounds=" + bounds + "]";
+    }
+  }
+}

+ 118 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldAndLiteralEvaluator.java

@@ -0,0 +1,118 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohex}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohexFromFieldAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator wkbBlock;
+
+  private final int precision;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohexFromFieldAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator wkbBlock, int precision, DriverContext driverContext) {
+    this.source = source;
+    this.wkbBlock = wkbBlock;
+    this.precision = precision;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (BytesRefBlock wkbBlockBlock = (BytesRefBlock) wkbBlock.eval(page)) {
+      return eval(page.getPositionCount(), wkbBlockBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, BytesRefBlock wkbBlockBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!wkbBlockBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohex.fromFieldAndLiteral(result, p, wkbBlockBlock, this.precision);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohexFromFieldAndLiteralEvaluator[" + "wkbBlock=" + wkbBlock + ", precision=" + precision + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(wkbBlock);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory wkbBlock;
+
+    private final int precision;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory wkbBlock,
+        int precision) {
+      this.source = source;
+      this.wkbBlock = wkbBlock;
+      this.precision = precision;
+    }
+
+    @Override
+    public StGeohexFromFieldAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohexFromFieldAndLiteralEvaluator(source, wkbBlock.get(context), precision, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohexFromFieldAndLiteralEvaluator[" + "wkbBlock=" + wkbBlock + ", precision=" + precision + "]";
+    }
+  }
+}

+ 118 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator.java

@@ -0,0 +1,118 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohex}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator encoded;
+
+  private final StGeohex.GeoHexBoundedGrid bounds;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator encoded, StGeohex.GeoHexBoundedGrid bounds,
+      DriverContext driverContext) {
+    this.source = source;
+    this.encoded = encoded;
+    this.bounds = bounds;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (LongBlock encodedBlock = (LongBlock) encoded.eval(page)) {
+      return eval(page.getPositionCount(), encodedBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, LongBlock encodedBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!encodedBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohex.fromFieldDocValuesAndLiteralAndLiteral(result, p, encodedBlock, this.bounds);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator[" + "encoded=" + encoded + ", bounds=" + bounds + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(encoded);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory encoded;
+
+    private final StGeohex.GeoHexBoundedGrid bounds;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory encoded,
+        StGeohex.GeoHexBoundedGrid bounds) {
+      this.source = source;
+      this.encoded = encoded;
+      this.bounds = bounds;
+    }
+
+    @Override
+    public StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator(source, encoded.get(context), bounds, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohexFromFieldDocValuesAndLiteralAndLiteralEvaluator[" + "encoded=" + encoded + ", bounds=" + bounds + "]";
+    }
+  }
+}

+ 116 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexFromFieldDocValuesAndLiteralEvaluator.java

@@ -0,0 +1,116 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+import java.lang.String;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.compute.operator.Warnings;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohex}.
+ * This class is generated. Edit {@code EvaluatorImplementer} instead.
+ */
+public final class StGeohexFromFieldDocValuesAndLiteralEvaluator implements EvalOperator.ExpressionEvaluator {
+  private final Source source;
+
+  private final EvalOperator.ExpressionEvaluator encoded;
+
+  private final int precision;
+
+  private final DriverContext driverContext;
+
+  private Warnings warnings;
+
+  public StGeohexFromFieldDocValuesAndLiteralEvaluator(Source source,
+      EvalOperator.ExpressionEvaluator encoded, int precision, DriverContext driverContext) {
+    this.source = source;
+    this.encoded = encoded;
+    this.precision = precision;
+    this.driverContext = driverContext;
+  }
+
+  @Override
+  public Block eval(Page page) {
+    try (LongBlock encodedBlock = (LongBlock) encoded.eval(page)) {
+      return eval(page.getPositionCount(), encodedBlock);
+    }
+  }
+
+  public LongBlock eval(int positionCount, LongBlock encodedBlock) {
+    try(LongBlock.Builder result = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      position: for (int p = 0; p < positionCount; p++) {
+        boolean allBlocksAreNulls = true;
+        if (!encodedBlock.isNull(p)) {
+          allBlocksAreNulls = false;
+        }
+        if (allBlocksAreNulls) {
+          result.appendNull();
+          continue position;
+        }
+        try {
+          StGeohex.fromFieldDocValuesAndLiteral(result, p, encodedBlock, this.precision);
+        } catch (IllegalArgumentException e) {
+          warnings().registerException(e);
+          result.appendNull();
+        }
+      }
+      return result.build();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohexFromFieldDocValuesAndLiteralEvaluator[" + "encoded=" + encoded + ", precision=" + precision + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(encoded);
+  }
+
+  private Warnings warnings() {
+    if (warnings == null) {
+      this.warnings = Warnings.createWarnings(
+              driverContext.warningsMode(),
+              source.source().getLineNumber(),
+              source.source().getColumnNumber(),
+              source.text()
+          );
+    }
+    return warnings;
+  }
+
+  static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory encoded;
+
+    private final int precision;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory encoded, int precision) {
+      this.source = source;
+      this.encoded = encoded;
+      this.precision = precision;
+    }
+
+    @Override
+    public StGeohexFromFieldDocValuesAndLiteralEvaluator get(DriverContext context) {
+      return new StGeohexFromFieldDocValuesAndLiteralEvaluator(source, encoded.get(context), precision, context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohexFromFieldDocValuesAndLiteralEvaluator[" + "encoded=" + encoded + ", precision=" + precision + "]";
+    }
+  }
+}

+ 126 - 0
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StGeohexToLongFromStringEvaluator.java

@@ -0,0 +1,126 @@
+// 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.expression.function.scalar.spatial;
+
+import java.lang.Override;
+import java.lang.String;
+import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.compute.data.BytesRefVector;
+import org.elasticsearch.compute.data.LongBlock;
+import org.elasticsearch.compute.data.Vector;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
+
+/**
+ * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StGeohexToLong}.
+ * This class is generated. Edit {@code ConvertEvaluatorImplementer} instead.
+ */
+public final class StGeohexToLongFromStringEvaluator extends AbstractConvertFunction.AbstractEvaluator {
+  private final EvalOperator.ExpressionEvaluator gridId;
+
+  public StGeohexToLongFromStringEvaluator(Source source, EvalOperator.ExpressionEvaluator gridId,
+      DriverContext driverContext) {
+    super(driverContext, source);
+    this.gridId = gridId;
+  }
+
+  @Override
+  public EvalOperator.ExpressionEvaluator next() {
+    return gridId;
+  }
+
+  @Override
+  public Block evalVector(Vector v) {
+    BytesRefVector vector = (BytesRefVector) v;
+    int positionCount = v.getPositionCount();
+    BytesRef scratchPad = new BytesRef();
+    if (vector.isConstant()) {
+      return driverContext.blockFactory().newConstantLongBlockWith(evalValue(vector, 0, scratchPad), positionCount);
+    }
+    try (LongBlock.Builder builder = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      for (int p = 0; p < positionCount; p++) {
+        builder.appendLong(evalValue(vector, p, scratchPad));
+      }
+      return builder.build();
+    }
+  }
+
+  private long evalValue(BytesRefVector container, int index, BytesRef scratchPad) {
+    BytesRef value = container.getBytesRef(index, scratchPad);
+    return StGeohexToLong.fromString(value);
+  }
+
+  @Override
+  public Block evalBlock(Block b) {
+    BytesRefBlock block = (BytesRefBlock) b;
+    int positionCount = block.getPositionCount();
+    try (LongBlock.Builder builder = driverContext.blockFactory().newLongBlockBuilder(positionCount)) {
+      BytesRef scratchPad = new BytesRef();
+      for (int p = 0; p < positionCount; p++) {
+        int valueCount = block.getValueCount(p);
+        int start = block.getFirstValueIndex(p);
+        int end = start + valueCount;
+        boolean positionOpened = false;
+        boolean valuesAppended = false;
+        for (int i = start; i < end; i++) {
+          long value = evalValue(block, i, scratchPad);
+          if (positionOpened == false && valueCount > 1) {
+            builder.beginPositionEntry();
+            positionOpened = true;
+          }
+          builder.appendLong(value);
+          valuesAppended = true;
+        }
+        if (valuesAppended == false) {
+          builder.appendNull();
+        } else if (positionOpened) {
+          builder.endPositionEntry();
+        }
+      }
+      return builder.build();
+    }
+  }
+
+  private long evalValue(BytesRefBlock container, int index, BytesRef scratchPad) {
+    BytesRef value = container.getBytesRef(index, scratchPad);
+    return StGeohexToLong.fromString(value);
+  }
+
+  @Override
+  public String toString() {
+    return "StGeohexToLongFromStringEvaluator[" + "gridId=" + gridId + "]";
+  }
+
+  @Override
+  public void close() {
+    Releasables.closeExpectNoException(gridId);
+  }
+
+  public static class Factory implements EvalOperator.ExpressionEvaluator.Factory {
+    private final Source source;
+
+    private final EvalOperator.ExpressionEvaluator.Factory gridId;
+
+    public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory gridId) {
+      this.source = source;
+      this.gridId = gridId;
+    }
+
+    @Override
+    public StGeohexToLongFromStringEvaluator get(DriverContext context) {
+      return new StGeohexToLongFromStringEvaluator(source, gridId.get(context), context);
+    }
+
+    @Override
+    public String toString() {
+      return "StGeohexToLongFromStringEvaluator[" + "gridId=" + gridId + "]";
+    }
+  }
+}

部分文件因文件數量過多而無法顯示