Skip to content

Commit f2d594d

Browse files
uros-dbdongjoon-hyun
authored andcommitted
[SPARK-54243][SQL] Introduce type coercion support for GEOGRAPHY data types
### What changes were proposed in this pull request? Implement least common type (LCT) logic for `GEOGRAPHY` types, as follows: - LCT for GeographyType(`srid_1`) and GeographyType(`srid_1`) is: GeographyType(`srid_1`) - LCT for GeographyType(`srid_1`) and GeographyType(`srid_2`) is: GeographyType(`ANY`) - LCT for GeographyType(`srid_1`) and GeographyType(`ANY`) is: GeographyType(`ANY`) - LCT for GeographyType(`ANY`) and GeographyType(`ANY`) is: GeographyType(`ANY`) In other words, the mixed SRID `GEOGRAPHY` type is the *common type* for all GEOGRAPHY types. ### Why are the changes needed? Introducing LCT and type coercion logic in the geospatial data type system. ### Does this PR introduce _any_ user-facing change? Yes, type coercion is now supported for `GeographyType`. ### How was this patch tested? Added tests for geography type coercion: - `AnsiTypeCoercionSuite` - `TypeCoercionSuite` Added appropriate Scala suite unit tests: - `STExpressionsSuite` Added appropriate end-to-end SQL tests: - `st-functions` ### Was this patch authored or co-authored using generative AI tooling? No. Closes #52944 from uros-db/geo-coercion-geog. Authored-by: Uros Bojanic <[email protected]> Signed-off-by: Dongjoon Hyun <[email protected]>
1 parent a32559a commit f2d594d

File tree

10 files changed

+498
-0
lines changed

10 files changed

+498
-0
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercion.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ object AnsiTypeCoercion extends TypeCoercionBase {
130130
case (t1: YearMonthIntervalType, t2: YearMonthIntervalType) =>
131131
Some(YearMonthIntervalType(t1.startField.min(t2.startField), t1.endField.max(t2.endField)))
132132

133+
// We allow coercion from GEOGRAPHY(<srid>) types (i.e. fixed SRID types) to the
134+
// GEOGRAPHY(ANY) type (i.e. mixed SRID type). This coercion is always safe to do.
135+
case (t1: GeographyType, t2: GeographyType) if t1 != t2 => Some(GeographyType("ANY"))
136+
133137
case (t1, t2) => findTypeForComplex(t1, t2, findTightestCommonType)
134138
}
135139

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ object TypeCoercion extends TypeCoercionBase {
9898
case (t1: YearMonthIntervalType, t2: YearMonthIntervalType) =>
9999
Some(YearMonthIntervalType(t1.startField.min(t2.startField), t1.endField.max(t2.endField)))
100100

101+
// We allow coercion from GEOGRAPHY(<srid>) types (i.e. fixed SRID types) to the
102+
// GEOGRAPHY(ANY) type (i.e. mixed SRID type). This coercion is always safe to do.
103+
case (t1: GeographyType, t2: GeographyType) if t1 != t2 => Some(GeographyType("ANY"))
104+
101105
case (t1, t2) => findTypeForComplex(t1, t2, findTightestCommonType)
102106
}
103107

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercionSuite.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ class AnsiTypeCoercionSuite extends TypeCoercionSuiteBase {
174174
widenTest(FloatType, FloatType, Some(FloatType))
175175
widenTest(DoubleType, DoubleType, Some(DoubleType))
176176

177+
// Geography with same fixed SRIDs.
178+
widenTest(GeographyType(4326), GeographyType(4326), Some(GeographyType(4326)))
179+
// Geography with mixed SRIDs.
180+
widenTest(GeographyType("ANY"), GeographyType("ANY"), Some(GeographyType("ANY")))
181+
widenTest(GeographyType("ANY"), GeographyType(4326), Some(GeographyType("ANY")))
182+
widenTest(GeographyType(4326), GeographyType("ANY"), Some(GeographyType("ANY")))
183+
177184
// Integral mixed with floating point.
178185
widenTest(IntegerType, FloatType, Some(DoubleType))
179186
widenTest(IntegerType, DoubleType, Some(DoubleType))

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionSuite.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,13 @@ class TypeCoercionSuite extends TypeCoercionSuiteBase {
597597
widenTest(FloatType, FloatType, Some(FloatType))
598598
widenTest(DoubleType, DoubleType, Some(DoubleType))
599599

600+
// Geography with same fixed SRIDs.
601+
widenTest(GeographyType(4326), GeographyType(4326), Some(GeographyType(4326)))
602+
// Geography with mixed SRIDs.
603+
widenTest(GeographyType("ANY"), GeographyType("ANY"), Some(GeographyType("ANY")))
604+
widenTest(GeographyType("ANY"), GeographyType(4326), Some(GeographyType("ANY")))
605+
widenTest(GeographyType(4326), GeographyType("ANY"), Some(GeographyType("ANY")))
606+
600607
// Integral mixed with floating point.
601608
widenTest(IntegerType, FloatType, Some(FloatType))
602609
widenTest(IntegerType, DoubleType, Some(DoubleType))

sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/st-functions.sql.out

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,78 @@ org.apache.spark.sql.catalyst.ExtendedAnalysisException
153153
}
154154

155155

156+
-- !query
157+
SELECT typeof(array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
158+
-- !query analysis
159+
Project [typeof(array(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
160+
+- SubqueryAlias spark_catalog.default.geodata
161+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
162+
163+
164+
-- !query
165+
SELECT typeof(map('a', ST_GeogFromWKB(wkb), 'b', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
166+
-- !query analysis
167+
Project [typeof(map(a, cast(st_geogfromwkb(wkb#x) as geography(any)), b, cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(map(a, st_geogfromwkb(wkb), b, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
168+
+- SubqueryAlias spark_catalog.default.geodata
169+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
170+
171+
172+
-- !query
173+
SELECT typeof(array(named_struct('g1', ST_GeogFromWKB(wkb), 'g2', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), named_struct('g1', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), 'g2', ST_GeogFromWKB(wkb)))) FROM geodata
174+
-- !query analysis
175+
Project [typeof(array(cast(named_struct(g1, st_geogfromwkb(wkb#x), g2, cast(st_geogfromwkb(wkb#x) as geography(any))) as struct<g1:geography(any),g2:geography(any)>), cast(named_struct(g1, cast(st_geogfromwkb(wkb#x) as geography(any)), g2, st_geogfromwkb(wkb#x)) as struct<g1:geography(any),g2:geography(any)>))) AS typeof(array(named_struct(g1, st_geogfromwkb(wkb), g2, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), named_struct(g1, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), g2, st_geogfromwkb(wkb))))#x]
176+
+- SubqueryAlias spark_catalog.default.geodata
177+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
178+
179+
180+
-- !query
181+
SELECT typeof(named_struct('a', array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), 'b', map('g', ST_GeogFromWKB(wkb), 'h', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)))) FROM geodata
182+
-- !query analysis
183+
Project [typeof(named_struct(a, array(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any))), b, map(g, cast(st_geogfromwkb(wkb#x) as geography(any)), h, cast(st_geogfromwkb(wkb#x) as geography(any))))) AS typeof(named_struct(a, array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), b, map(g, st_geogfromwkb(wkb), h, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))))#x]
184+
+- SubqueryAlias spark_catalog.default.geodata
185+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
186+
187+
188+
-- !query
189+
SELECT typeof(nvl(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
190+
-- !query analysis
191+
Project [typeof(nvl(st_geogfromwkb(wkb#x), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(nvl(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
192+
+- SubqueryAlias spark_catalog.default.geodata
193+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
194+
195+
196+
-- !query
197+
SELECT typeof(nvl2(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
198+
-- !query analysis
199+
Project [typeof(nvl2(st_geogfromwkb(wkb#x), cast(st_geogfromwkb(wkb#x) as geography(any)), st_geogfromwkb(wkb#x))) AS typeof(nvl2(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb)))#x]
200+
+- SubqueryAlias spark_catalog.default.geodata
201+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
202+
203+
204+
-- !query
205+
SELECT typeof(CASE WHEN wkb IS NOT NULL THEN ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY) ELSE ST_GeogFromWKB(wkb) END) FROM geodata
206+
-- !query analysis
207+
Project [typeof(CASE WHEN isnotnull(wkb#x) THEN cast(st_geogfromwkb(wkb#x) as geography(any)) ELSE cast(st_geogfromwkb(wkb#x) as geography(any)) END) AS typeof(CASE WHEN (wkb IS NOT NULL) THEN CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)) ELSE st_geogfromwkb(wkb) END)#x]
208+
+- SubqueryAlias spark_catalog.default.geodata
209+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
210+
211+
212+
-- !query
213+
SELECT typeof(coalesce(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
214+
-- !query analysis
215+
Project [typeof(coalesce(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(coalesce(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
216+
+- SubqueryAlias spark_catalog.default.geodata
217+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
218+
219+
220+
-- !query
221+
SELECT typeof(IF(wkb IS NOT NULL, ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
222+
-- !query analysis
223+
Project [typeof(if (isnotnull(wkb#x)) cast(st_geogfromwkb(wkb#x) as geography(any)) else cast(st_geogfromwkb(wkb#x) as geography(any))) AS typeof((IF((wkb IS NOT NULL), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb))))#x]
224+
+- SubqueryAlias spark_catalog.default.geodata
225+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
226+
227+
156228
-- !query
157229
SELECT hex(ST_AsBinary(ST_GeogFromWKB(X'0101000000000000000000f03f0000000000000040'))) AS result
158230
-- !query analysis

sql/core/src/test/resources/sql-tests/analyzer-results/st-functions.sql.out

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,78 @@ org.apache.spark.sql.catalyst.ExtendedAnalysisException
153153
}
154154

155155

156+
-- !query
157+
SELECT typeof(array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
158+
-- !query analysis
159+
Project [typeof(array(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
160+
+- SubqueryAlias spark_catalog.default.geodata
161+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
162+
163+
164+
-- !query
165+
SELECT typeof(map('a', ST_GeogFromWKB(wkb), 'b', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
166+
-- !query analysis
167+
Project [typeof(map(a, cast(st_geogfromwkb(wkb#x) as geography(any)), b, cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(map(a, st_geogfromwkb(wkb), b, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
168+
+- SubqueryAlias spark_catalog.default.geodata
169+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
170+
171+
172+
-- !query
173+
SELECT typeof(array(named_struct('g1', ST_GeogFromWKB(wkb), 'g2', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), named_struct('g1', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), 'g2', ST_GeogFromWKB(wkb)))) FROM geodata
174+
-- !query analysis
175+
Project [typeof(array(cast(named_struct(g1, st_geogfromwkb(wkb#x), g2, cast(st_geogfromwkb(wkb#x) as geography(any))) as struct<g1:geography(any),g2:geography(any)>), cast(named_struct(g1, cast(st_geogfromwkb(wkb#x) as geography(any)), g2, st_geogfromwkb(wkb#x)) as struct<g1:geography(any),g2:geography(any)>))) AS typeof(array(named_struct(g1, st_geogfromwkb(wkb), g2, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), named_struct(g1, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), g2, st_geogfromwkb(wkb))))#x]
176+
+- SubqueryAlias spark_catalog.default.geodata
177+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
178+
179+
180+
-- !query
181+
SELECT typeof(named_struct('a', array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), 'b', map('g', ST_GeogFromWKB(wkb), 'h', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)))) FROM geodata
182+
-- !query analysis
183+
Project [typeof(named_struct(a, array(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any))), b, map(g, cast(st_geogfromwkb(wkb#x) as geography(any)), h, cast(st_geogfromwkb(wkb#x) as geography(any))))) AS typeof(named_struct(a, array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), b, map(g, st_geogfromwkb(wkb), h, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))))#x]
184+
+- SubqueryAlias spark_catalog.default.geodata
185+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
186+
187+
188+
-- !query
189+
SELECT typeof(nvl(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
190+
-- !query analysis
191+
Project [typeof(nvl(st_geogfromwkb(wkb#x), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(nvl(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
192+
+- SubqueryAlias spark_catalog.default.geodata
193+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
194+
195+
196+
-- !query
197+
SELECT typeof(nvl2(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
198+
-- !query analysis
199+
Project [typeof(nvl2(st_geogfromwkb(wkb#x), cast(st_geogfromwkb(wkb#x) as geography(any)), st_geogfromwkb(wkb#x))) AS typeof(nvl2(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb)))#x]
200+
+- SubqueryAlias spark_catalog.default.geodata
201+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
202+
203+
204+
-- !query
205+
SELECT typeof(CASE WHEN wkb IS NOT NULL THEN ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY) ELSE ST_GeogFromWKB(wkb) END) FROM geodata
206+
-- !query analysis
207+
Project [typeof(CASE WHEN isnotnull(wkb#x) THEN cast(st_geogfromwkb(wkb#x) as geography(any)) ELSE cast(st_geogfromwkb(wkb#x) as geography(any)) END) AS typeof(CASE WHEN (wkb IS NOT NULL) THEN CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)) ELSE st_geogfromwkb(wkb) END)#x]
208+
+- SubqueryAlias spark_catalog.default.geodata
209+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
210+
211+
212+
-- !query
213+
SELECT typeof(coalesce(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
214+
-- !query analysis
215+
Project [typeof(coalesce(cast(st_geogfromwkb(wkb#x) as geography(any)), cast(st_geogfromwkb(wkb#x) as geography(any)))) AS typeof(coalesce(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))#x]
216+
+- SubqueryAlias spark_catalog.default.geodata
217+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
218+
219+
220+
-- !query
221+
SELECT typeof(IF(wkb IS NOT NULL, ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
222+
-- !query analysis
223+
Project [typeof(if (isnotnull(wkb#x)) cast(st_geogfromwkb(wkb#x) as geography(any)) else cast(st_geogfromwkb(wkb#x) as geography(any))) AS typeof((IF((wkb IS NOT NULL), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb))))#x]
224+
+- SubqueryAlias spark_catalog.default.geodata
225+
+- Relation spark_catalog.default.geodata[wkb#x] parquet
226+
227+
156228
-- !query
157229
SELECT hex(ST_AsBinary(ST_GeogFromWKB(X'0101000000000000000000f03f0000000000000040'))) AS result
158230
-- !query analysis

sql/core/src/test/resources/sql-tests/inputs/st-functions.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ SELECT hex(ST_AsBinary(CAST(ST_GeomFromWKB(X'0101000000000000000000f03f000000000
2828
-- Casting GEOMETRY(ANY) to GEOMETRY(<srid>) is not allowed.
2929
SELECT CAST(ST_GeomFromWKB(X'0101000000000000000000f03f0000000000000040')::GEOMETRY(ANY) AS GEOMETRY(4326)) AS result;
3030

31+
---- Geospatial type coercion
32+
33+
-- Array
34+
SELECT typeof(array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata;
35+
-- Map
36+
SELECT typeof(map('a', ST_GeogFromWKB(wkb), 'b', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata;
37+
-- Struct
38+
SELECT typeof(array(named_struct('g1', ST_GeogFromWKB(wkb), 'g2', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), named_struct('g1', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), 'g2', ST_GeogFromWKB(wkb)))) FROM geodata;
39+
-- Nested
40+
SELECT typeof(named_struct('a', array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), 'b', map('g', ST_GeogFromWKB(wkb), 'h', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)))) FROM geodata;
41+
42+
-- NVL
43+
SELECT typeof(nvl(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata;
44+
-- NVL2
45+
SELECT typeof(nvl2(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata;
46+
-- CASE WHEN
47+
SELECT typeof(CASE WHEN wkb IS NOT NULL THEN ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY) ELSE ST_GeogFromWKB(wkb) END) FROM geodata;
48+
-- COALESCE
49+
SELECT typeof(coalesce(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata;
50+
-- IF
51+
SELECT typeof(IF(wkb IS NOT NULL, ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata;
52+
3153
---- ST reader/writer expressions
3254

3355
-- WKB (Well-Known Binary) round-trip tests for GEOGRAPHY and GEOMETRY types.

sql/core/src/test/resources/sql-tests/results/nonansi/st-functions.sql.out

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,87 @@ org.apache.spark.sql.catalyst.ExtendedAnalysisException
169169
}
170170

171171

172+
-- !query
173+
SELECT typeof(array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
174+
-- !query schema
175+
struct<typeof(array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))):string>
176+
-- !query output
177+
array<geography(any)>
178+
array<geography(any)>
179+
180+
181+
-- !query
182+
SELECT typeof(map('a', ST_GeogFromWKB(wkb), 'b', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
183+
-- !query schema
184+
struct<typeof(map(a, st_geogfromwkb(wkb), b, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))):string>
185+
-- !query output
186+
map<string,geography(any)>
187+
map<string,geography(any)>
188+
189+
190+
-- !query
191+
SELECT typeof(array(named_struct('g1', ST_GeogFromWKB(wkb), 'g2', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), named_struct('g1', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), 'g2', ST_GeogFromWKB(wkb)))) FROM geodata
192+
-- !query schema
193+
struct<typeof(array(named_struct(g1, st_geogfromwkb(wkb), g2, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), named_struct(g1, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), g2, st_geogfromwkb(wkb)))):string>
194+
-- !query output
195+
array<struct<g1:geography(any),g2:geography(any)>>
196+
array<struct<g1:geography(any),g2:geography(any)>>
197+
198+
199+
-- !query
200+
SELECT typeof(named_struct('a', array(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)), 'b', map('g', ST_GeogFromWKB(wkb), 'h', ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY)))) FROM geodata
201+
-- !query schema
202+
struct<typeof(named_struct(a, array(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))), b, map(g, st_geogfromwkb(wkb), h, CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY))))):string>
203+
-- !query output
204+
struct<a:array<geography(any)>,b:map<string,geography(any)>>
205+
struct<a:array<geography(any)>,b:map<string,geography(any)>>
206+
207+
208+
-- !query
209+
SELECT typeof(nvl(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
210+
-- !query schema
211+
struct<typeof(nvl(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))):string>
212+
-- !query output
213+
geography(any)
214+
geography(any)
215+
216+
217+
-- !query
218+
SELECT typeof(nvl2(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
219+
-- !query schema
220+
struct<typeof(nvl2(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb))):string>
221+
-- !query output
222+
geography(any)
223+
geography(any)
224+
225+
226+
-- !query
227+
SELECT typeof(CASE WHEN wkb IS NOT NULL THEN ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY) ELSE ST_GeogFromWKB(wkb) END) FROM geodata
228+
-- !query schema
229+
struct<typeof(CASE WHEN (wkb IS NOT NULL) THEN CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)) ELSE st_geogfromwkb(wkb) END):string>
230+
-- !query output
231+
geography(any)
232+
geography(any)
233+
234+
235+
-- !query
236+
SELECT typeof(coalesce(ST_GeogFromWKB(wkb), ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY))) FROM geodata
237+
-- !query schema
238+
struct<typeof(coalesce(st_geogfromwkb(wkb), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)))):string>
239+
-- !query output
240+
geography(any)
241+
geography(any)
242+
243+
244+
-- !query
245+
SELECT typeof(IF(wkb IS NOT NULL, ST_GeogFromWKB(wkb)::GEOGRAPHY(ANY), ST_GeogFromWKB(wkb))) FROM geodata
246+
-- !query schema
247+
struct<typeof((IF((wkb IS NOT NULL), CAST(st_geogfromwkb(wkb) AS GEOGRAPHY(ANY)), st_geogfromwkb(wkb)))):string>
248+
-- !query output
249+
geography(any)
250+
geography(any)
251+
252+
172253
-- !query
173254
SELECT hex(ST_AsBinary(ST_GeogFromWKB(X'0101000000000000000000f03f0000000000000040'))) AS result
174255
-- !query schema

0 commit comments

Comments
 (0)