You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@asterixdb.apache.org by AsterixDB Code Review <do...@asterix-gerrit.ics.uci.edu> on 2025/03/25 17:27:36 UTC

Change in asterixdb[master]: [ASTERIXDB-3542] Added Coordinate Reference System support - Added su...

From Suryaa Charan Shivakumar <ss...@ucr.edu>:

Suryaa Charan Shivakumar has uploaded this change for review. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19549 )


Change subject: [ASTERIXDB-3542] Added Coordinate Reference System support - Added support for storing SRID using Extended WKB (EWKB) format - Introduced ST_Transform(geometry, int) and ST_Transform(geometry, string, string)   to support CRS-aware transformations using Apache SIS - Updated existing spatial functions and internal logic to respect CRS metadata - Modified test cases to validate SRID preservation and transformations - Added script to download EPSG CRS dataset and initialize SIS_DATA directory - Updated startup scripts to set SIS_DATA for CRS support - Revised documentation to reflect CRS support, WKT usage, and transformation behavior
......................................................................

[ASTERIXDB-3542] Added Coordinate Reference System support
- Added support for storing SRID using Extended WKB (EWKB) format
- Introduced ST_Transform(geometry, int) and ST_Transform(geometry, string, string)
  to support CRS-aware transformations using Apache SIS
- Updated existing spatial functions and internal logic to respect CRS metadata
- Modified test cases to validate SRID preservation and transformations
- Added script to download EPSG CRS dataset and initialize SIS_DATA directory
- Updated startup scripts to set SIS_DATA for CRS support
- Revised documentation to reflect CRS support, WKT usage, and transformation behavior

Change-Id: Ia6e37080a581292744ddc9020b214936413c15ac
---
M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/AbstractFunctionDescriptor.java
M asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/GeoJsonConstants.java
A asterixdb/asterix-server/src/main/opt/local/bin/install-epsg-database.sh
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextSRIDDescriptor.java
M asterixdb/asterix-server/src/main/opt/ansible/yaml/start_cc.yml
M asterixdb/asterix-doc/src/site/markdown/geo/functions.md
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STAsBinaryDescriptor.java
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/index/result.20.adm
M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.10.adm
M asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/serde/GeometrySerializer.java
A asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoConstants.java
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.04.adm
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.04.adm
M asterixdb/asterix-doc/src/site/markdown/geo/quickstart.md
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DWithMDescriptor.java
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
M asterixdb/asterix-geo/pom.xml
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DDescriptor.java
A asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformWKTDescriptor.java
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTDoubleGeometryDescriptor.java
M asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/parsers/GenericGeometryParser.java
M asterixdb/pom.xml
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.05.adm
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.03.adm
A asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformDescriptor.java
M asterixdb/asterix-server/src/main/opt/ansible/yaml/start_ncservice.yml
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextDescriptor.java
M asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AGeometrySerializerDeserializer.java
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.07.adm
M asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.06.adm
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePointDescriptor.java
M asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakeEnvelopeDescriptorSRID.java
M asterixdb/asterix-server/src/main/opt/local/bin/start-sample-cluster.sh
35 files changed, 763 insertions(+), 100 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/49/19549/1

diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.03.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.03.adm
index 06c68c8..8169c3b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.03.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.03.adm
@@ -1,13 +1,13 @@
-{ "Geometries": { "id": 123, "myGeometry": {"type":"Point","coordinates":[-118.4,33.93]} } }
-{ "Geometries": { "id": 124, "myGeometry": {"type":"Polygon","coordinates":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]]} } }
-{ "Geometries": { "id": 126, "myGeometry": {"type":"LineString","coordinates":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]]} } }
-{ "Geometries": { "id": 127, "myGeometry": {"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]]} } }
-{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]]} } }
-{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]]} } }
-{ "Geometries": { "id": 130, "myGeometry": {"type":"Point","coordinates":[-71.1043443253471,42.3150676015829]} } }
-{ "Geometries": { "id": 131, "myGeometry": {"type":"Point","coordinates":[1,2,3]} } }
-{ "Geometries": { "id": 133, "myGeometry": {"type":"Polygon","coordinates":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]]} } }
-{ "Geometries": { "id": 134, "myGeometry": {"type":"LineString","coordinates":[[-113.98,39.198],[-113.981,39.195]]} } }
-{ "Geometries": { "id": 135, "myGeometry": {"type":"LineString","coordinates":[[1,2],[4,5],[7,8]]} } }
-{ "Geometries": { "id": 136, "myGeometry": {"type":"Polygon","coordinates":[[[10,10],[10,11],[11,11],[11,10],[10,10]]]} } }
-{ "Geometries": { "id": 137, "myGeometry": {"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]]} } }
+{ "Geometries": { "id": 123, "myGeometry": {"type":"Point","coordinates":[-118.4,33.93],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 124, "myGeometry": {"type":"Polygon","coordinates":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 126, "myGeometry": {"type":"LineString","coordinates":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 127, "myGeometry": {"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 130, "myGeometry": {"type":"Point","coordinates":[-71.1043443253471,42.3150676015829],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 131, "myGeometry": {"type":"Point","coordinates":[1,2,3],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 133, "myGeometry": {"type":"Polygon","coordinates":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 134, "myGeometry": {"type":"LineString","coordinates":[[-113.98,39.198],[-113.981,39.195]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 135, "myGeometry": {"type":"LineString","coordinates":[[1,2],[4,5],[7,8]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 136, "myGeometry": {"type":"Polygon","coordinates":[[[10,10],[10,11],[11,11],[11,10],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 137, "myGeometry": {"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.04.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.04.adm
index 688fcf1..c13ad78 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.04.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.04.adm
@@ -1,13 +1,13 @@
-{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 1, "XMax": -118.4, "XMin": -118.4, "YMax": 33.93, "YMin": 33.93, "Binary": hex("01010000009A99999999995DC0D7A3703D0AF74040"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[-118.4,33.93]}", "WKT": "POINT (-118.4 33.93)" }
-{ "Type": "Polygon", "Area": 1.3755215000294761E-8, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 6, "XMax": 8.760178, "XMin": 8.7599721, "YMax": 49.7103478, "YMin": 49.7102133, "Binary": hex("01030000000100000007000000B1BE26101B852140ED20C033EBDA4840C11DA8531E8521407694394CEADA4840BAF8DB9E20852140D5F89683EADA484098EF2AB5288521409557F844E8DA48400247020D3685214041F74086E9DA484014F131B32A8521408DE43CADECDA4840B1BE26101B852140ED20C033EBDA4840"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]]}", "WKT": "POLYGON ((8.7599721 49.7103028, 8.759997 49.7102752, 8.7600145 49.7102818, 8.7600762 49.7102133, 8.760178 49.7102516, 8.7600914 49.7103478, 8.7599721 49.7103028))" }
-{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 13, "XMax": -69.1972972, "XMin": -69.199136, "YMax": -12.5998133, "YMin": -12.6010968, "Binary": hex("01020000000D00000081BF4EA0BE4C51C0CE80C4C0843329C033DDEBA4BE4C51C0D388997D1E3329C064D7ACE9B04C51C05787927F1C3329C02347DF49B04C51C0B9C49107223329C0F4DCE79DAF4C51C054B76922223329C0184339D1AE4C51C042A89C40223329C048E17A14AE4C51C010DBCCD71B3329C007DB3E9AA04C51C0636996BA1A3329C0E9656F84A04C51C05ADD45F35B3329C04E9B711AA24C51C033373A42613329C06CE22E0CA24C51C066D24B31AC3329C05F454607A44C51C065170CAEB93329C07C8C03F9A34C51C0E475B3F5C23329C0"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]]}", "WKT": "LINESTRING (-69.1991349 -12.6006222, -69.199136 -12.599842, -69.1982979 -12.5998268, -69.1982598 -12.599869, -69.1982188 -12.5998698, -69.19817 -12.5998707, -69.198125 -12.5998218, -69.1973024 -12.5998133, -69.1972972 -12.6003109, -69.197394 -12.6003514, -69.1973906 -12.6009231, -69.1975115 -12.601026, -69.1975081 -12.6010968)" }
-{ "Type": "MultiPoint", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 4, "XMax": 40.0, "XMin": 10.0, "YMax": 40.0, "YMin": 10.0, "Binary": hex("010400000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003E4001010000000000000000003440000000000000344001010000000000000000003E400000000000002440"), "GeoJSON": "{\"type\":\"MultiPoint\",\"coordinates\":[[10,40],[40,30],[20,20],[30,10]]}", "WKT": "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" }
-{ "Type": "MultiLineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 7, "XMax": 40.0, "XMin": 10.0, "YMax": 40.0, "YMin": 10.0, "Binary": hex("010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003E400000000000003E40000000000000444000000000000034400000000000003E400000000000002440"), "GeoJSON": "{\"type\":\"MultiLineString\",\"coordinates\":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]]}", "WKT": "MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))" }
-{ "Type": "MultiPolygon", "Area": 712.5, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 11, "XMax": 45.0, "XMin": 10.0, "YMax": 45.0, "YMin": 5.0, "Binary": hex("01060000000200000001030000000100000004000000000000000000444000000000000044400000000000003440000000000080464000000000008046400000000000003E4000000000000044400000000000004440010300000002000000060000000000000000003440000000000080414000000000000024400000000000003E40000000000000244000000000000024400000000000003E4000000000000014400000000000804640000000000000344000000000000034400000000000804140040000000000000000003E40000000000000344000000000000034400000000000002E40000000000000344000000000000039400000000000003E400000000000003440"), "GeoJSON": "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]]}", "WKT": "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))" }
-{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 1, "XMax": -71.1043443253471, "XMin": -71.1043443253471, "YMax": 42.3150676015829, "YMin": 42.3150676015829, "Binary": hex("0101000000E538D293ADC651C0F3699A2254284540"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[-71.1043443253471,42.3150676015829]}", "WKT": "POINT (-71.1043443253471 42.3150676015829)" }
-{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 3, "Dimension": 0, "NPoints": 1, "XMax": 1.0, "XMin": 1.0, "YMax": 2.0, "YMin": 2.0, "Binary": hex("0101000080000000000000F03F00000000000000400000000000000840"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[1,2,3]}", "WKT": "POINT Z(1 2 3)" }
-{ "Type": "Polygon", "Area": 928.625, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 4, "XMax": 743265.625, "XMin": 743238.0, "YMax": 2967450.0, "YMin": 2967416.0, "Binary": hex("01030000000100000005000000000000008CAE264100000000BCA34641000000008CAE264100000000CDA3464100000000C2AE264100000000CDA3464100000040C3AE264100000000BCA34641000000008CAE264100000000BCA34641"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]]}", "WKT": "POLYGON ((743238 2967416, 743238 2967450, 743265 2967450, 743265.625 2967416, 743238 2967416))" }
-{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 2, "XMax": -113.98, "XMin": -113.981, "YMax": 39.198, "YMin": 39.195, "Binary": hex("0102000000020000001F85EB51B87E5CC0D34D621058994340105839B4C87E5CC0295C8FC2F5984340"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[-113.98,39.198],[-113.981,39.195]]}", "WKT": "LINESTRING (-113.98 39.198, -113.981 39.195)" }
-{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 3, "XMax": 7.0, "XMin": 1.0, "YMax": 8.0, "YMin": 2.0, "Binary": hex("010200000003000000000000000000F03F0000000000000040000000000000104000000000000014400000000000001C400000000000002040"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[1,2],[4,5],[7,8]]}", "WKT": "LINESTRING (1 2, 4 5, 7 8)" }
-{ "Type": "Polygon", "Area": 1.0, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 4, "XMax": 11.0, "XMin": 10.0, "YMax": 11.0, "YMin": 10.0, "Binary": hex("010300000001000000050000000000000000002440000000000000244000000000000024400000000000002640000000000000264000000000000026400000000000002640000000000000244000000000000024400000000000002440"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[10,10],[10,11],[11,11],[11,10],[10,10]]]}", "WKT": "POLYGON ((10 10, 10 11, 11 11, 11 10, 10 10))" }
-{ "Type": "Polygon", "Area": 675.0, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 7, "XMax": 45.0, "XMin": 10.0, "YMax": 45.0, "YMin": 10.0, "Binary": hex("0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002E40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003E40000000000080414000000000008041400000000000003E40000000000000344000000000000034400000000000003E40"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]]}", "WKT": "POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))" }
+{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 1, "XMax": -118.4, "XMin": -118.4, "YMax": 33.93, "YMin": 33.93, "Binary": hex("0101000020E61000009A99999999995DC0D7A3703D0AF74040"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[-118.4,33.93],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POINT (-118.4 33.93)" }
+{ "Type": "Polygon", "Area": 1.3755215000294761E-8, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 6, "XMax": 8.760178, "XMin": 8.7599721, "YMax": 49.7103478, "YMin": 49.7102133, "Binary": hex("0103000020E61000000100000007000000B1BE26101B852140ED20C033EBDA4840C11DA8531E8521407694394CEADA4840BAF8DB9E20852140D5F89683EADA484098EF2AB5288521409557F844E8DA48400247020D3685214041F74086E9DA484014F131B32A8521408DE43CADECDA4840B1BE26101B852140ED20C033EBDA4840"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POLYGON ((8.7599721 49.7103028, 8.759997 49.7102752, 8.7600145 49.7102818, 8.7600762 49.7102133, 8.760178 49.7102516, 8.7600914 49.7103478, 8.7599721 49.7103028))" }
+{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 13, "XMax": -69.1972972, "XMin": -69.199136, "YMax": -12.5998133, "YMin": -12.6010968, "Binary": hex("0102000020E61000000D00000081BF4EA0BE4C51C0CE80C4C0843329C033DDEBA4BE4C51C0D388997D1E3329C064D7ACE9B04C51C05787927F1C3329C02347DF49B04C51C0B9C49107223329C0F4DCE79DAF4C51C054B76922223329C0184339D1AE4C51C042A89C40223329C048E17A14AE4C51C010DBCCD71B3329C007DB3E9AA04C51C0636996BA1A3329C0E9656F84A04C51C05ADD45F35B3329C04E9B711AA24C51C033373A42613329C06CE22E0CA24C51C066D24B31AC3329C05F454607A44C51C065170CAEB93329C07C8C03F9A34C51C0E475B3F5C23329C0"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "LINESTRING (-69.1991349 -12.6006222, -69.199136 -12.599842, -69.1982979 -12.5998268, -69.1982598 -12.599869, -69.1982188 -12.5998698, -69.19817 -12.5998707, -69.198125 -12.5998218, -69.1973024 -12.5998133, -69.1972972 -12.6003109, -69.197394 -12.6003514, -69.1973906 -12.6009231, -69.1975115 -12.601026, -69.1975081 -12.6010968)" }
+{ "Type": "MultiPoint", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 4, "XMax": 40.0, "XMin": 10.0, "YMax": 40.0, "YMin": 10.0, "Binary": hex("0104000020E610000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003E4001010000000000000000003440000000000000344001010000000000000000003E400000000000002440"), "GeoJSON": "{\"type\":\"MultiPoint\",\"coordinates\":[[10,40],[40,30],[20,20],[30,10]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" }
+{ "Type": "MultiLineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 7, "XMax": 40.0, "XMin": 10.0, "YMax": 40.0, "YMin": 10.0, "Binary": hex("0105000020E610000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003E400000000000003E40000000000000444000000000000034400000000000003E400000000000002440"), "GeoJSON": "{\"type\":\"MultiLineString\",\"coordinates\":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))" }
+{ "Type": "MultiPolygon", "Area": 712.5, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 11, "XMax": 45.0, "XMin": 10.0, "YMax": 45.0, "YMin": 5.0, "Binary": hex("0106000020E61000000200000001030000000100000004000000000000000000444000000000000044400000000000003440000000000080464000000000008046400000000000003E4000000000000044400000000000004440010300000002000000060000000000000000003440000000000080414000000000000024400000000000003E40000000000000244000000000000024400000000000003E4000000000000014400000000000804640000000000000344000000000000034400000000000804140040000000000000000003E40000000000000344000000000000034400000000000002E40000000000000344000000000000039400000000000003E400000000000003440"), "GeoJSON": "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))" }
+{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 0, "NPoints": 1, "XMax": -71.1043443253471, "XMin": -71.1043443253471, "YMax": 42.3150676015829, "YMin": 42.3150676015829, "Binary": hex("0101000020E6100000E538D293ADC651C0F3699A2254284540"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[-71.1043443253471,42.3150676015829],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POINT (-71.1043443253471 42.3150676015829)" }
+{ "Type": "Point", "Area": 0.0, "Coordinate dimension": 3, "Dimension": 0, "NPoints": 1, "XMax": 1.0, "XMin": 1.0, "YMax": 2.0, "YMin": 2.0, "Binary": hex("01010000A0E6100000000000000000F03F00000000000000400000000000000840"), "GeoJSON": "{\"type\":\"Point\",\"coordinates\":[1,2,3],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POINT Z(1 2 3)" }
+{ "Type": "Polygon", "Area": 928.625, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 4, "XMax": 743265.625, "XMin": 743238.0, "YMax": 2967450.0, "YMin": 2967416.0, "Binary": hex("0103000020E61000000100000005000000000000008CAE264100000000BCA34641000000008CAE264100000000CDA3464100000000C2AE264100000000CDA3464100000040C3AE264100000000BCA34641000000008CAE264100000000BCA34641"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POLYGON ((743238 2967416, 743238 2967450, 743265 2967450, 743265.625 2967416, 743238 2967416))" }
+{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 2, "XMax": -113.98, "XMin": -113.981, "YMax": 39.198, "YMin": 39.195, "Binary": hex("0102000020E6100000020000001F85EB51B87E5CC0D34D621058994340105839B4C87E5CC0295C8FC2F5984340"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[-113.98,39.198],[-113.981,39.195]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "LINESTRING (-113.98 39.198, -113.981 39.195)" }
+{ "Type": "LineString", "Area": 0.0, "Coordinate dimension": 2, "Dimension": 1, "NPoints": 3, "XMax": 7.0, "XMin": 1.0, "YMax": 8.0, "YMin": 2.0, "Binary": hex("0102000020E610000003000000000000000000F03F0000000000000040000000000000104000000000000014400000000000001C400000000000002040"), "GeoJSON": "{\"type\":\"LineString\",\"coordinates\":[[1,2],[4,5],[7,8]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "LINESTRING (1 2, 4 5, 7 8)" }
+{ "Type": "Polygon", "Area": 1.0, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 4, "XMax": 11.0, "XMin": 10.0, "YMax": 11.0, "YMin": 10.0, "Binary": hex("0103000020E610000001000000050000000000000000002440000000000000244000000000000024400000000000002640000000000000264000000000000026400000000000002640000000000000244000000000000024400000000000002440"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[10,10],[10,11],[11,11],[11,10],[10,10]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POLYGON ((10 10, 10 11, 11 11, 11 10, 10 10))" }
+{ "Type": "Polygon", "Area": 675.0, "Coordinate dimension": 2, "Dimension": 2, "NPoints": 7, "XMax": 45.0, "XMin": 10.0, "YMax": 45.0, "YMin": 10.0, "Binary": hex("0103000020E6100000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002E40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003E40000000000080414000000000008041400000000000003E40000000000000344000000000000034400000000000003E40"), "GeoJSON": "{\"type\":\"Polygon\",\"coordinates\":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", "WKT": "POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))" }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.06.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.06.adm
index 39ced5e..8d0c233 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.06.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.06.adm
@@ -1,4 +1,4 @@
-{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]} }
-{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]} }
-{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[10,10],[10,11],[11,11],[11,10],[10,10]]} }
-{ "NumInteriorRings": 1, "ExteriorRing": {"type":"LineString","coordinates":[[35,10],[45,45],[15,40],[10,20],[35,10]]} }
\ No newline at end of file
+{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "NumInteriorRings": 0, "ExteriorRing": {"type":"LineString","coordinates":[[10,10],[10,11],[11,11],[11,10],[10,10]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "NumInteriorRings": 1, "ExteriorRing": {"type":"LineString","coordinates":[[35,10],[45,45],[15,40],[10,20],[35,10]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.07.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.07.adm
index 3a026d5..e22bade 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.07.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.07.adm
@@ -1,4 +1,4 @@
-{ "Length": 0.004058119099397876, "Boundary": {"type":"MultiPoint","coordinates":[[-69.1991349,-12.6006222],[-69.1975081,-12.6010968]]} }
-{ "Length": 78.9292222699217, "Boundary": {"type":"MultiPoint","coordinates":[[10,10],[10,40],[30,10],[40,40]]} }
-{ "Length": 0.0031622776601655037, "Boundary": {"type":"MultiPoint","coordinates":[[-113.98,39.198],[-113.981,39.195]]} }
-{ "Length": 8.48528137423857, "Boundary": {"type":"MultiPoint","coordinates":[[1,2],[7,8]]} }
+{ "Length": 0.004058119099397876, "Boundary": {"type":"MultiPoint","coordinates":[[-69.1991349,-12.6006222],[-69.1975081,-12.6010968]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Length": 78.9292222699217, "Boundary": {"type":"MultiPoint","coordinates":[[10,10],[10,40],[30,10],[40,40]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Length": 0.0031622776601655037, "Boundary": {"type":"MultiPoint","coordinates":[[-113.98,39.198],[-113.981,39.195]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Length": 8.48528137423857, "Boundary": {"type":"MultiPoint","coordinates":[[1,2],[7,8]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
index 1987970..6bc1369 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/datatype/result.08.adm
@@ -1,3 +1,3 @@
-{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, "StartPoint": {"type":"Point","coordinates":[-69.1991349,-12.6006222]}, "Envelope": {"type":"Polygon","coordinates":[[[-69.199136,-12.6010968],[-69.199136,-12.5998133],[-69.1972972,-12.5998133],[-69.1972972,-12.6010968],[-69.199136,-12.6010968]]]} }
-{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, "StartPoint": {"type":"Point","coordinates":[-113.98,39.198]}, "Envelope": {"type":"Polygon","coordinates":[[[-113.981,39.195],[-113.981,39.198],[-113.98,39.198],[-113.98,39.195],[-113.981,39.195]]]} }
-{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842]}, "StartPoint": {"type":"Point","coordinates":[1,2]}, "Envelope": {"type":"Polygon","coordinates":[[[1,2],[1,8],[7,8],[7,2],[1,2]]]} }
\ No newline at end of file
+{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "StartPoint": {"type":"Point","coordinates":[-69.1991349,-12.6006222],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Envelope": {"type":"Polygon","coordinates":[[[-69.199136,-12.6010968],[-69.199136,-12.5998133],[-69.1972972,-12.5998133],[-69.1972972,-12.6010968],[-69.199136,-12.6010968]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "StartPoint": {"type":"Point","coordinates":[-113.98,39.198],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Envelope": {"type":"Polygon","coordinates":[[[-113.981,39.195],[-113.981,39.198],[-113.98,39.198],[-113.98,39.195],[-113.981,39.195]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "PointN": {"type":"Point","coordinates":[-69.199136,-12.599842],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "StartPoint": {"type":"Point","coordinates":[1,2],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Envelope": {"type":"Polygon","coordinates":[[[1,2],[1,8],[7,8],[7,2],[1,2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/index/result.20.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/index/result.20.adm
index bebded7..f830271 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/index/result.20.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/index/result.20.adm
@@ -1,13 +1,13 @@
-{ "Geometries": { "id": 123, "myGeometry": {"type":"Point","coordinates":[-118.4,33.93]} } }
-{ "Geometries": { "id": 124, "myGeometry": {"type":"Polygon","coordinates":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]]} } }
-{ "Geometries": { "id": 126, "myGeometry": {"type":"LineString","coordinates":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]]} } }
-{ "Geometries": { "id": 127, "myGeometry": {"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]]} } }
-{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]]} } }
-{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]]} } }
-{ "Geometries": { "id": 130, "myGeometry": {"type":"Point","coordinates":[-71.1043443253471,42.3150676015829]} } }
-{ "Geometries": { "id": 131, "myGeometry": {"type":"Point","coordinates":[1,2,3]} } }
-{ "Geometries": { "id": 133, "myGeometry": {"type":"Polygon","coordinates":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]]} } }
-{ "Geometries": { "id": 134, "myGeometry": {"type":"LineString","coordinates":[[-113.98,39.198],[-113.981,39.195]]} } }
-{ "Geometries": { "id": 135, "myGeometry": {"type":"LineString","coordinates":[[1,2],[4,5],[7,8]]} } }
-{ "Geometries": { "id": 136, "myGeometry": {"type":"Polygon","coordinates":[[[10,10],[10,11],[11,11],[11,10],[10,10]]]} } }
-{ "Geometries": { "id": 137, "myGeometry": {"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]]} } }
\ No newline at end of file
+{ "Geometries": { "id": 123, "myGeometry": {"type":"Point","coordinates":[-118.4,33.93],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 124, "myGeometry": {"type":"Polygon","coordinates":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 126, "myGeometry": {"type":"LineString","coordinates":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 127, "myGeometry": {"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 130, "myGeometry": {"type":"Point","coordinates":[-71.1043443253471,42.3150676015829],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 131, "myGeometry": {"type":"Point","coordinates":[1,2,3],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 133, "myGeometry": {"type":"Polygon","coordinates":[[[743238,2967416],[743238,2967450],[743265,2967450],[743265.625,2967416],[743238,2967416]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 134, "myGeometry": {"type":"LineString","coordinates":[[-113.98,39.198],[-113.981,39.195]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 135, "myGeometry": {"type":"LineString","coordinates":[[1,2],[4,5],[7,8]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 136, "myGeometry": {"type":"Polygon","coordinates":[[[10,10],[10,11],[11,11],[11,10],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
+{ "Geometries": { "id": 137, "myGeometry": {"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.10.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.10.adm
index bfa005e..a1e16dd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.10.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/single-method/result.10.adm
@@ -1 +1 @@
-{"type":"Polygon","coordinates":[[[-7,4.2],[-7.1,5],[-7.1,4.3],[-7,4.2]]]}
\ No newline at end of file
+{"type":"Polygon","coordinates":[[[-7,4.2],[-7.1,5],[-7.1,4.3],[-7,4.2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.04.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.04.adm
index 57d5885..8d31c0c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.04.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.04.adm
@@ -1,10 +1,10 @@
-{ "Union": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]]}, "Intersection": {"type":"Point","coordinates":[0,2]}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]]} }
-{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3]],[[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[3,3],[4,2],[5,2]]]}, "Intersection": {"type":"LineString","coordinates":[[2,2],[3,3]]}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[3,3],[4,2],[5,2]]]} }
-{ "Union": {"type":"LineString","coordinates":[[0,0],[0,2]]}, "Intersection": {"type":"Point","coordinates":[0,0]}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[0,2]]} }
-{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[-1,-1],[1,2]],[[1,2],[2,3.5],[1,3],[1,2]],[[1,2],[2,1]]]}, "Intersection": {"type":"Point","coordinates":[-1,-1]}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[-1,-1],[1,2]],[[1,2],[2,3.5],[1,3],[1,2]],[[1,2],[2,1]]]} }
-{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[2,2],[3,2],[4,2],[5,2]]]}, "Intersection": {"type":"Point","coordinates":[2,2]}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[2,2],[3,2],[4,2],[5,2]]]} }
-{ "Union": {"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[0,0]},{"type":"LineString","coordinates":[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]]}]}, "Intersection": , "SymDifference": {"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[0,0]},{"type":"LineString","coordinates":[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]]}]} }
-{ "Union": {"type":"MultiLineString","coordinates":[[[0,0],[5,5]],[[5,5],[10,10]]]}, "Intersection": {"type":"MultiLineString","coordinates":[[[0,0],[5,5]],[[5,5],[10,10]]]}, "SymDifference": {"type":"LineString","coordinates":[]} }
-{ "Union": {"type":"MultiLineString","coordinates":[[[1,2],[3,4]],[[5,6],[7,8]]]}, "Intersection": {"type":"LineString","coordinates":[]}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,2],[3,4]],[[5,6],[7,8]]]} }
-{ "Union": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]]}, "Intersection": {"type":"Point","coordinates":[0,2]}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]]} }
-{ "Union": {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}, "Intersection": {"type":"Polygon","coordinates":[[[0.25,0.25],[0.25,0.5],[0.5,0.5],[0.5,0.25],[0.25,0.25]]]}, "SymDifference": {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]],[[0.25,0.25],[0.5,0.25],[0.5,0.5],[0.25,0.5],[0.25,0.25]]]} }
+{ "Union": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Point","coordinates":[0,2],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3]],[[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[3,3],[4,2],[5,2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"LineString","coordinates":[[2,2],[3,3]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[3,3],[4,2],[5,2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"LineString","coordinates":[[0,0],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Point","coordinates":[0,0],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[-1,-1],[1,2]],[[1,2],[2,3.5],[1,3],[1,2]],[[1,2],[2,1]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Point","coordinates":[-1,-1],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[-1,-1],[1,2]],[[1,2],[2,3.5],[1,3],[1,2]],[[1,2],[2,1]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[2,2],[3,2],[4,2],[5,2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Point","coordinates":[2,2],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,1],[2,2]],[[2,2],[3,3],[4,4],[5,5],[6,6]],[[0,2],[1,2],[2,2]],[[2,2],[3,2],[4,2],[5,2]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[0,0]},{"type":"LineString","coordinates":[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]]}],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": , "SymDifference": {"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[0,0]},{"type":"LineString","coordinates":[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]]}],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"MultiLineString","coordinates":[[[0,0],[5,5]],[[5,5],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"MultiLineString","coordinates":[[[0,0],[5,5]],[[5,5],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"LineString","coordinates":[],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"MultiLineString","coordinates":[[[1,2],[3,4]],[[5,6],[7,8]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"LineString","coordinates":[],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"MultiLineString","coordinates":[[[1,2],[3,4]],[[5,6],[7,8]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Point","coordinates":[0,2],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"LineString","coordinates":[[0,0],[1,1],[0,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
+{ "Union": {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "Intersection": {"type":"Polygon","coordinates":[[[0.25,0.25],[0.25,0.5],[0.5,0.5],[0.5,0.25],[0.25,0.25]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}, "SymDifference": {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]],[[0.25,0.25],[0.5,0.25],[0.5,0.5],[0.25,0.5],[0.25,0.25]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.05.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.05.adm
index d7e9872..5123e09 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.05.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/geojson/two-geometries/result.05.adm
@@ -1 +1 @@
-{"type":"MultiPoint","coordinates":[[1,1],[1,2]]}
\ No newline at end of file
+{"type":"MultiPoint","coordinates":[[1,1],[1,2]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
\ No newline at end of file
diff --git a/asterixdb/asterix-doc/src/site/markdown/geo/functions.md b/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
index 2bd2250..99e564d 100644
--- a/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
+++ b/asterixdb/asterix-doc/src/site/markdown/geo/functions.md
@@ -30,6 +30,7 @@
 ## <a id="Introduction">Introduction</a>
  
 To support standard GIS objects in AsterixDB, you need to use the `geometry` data type as follows.
+AsterixDB supports spatial data through a native geometry type. Users can create datasets with spatial fields and perform a variety of spatial operations using built-in functions. Geometries can store multidimensional coordinates and support a coordinate reference system (CRS) via an associated Spatial Reference Identifier(SRID).
 
 ```
 DROP dataverse GeoJSON if exists;
@@ -45,8 +46,40 @@
 CREATE DATASET Geometries (GeometryType) PRIMARY KEY id;
 ```
 
-Please note that even though the [SRID](http://desktop.arcgis.com/en/arcmap/10.3/manage-data/using-sql-with-gdbs/what-is-an-srid.htm)
-input is supported for certain functions and is represented internally in the correct manner the serialized result (printed in the output) displays the SRID as 4326 always because of the limitations in Esri API.
+## <a id="crs">CRS and SRID Support</a>
+AsterixDB stores and tracks the SRID for each geometry. SRIDs are used to specify the spatial reference system for geometries. If no SRID is specified during geometry creation, **EPSG:4326 (WGS84)** is assumed by default.
+
+We currently use **Apache SIS** to handle CRS metadata and transformations. The system supports **all EPSG definitions provided by Apache SIS**. However, these are not bundled with AsterixDB by default due to licensing restrictions. To enable CRS transformation support:
+
+- Run the setup script provided in the repository (`install-epsg-database.sh`)
+- Accept EPSG terms and download the required data
+- Set the environment variable `SIS_DATA` to the downloaded data directory
+
+Internally, we use an embedded **Apache Derby** database on each node to manage CRS metadata.
+
+> AsterixDB follows NoSQL principles and will allow storing any SRID, even if the definition is unavailable. However, CRS-aware operations will fail or fall back if the CRS metadata is missing.
+
+For operations involving **two geometries**, both must be in the **same CRS**. Mismatched SRIDs will raise an error unless a transformation is explicitly performed using `ST_Transform`.
+
+We are working on extending support for **custom CRS definitions** in the near future.
+
+## New CRS-Aware Functions
+
+### ST_Transform(geometry, int targetSRID)
+Transforms the geometry to the target SRID. Uses Apache SIS to perform the transformation. SRID must be defined in the Apache SIS EPSG dataset.
+
+```
+SELECT ST_Transform(ST_MakePoint(12.9716, 77.5946), 3857);
+```
+
+### ST_Transform(geometry, string sourceWKT, string targetWKT)
+Transforms a geometry from a custom WKT-defined CRS to another. Useful when working with non-standard or locally-defined projections.
+
+```
+SELECT ST_Transform(ST_MakePoint(12.9716, 77.5946), "GEOGCS[\"WGS 84\"...", "PROJCS[\"Custom Mercator\"...);
+```
+> **Note:** When using WKT strings in SQL++ queries, **always enclose the WKT in double quotes** and **escape inner quotes** using `\"`.
+> These functions ensure CRS consistency across operations. Users are responsible for specifying correct WKT strings and ensuring valid definitions.
 
 ## <a id="construction">Construction functions</a>
 The Geometry datatype can be created by the constructor functions.
@@ -89,7 +122,7 @@
         st_geom_from_text('MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10))');
   * Result:
   
-        {"type":"MultiLineString","coordinates":[[[1,2],[3,4],[5,6]],[[7,8],[9,10]]],"crs":null}
+        {"type":"MultiLineString","coordinates":[[[1,2],[3,4],[5,6]],[[7,8],[9,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 
 ### st_geom_from_wkb ###
 * Creates a geometry instance from a Well-Known Binary geometry representation (WKB) and optional SRID.
@@ -505,7 +538,7 @@
         st_boundary(st_geom_from_text('POLYGON((1 1,0 0, -1 1, 1 1))'));
   * Result:
   
-        {"type":"MultiLineString","coordinates":[[[1,1],[-1,1],[0,0],[1,1]]],"crs":null}
+        {"type":"MultiLineString","coordinates":[[[1,1],[-1,1],[0,0],[1,1]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 
 ### st_end_point ###
 * Return the last point of a LINESTRING or CIRCULARLINESTRING geometry as a POINT.
@@ -615,7 +648,7 @@
         st_sym_difference(st_geom_from_text("LINESTRING(1 1,2 2,3 3,4 4, 5 5,6 6)"), st_geom_from_text("LINESTRING(0 2,1 2,2 2,3 3,4 2,5 2)"));
   * Result:
   
-        {"type":"MultiLineString","coordinates":[[[0,2],[1,2],[2,2],[1,1]],[[5,2],[4,2],[3,3],[4,4],[5,5],[6,6]]],"crs":null}
+        {"type":"MultiLineString","coordinates":[[[0,2],[1,2],[2,2],[1,1]],[[5,2],[4,2],[3,3],[4,4],[5,5],[6,6]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 
 ### st_polygonize ###
 * Aggregate. Creates a GeometryCollection containing possible polygons formed from the constituent linework of a set of geometries.
diff --git a/asterixdb/asterix-doc/src/site/markdown/geo/quickstart.md b/asterixdb/asterix-doc/src/site/markdown/geo/quickstart.md
index 29f16bd..86af80a 100644
--- a/asterixdb/asterix-doc/src/site/markdown/geo/quickstart.md
+++ b/asterixdb/asterix-doc/src/site/markdown/geo/quickstart.md
@@ -88,7 +88,7 @@
 ```
 { "Geometries": { "id": 124, "myGeometry": {"type":"Polygon","coordinates":[[[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 126, "myGeometry": {"type":"LineString","coordinates":[[-69.1991349,-12.6006222],[-69.199136,-12.599842],[-69.1982979,-12.5998268],[-69.1982598,-12.599869],[-69.1982188,-12.5998698],[-69.19817,-12.5998707],[-69.198125,-12.5998218],[-69.1973024,-12.5998133],[-69.1972972,-12.6003109],[-69.197394,-12.6003514],[-69.1973906,-12.6009231],[-69.1975115,-12.601026],[-69.1975081,-12.6010968]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
-{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":null} } }
+{ "Geometries": { "id": 128, "myGeometry": {"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 132, "myGeometry": {"type":"Point","coordinates":[1,2,3,4],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 133, "myGeometry": {"type":"Polygon","coordinates":[[[743238,2967416],[743265.625,2967416],[743265,2967450],[743238,2967450],[743238,2967416]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 134, "myGeometry": {"type":"LineString","coordinates":[[-113.98,39.198],[-113.981,39.195]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
@@ -96,7 +96,7 @@
 { "Geometries": { "id": 136, "myGeometry": {"type":"Polygon","coordinates":[[[10,10],[11,10],[11,11],[10,11],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 123, "myGeometry": {"type":"Point","coordinates":[-118.4,33.93],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 127, "myGeometry": {"type":"MultiPoint","coordinates":[[10,40],[40,30],[20,20],[30,10]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
-{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]],"crs":null} } }
+{ "Geometries": { "id": 129, "myGeometry": {"type":"MultiPolygon","coordinates":[[[[40,40],[20,45],[45,30],[40,40]]],[[[20,35],[10,30],[10,10],[30,5],[45,20],[20,35]],[[30,20],[20,15],[20,25],[30,20]]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 130, "myGeometry": {"type":"Point","coordinates":[-71.1043443253471,42.3150676015829],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 131, "myGeometry": {"type":"Point","coordinates":[1,2,3],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
 { "Geometries": { "id": 137, "myGeometry": {"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}} } }
@@ -137,7 +137,7 @@
 result:
 
 ```
-{"type":"MultiPolygon","coordinates":[[[[10,10],[30,5],[35,10],[45,20],[38.90243902439025,23.65853658536585],[41.34146341463415,32.19512195121951],[45,30],[42.27272727272727,35.45454545454545],[45,45],[30,42.5],[20,45],[25.434782608695656,41.73913043478261],[15,40],[12.857142857142858,31.428571428571427],[10,30],[10,20],[10,11],[10,10]],[[32.5,27.5],[25.357142857142858,31.785714285714285],[35,35],[32.5,27.5]],[[20,15],[20,16],[21.11111111111111,15.555555555555555],[20,15]]],[[[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133]]],[[[743238,2967416],[743265.625,2967416],[743265,2967450],[743238,2967450],[743238,2967416]]]],"crs":null}
+{"type":"MultiPolygon","coordinates":[[[[10,10],[30,5],[35,10],[45,20],[38.90243902439025,23.65853658536585],[41.34146341463415,32.19512195121951],[45,30],[42.27272727272727,35.45454545454545],[45,45],[30,42.5],[20,45],[25.434782608695656,41.73913043478261],[15,40],[12.857142857142858,31.428571428571427],[10,30],[10,20],[10,11],[10,10]],[[32.5,27.5],[25.357142857142858,31.785714285714285],[35,35],[32.5,27.5]],[[20,15],[20,16],[21.11111111111111,15.555555555555555],[20,15]]],[[[8.7600762,49.7102133],[8.760178,49.7102516],[8.7600914,49.7103478],[8.7599721,49.7103028],[8.759997,49.7102752],[8.7600145,49.7102818],[8.7600762,49.7102133]]],[[[743238,2967416],[743265.625,2967416],[743265,2967450],[743238,2967450],[743238,2967416]]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 ```
 
 ## <a id="range">Range query</a>
@@ -176,7 +176,7 @@
 {"type":"LineString","coordinates":[[1,2],[4,5],[7,8]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 {"type":"Point","coordinates":[1,2,3],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 {"type":"Polygon","coordinates":[[[10,10],[11,10],[11,11],[10,11],[10,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
-{"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":null}
+{"type":"MultiLineString","coordinates":[[[10,10],[20,20],[10,40]],[[40,40],[30,30],[40,20],[30,10]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
 ```
 
 ## <a id="joint">Spatial join query</a>
diff --git a/asterixdb/asterix-geo/pom.xml b/asterixdb/asterix-geo/pom.xml
index 7568d5d..a9d08ad 100644
--- a/asterixdb/asterix-geo/pom.xml
+++ b/asterixdb/asterix-geo/pom.xml
@@ -124,6 +124,14 @@
       <groupId>org.locationtech.jts</groupId>
       <artifactId>jts-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.sis.core</groupId>
+      <artifactId>sis-referencing</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoConstants.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoConstants.java
new file mode 100644
index 0000000..2c1a598
--- /dev/null
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoConstants.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.asterix.geo.evaluators;
+
+/**
+ * A collection of constants used across the geo module.
+ */
+public final class GeoConstants {
+
+    /**
+     * Default SRID for geospatial data.
+     * EPSG:4326 represents the WGS84 coordinate system using (longitude, latitude) in degrees.
+     */
+    public static final int DEFAULT_SRID_4326 = 4326;
+
+    private GeoConstants() {
+
+    }
+}
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
index 75927cc..3f991ec 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/GeoFunctionRegistrant.java
@@ -72,6 +72,8 @@
 import org.apache.asterix.geo.evaluators.functions.STStartPointDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STSymDifferenceDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STTouchesDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STTransformDescriptor;
+import org.apache.asterix.geo.evaluators.functions.STTransformWKTDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STUnionDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STWithinDescriptor;
 import org.apache.asterix.geo.evaluators.functions.STXDescriptor;
@@ -160,5 +162,7 @@
         fc.add(STPolygonizeDescriptor.FACTORY);
         fc.add(STMBRDescriptor.FACTORY);
         fc.add(STMBREnlargeDescriptor.FACTORY);
+        fc.add(STTransformDescriptor.FACTORY);
+        fc.add(STTransformWKTDescriptor.FACTORY);
     }
 }
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTDoubleGeometryDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTDoubleGeometryDescriptor.java
index 69f841c..953e8f0 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTDoubleGeometryDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/AbstractSTDoubleGeometryDescriptor.java
@@ -39,10 +39,13 @@
 import org.apache.hyracks.data.std.primitive.VoidPointable;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.locationtech.jts.geom.Geometry;
 
 public abstract class AbstractSTDoubleGeometryDescriptor extends AbstractScalarFunctionDynamicDescriptor {
     private static final long serialVersionUID = -4181892424621765426L;
+    private static final Logger LOGGER = LogManager.getLogger();
 
     abstract protected Object evaluateOGCGeometry(Geometry geometry0, Geometry geometry1) throws HyracksDataException;
 
@@ -107,6 +110,16 @@
                 Geometry geometry0 = AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn0).getGeometry();
                 DataInputStream dataIn1 = new DataInputStream(new ByteArrayInputStream(bytes1, offset1 + 1, len1 - 1));
                 Geometry geometry1 = AGeometrySerializerDeserializer.INSTANCE.deserialize(dataIn1).getGeometry();
+                if (geometry0.getSRID() != geometry1.getSRID()) {
+                    int srid0 = geometry0.getSRID();
+                    int srid1 = geometry1.getSRID();
+                    LOGGER.warn(
+                            "{}: Geometry SRID mismatch (geometry0 SRID={}, geometry1 SRID={}). Function expects geometries to be in the same CRS.",
+                            getIdentifier().getName(), srid0, srid1);
+                    throw new HyracksDataException(String.format(
+                            "Function %s requires both geometries to have the same SRID, but got %d and %d.",
+                            getIdentifier().getName(), srid0, srid1));
+                }
                 Object finalResult = evaluateOGCGeometry(geometry0, geometry1);
                 if (finalResult instanceof Geometry) {
                     out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STAsBinaryDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STAsBinaryDescriptor.java
index 9ee77c1..ab0b06d 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STAsBinaryDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STAsBinaryDescriptor.java
@@ -34,7 +34,7 @@
     @Override
     protected Object evaluateOGCGeometry(Geometry geometry) throws HyracksDataException {
         WKBWriter wkbWriter = new WKBWriter(GeoFunctionUtils.getCoordinateDimension(geometry),
-                GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER);
+                GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER, true);
         return wkbWriter.write(geometry);
     }
 
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextDescriptor.java
index fc097ce..37b9232 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextDescriptor.java
@@ -25,6 +25,7 @@
 
 import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
 import org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
+import org.apache.asterix.geo.evaluators.GeoConstants;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.types.ATypeTag;
@@ -100,6 +101,7 @@
                 WKTReader reader = new WKTReader();
                 String wktString = AStringSerializerDeserializer.INSTANCE.deserialize(dataIn).getStringValue();
                 Geometry geometry = reader.read(wktString);
+                geometry.setSRID(GeoConstants.DEFAULT_SRID_4326);
                 out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(geometry, out);
                 result.set(resultStorage);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextSRIDDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextSRIDDescriptor.java
index 3a3dddb..88a5fd4 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextSRIDDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STGeomFromTextSRIDDescriptor.java
@@ -24,6 +24,7 @@
 import java.io.IOException;
 
 import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AInt64SerializerDeserializer;
 import org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
@@ -112,7 +113,9 @@
             try {
                 WKTReader reader = new WKTReader();
                 String wktString = AStringSerializerDeserializer.INSTANCE.deserialize(dataIn).getStringValue();
+                int srid = (int) AInt64SerializerDeserializer.getLong(data0, offset0 + 1);
                 Geometry geometry = reader.read(wktString);
+                geometry.setSRID(srid);
                 out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(geometry, out);
                 result.set(resultStorage);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakeEnvelopeDescriptorSRID.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakeEnvelopeDescriptorSRID.java
index f8cc270..fd51889 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakeEnvelopeDescriptorSRID.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakeEnvelopeDescriptorSRID.java
@@ -125,7 +125,6 @@
             byte[] data3 = inputArg3.getByteArray();
             int offset3 = inputArg3.getStartOffset();
 
-            //Spatial Reference System Identifier (SRID), currently not used.
             eval4.evaluate(tuple, inputArg4);
             byte[] data4 = inputArg4.getByteArray();
             int offset4 = inputArg4.getStartOffset();
@@ -147,6 +146,8 @@
                 Coordinate[] coords =
                         new Coordinate[] { coordinate0, coordinate1, coordinate2, coordinate3, coordinate0 };
                 Polygon polygon = geometryFactory.createPolygon(coords);
+                int srid = (int) getVal(data4, offset4);
+                polygon.setSRID(srid);
                 out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(polygon, out);
                 result.set(resultStorage);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DDescriptor.java
index 8009510..a6c4d60 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DDescriptor.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 
 import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.geo.evaluators.GeoConstants;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.types.ATypeTag;
@@ -105,6 +106,7 @@
                 Coordinate coordinate =
                         new Coordinate(getVal(bytes0, offset0), getVal(bytes1, offset1), getVal(bytes2, offset2));
                 point = geometryFactory.createPoint(coordinate);
+                point.setSRID(GeoConstants.DEFAULT_SRID_4326);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(point, out);
             } catch (IOException e1) {
                 throw HyracksDataException.create(e1);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DWithMDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DWithMDescriptor.java
index edc0cdc..0f6b41a 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DWithMDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePoint3DWithMDescriptor.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 
 import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.geo.evaluators.GeoConstants;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.types.ATypeTag;
@@ -117,6 +118,7 @@
                 CoordinateXYZM coordinate = new CoordinateXYZM(getVal(bytes0, offset0), getVal(bytes1, offset1),
                         getVal(bytes2, offset2), getVal(bytes3, offset3));
                 point = geometryFactory.createPoint(coordinate);
+                point.setSRID(GeoConstants.DEFAULT_SRID_4326);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(point, out);
             } catch (IOException e1) {
                 throw HyracksDataException.create(e1);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePointDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePointDescriptor.java
index f21b381..1225f62 100644
--- a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePointDescriptor.java
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STMakePointDescriptor.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 
 import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.geo.evaluators.GeoConstants;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
 import org.apache.asterix.om.types.ATypeTag;
@@ -96,6 +97,7 @@
                 out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
                 Coordinate coordinate = new Coordinate(getVal(bytes0, offset0), getVal(bytes1, offset1));
                 point = geometryFactory.createPoint(coordinate);
+                point.setSRID(GeoConstants.DEFAULT_SRID_4326);
                 AGeometrySerializerDeserializer.INSTANCE.serialize(point, out);
             } catch (IOException e1) {
                 throw HyracksDataException.create(e1);
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformDescriptor.java
new file mode 100644
index 0000000..42eb9a8
--- /dev/null
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformDescriptor.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.sis.referencing.CRS;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.CoordinateSequenceFactory;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.util.GeometryTransformer;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+public class STTransformDescriptor extends AbstractSTGeometryNDescriptor {
+    public static final IFunctionDescriptorFactory FACTORY = STTransformDescriptor::new;
+    private static final long serialVersionUID = -4880751277070553733L;
+
+    /**
+     * Applies the given MathTransform to each coordinate in a JTS CoordinateSequence.
+     */
+    private static CoordinateSequence applyMathTransform(CoordinateSequence inputSeq, MathTransform transform) {
+        GeometryFactory geomFactory = new GeometryFactory();
+        CoordinateSequenceFactory csFactory = geomFactory.getCoordinateSequenceFactory();
+
+        int size = inputSeq.size();
+        int dimension = inputSeq.getDimension();
+        CoordinateSequence outputSeq = csFactory.create(size, dimension);
+
+        double[] coords = new double[inputSeq.getDimension()];
+        double[] result = new double[inputSeq.getDimension()];
+
+        try {
+            for (int i = 0; i < inputSeq.size(); i++) {
+                for (int d = 0; d < inputSeq.getDimension(); d++) {
+                    coords[d] = inputSeq.getOrdinate(i, d);
+                }
+
+                transform.transform(coords, 0, result, 0, 1);
+
+                for (int d = 0; d < inputSeq.getDimension(); d++) {
+                    outputSeq.setOrdinate(i, d, result[d]);
+                }
+            }
+        } catch (TransformException e) {
+            throw new RuntimeException("Coordinate transform failed", e);
+        }
+        return outputSeq;
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_TRANSFORM;
+    }
+
+    @Override
+    protected Geometry evaluateOGCGeometry(Geometry geometry, int srid) throws HyracksDataException {
+        try {
+            return transformGeomToTargetSRID(geometry, srid);
+        } catch (Exception e) {
+            throw HyracksDataException.create(e);
+        }
+    }
+
+    /**
+     * Performs an Apache SIS transformation from inputGeom.getSRID() to targetSRID.
+     *
+     * @param inputGeom
+     *         the original geometry to transform
+     * @param targetSRID
+     *         the target SRID
+     * @return a new geometry instance in the target SRID
+     */
+    private Geometry transformGeomToTargetSRID(Geometry inputGeom, int targetSRID) throws Exception {
+        int sourceSRID = inputGeom.getSRID();
+        String sourceCRSCode = "EPSG:" + sourceSRID;
+        String targetCRSCode = "EPSG:" + targetSRID;
+        if (sourceSRID == 0 || targetSRID == 0) {
+            throw new HyracksDataException("Source and target SRIDs must be non-zero and valid CRS codes.");
+        }
+        CoordinateReferenceSystem sourceCRS;
+        CoordinateReferenceSystem targetCRS;
+        try {
+            sourceCRS = CRS.forCode(sourceCRSCode);
+            targetCRS = CRS.forCode(targetCRSCode);
+        } catch (Exception e) {
+            throw new HyracksDataException("Failed to find CRS for EPSG codes: " + sourceSRID + " or " + targetSRID, e);
+        }
+
+        CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null);
+        //todo(suryaa):Check if the above can be cached, as findOperation is expensive
+        MathTransform mathTransform = operation.getMathTransform();
+
+        GeometryTransformer transformer = new GeometryTransformer() {
+            @Override
+            protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) {
+                return applyMathTransform(coords, mathTransform);
+            }
+        };
+
+        Geometry transformedGeometry = transformer.transform(inputGeom);
+        transformedGeometry.setSRID(targetSRID);
+        return transformedGeometry;
+    }
+
+}
diff --git a/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformWKTDescriptor.java b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformWKTDescriptor.java
new file mode 100644
index 0000000..e74b069
--- /dev/null
+++ b/asterixdb/asterix-geo/src/main/java/org/apache/asterix/geo/evaluators/functions/STTransformWKTDescriptor.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.asterix.geo.evaluators.functions;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.asterix.dataflow.data.nontagged.serde.AGeometrySerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.exceptions.InvalidDataFormatException;
+import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import org.apache.hyracks.util.string.UTF8StringReader;
+import org.apache.hyracks.util.string.UTF8StringWriter;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.CoordinateSequenceFactory;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.util.GeometryTransformer;
+import org.opengis.metadata.Identifier;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+public class STTransformWKTDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+    public static final IFunctionDescriptorFactory FACTORY = STTransformWKTDescriptor::new;
+    private static final long serialVersionUID = 1L;
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ST_TRANSFORM_WITH_WKT;
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+                return new STTransformWKTEvaluator(args, ctx);
+            }
+        };
+    }
+
+    private class STTransformWKTEvaluator implements IScalarEvaluator {
+        private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
+        private final DataOutput out = resultStorage.getDataOutput();
+
+        private final IPointable geomArg = new VoidPointable();
+        private final IPointable sourceWKTArg = new VoidPointable();
+        private final IPointable targetWKTArg = new VoidPointable();
+
+        private final IScalarEvaluator geomEval;
+        private final IScalarEvaluator sourceWKTEval;
+        private final IScalarEvaluator targetWKTEval;
+
+        public STTransformWKTEvaluator(IScalarEvaluatorFactory[] args, IEvaluatorContext ctx)
+                throws HyracksDataException {
+            this.geomEval = args[0].createScalarEvaluator(ctx);
+            this.sourceWKTEval = args[1].createScalarEvaluator(ctx);
+            this.targetWKTEval = args[2].createScalarEvaluator(ctx);
+        }
+
+        @Override
+        public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+            resultStorage.reset();
+
+            geomEval.evaluate(tuple, geomArg);
+            sourceWKTEval.evaluate(tuple, sourceWKTArg);
+            targetWKTEval.evaluate(tuple, targetWKTArg);
+
+            // Validate geometry type
+            byte[] geomBytes = geomArg.getByteArray();
+            int geomOffset = geomArg.getStartOffset();
+            int geomLen = geomArg.getLength();
+            if (geomBytes[geomOffset] != ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, geomBytes[geomOffset],
+                        ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+            }
+
+            // Validate both WKT inputs
+            byte[] sourceBytes = sourceWKTArg.getByteArray();
+            byte[] targetBytes = targetWKTArg.getByteArray();
+            int sourceOffset = sourceWKTArg.getStartOffset();
+            int targetOffset = targetWKTArg.getStartOffset();
+            if (sourceBytes[sourceOffset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 1, sourceBytes[sourceOffset],
+                        ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+            }
+            if (targetBytes[targetOffset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
+                throw new TypeMismatchException(sourceLoc, getIdentifier(), 2, targetBytes[targetOffset],
+                        ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+            }
+
+            Geometry geometry;
+            String sourceWKT;
+            String targetWKT;
+            try {
+                AStringSerializerDeserializer stringSerDer =
+                        new AStringSerializerDeserializer(new UTF8StringWriter(), new UTF8StringReader());
+                DataInputStream geomIn =
+                        new DataInputStream(new ByteArrayInputStream(geomBytes, geomOffset + 1, geomLen - 1));
+                geometry = AGeometrySerializerDeserializer.INSTANCE.deserialize(geomIn).getGeometry();
+
+                DataInputStream sourceIn = new DataInputStream(
+                        new ByteArrayInputStream(sourceBytes, sourceOffset + 1, sourceWKTArg.getLength() - 1));
+                sourceWKT = stringSerDer.deserialize(sourceIn).getStringValue();
+
+                DataInputStream targetIn = new DataInputStream(
+                        new ByteArrayInputStream(targetBytes, targetOffset + 1, targetWKTArg.getLength() - 1));
+                targetWKT = stringSerDer.deserialize(targetIn).getStringValue();
+            } catch (IOException e) {
+                throw HyracksDataException.create(e);
+            }
+
+            try {
+                Geometry transformed = transformGeometry(geometry, sourceWKT, targetWKT);
+                out.writeByte(ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+                AGeometrySerializerDeserializer.INSTANCE.serialize(transformed, out);
+                result.set(resultStorage);
+            } catch (Exception e) {
+                throw new InvalidDataFormatException(sourceLoc, getIdentifier(), e,
+                        ATypeTag.SERIALIZED_GEOMETRY_TYPE_TAG);
+            }
+        }
+
+        private Geometry transformGeometry(Geometry geom, String sourceWKT, String targetWKT) throws Exception {
+            CoordinateReferenceSystem sourceCRS = CRS.fromWKT(sourceWKT);
+            CoordinateReferenceSystem targetCRS = CRS.fromWKT(targetWKT);
+            CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null);
+            MathTransform mathTransform = operation.getMathTransform();
+
+            GeometryTransformer transformer = new GeometryTransformer() {
+                @Override
+                protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) {
+                    return applyMathTransform(coords, mathTransform);
+                }
+            };
+
+            Geometry transformed = transformer.transform(geom);
+            Identifier identifier = IdentifiedObjects.getIdentifier(targetCRS, null);
+            if (identifier != null) {
+                String code = identifier.getCode();
+                if (code != null) {
+                    try {
+                        transformed.setSRID(Integer.parseInt(code));
+                    } catch (NumberFormatException e) {
+                        LOGGER.warn(
+                                "ST_TRANSFORM_WKT: Unable to parse SRID from target CRS identifier code. The transformed geometry will have SRID=0.");
+                    }
+                }
+            } else {
+                LOGGER.warn(
+                        "ST_TRANSFORM_WKT: Unable to parse SRID from target CRS identifier code. This maybe due to the target WKT string. The transformed geometry will have SRID=0.");
+                transformed.setSRID(0);
+            }
+            return transformed;
+        }
+
+        private CoordinateSequence applyMathTransform(CoordinateSequence inputSeq, MathTransform transform) {
+            GeometryFactory geomFactory = new GeometryFactory();
+            CoordinateSequenceFactory csFactory = geomFactory.getCoordinateSequenceFactory();
+
+            int size = inputSeq.size();
+            int dimension = inputSeq.getDimension();
+            CoordinateSequence outputSeq = csFactory.create(size, dimension);
+
+            double[] coords = new double[dimension];
+            double[] result = new double[dimension];
+
+            try {
+                for (int i = 0; i < size; i++) {
+                    for (int d = 0; d < dimension; d++) {
+                        coords[d] = inputSeq.getOrdinate(i, d);
+                    }
+                    transform.transform(coords, 0, result, 0, 1);
+                    for (int d = 0; d < dimension; d++) {
+                        outputSeq.setOrdinate(i, d, result[d]);
+                    }
+                }
+            } catch (TransformException e) {
+                throw new RuntimeException("Coordinate transformation failed", e);
+            }
+            return outputSeq;
+        }
+    }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AGeometrySerializerDeserializer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AGeometrySerializerDeserializer.java
index 28c171d..5019bc7 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AGeometrySerializerDeserializer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AGeometrySerializerDeserializer.java
@@ -26,6 +26,7 @@
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.exceptions.RuntimeDataException;
 import org.apache.asterix.dataflow.data.nontagged.serde.jacksonjts.GeoFunctionUtils;
+import org.apache.asterix.dataflow.data.nontagged.serde.jacksonjts.GeoJsonConstants;
 import org.apache.asterix.om.base.AGeometry;
 import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -51,6 +52,9 @@
             byte[] bytes = new byte[length];
             in.readFully(bytes);
             Geometry geometry = wkbReader.read(bytes);
+            if (geometry.getSRID() == 0) {
+                geometry.setSRID(GeoJsonConstants.DEFAULT_CRS_4326);
+            }
             return new AGeometry(geometry);
         } catch (IOException | ParseException e) {
             throw HyracksDataException.create(e);
@@ -62,7 +66,7 @@
         try {
             Geometry geometry = instance.getGeometry();
             WKBWriter wkbWriter = new WKBWriter(GeoFunctionUtils.getCoordinateDimension(geometry),
-                    GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER);
+                    GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER, true);
             byte[] buffer = wkbWriter.write(geometry);
             // For efficiency, we store the size of the geometry in bytes in the first 32 bits
             // This allows AsterixDB to skip over this attribute if needed.
@@ -76,7 +80,7 @@
     public void serialize(Geometry geometry, DataOutput out) throws HyracksDataException {
         try {
             WKBWriter wkbWriter = new WKBWriter(GeoFunctionUtils.getCoordinateDimension(geometry),
-                    GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER);
+                    GeoFunctionUtils.LITTLE_ENDIAN_BYTEORDER, true);
             byte[] buffer = wkbWriter.write(geometry);
             // For efficiency, we store the size of the geometry in bytes in the first 32 bits
             // This allows AsterixDB to skip over this attribute if needed.
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/GeoJsonConstants.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/GeoJsonConstants.java
index 7f3d1de..4638c37 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/GeoJsonConstants.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/GeoJsonConstants.java
@@ -39,6 +39,10 @@
     public static final String GEOMETRY_COLLECTION = "GeometryCollection";
 
     public static final String TYPE = "type";
+    public static final String FIELD_CRS = "crs";
+    public static final String FIELD_NAME = "name";
+    public static final String FIELD_PROPERTIES = "properties";
+    public static final int DEFAULT_CRS_4326 = 4326;
 
     public static final String GEOMETRIES = "geometries";
 
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/parsers/GenericGeometryParser.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/parsers/GenericGeometryParser.java
index d1c9475..496ca6e 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/parsers/GenericGeometryParser.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/parsers/GenericGeometryParser.java
@@ -69,9 +69,64 @@
         String typeName = node.get(GeoJsonConstants.TYPE).asText();
         GeometryParser parser = parsers.get(typeName);
         if (parser != null) {
-            return parser.geometryFromJson(node);
+            Geometry geometry = parser.geometryFromJson(node);
+            parseCRSIfPresent(node, geometry);
+            if (geometry.getSRID() == 0) {
+                geometry.setSRID(GeoJsonConstants.DEFAULT_CRS_4326);
+            }
+            return geometry;
         } else {
             throw new JsonMappingException("Invalid geometry type: " + typeName);
         }
     }
+
+    protected void parseCRSIfPresent(JsonNode node, Geometry geometry) {
+        // "crs" is optional or legacy, so check first
+        if (!node.has(GeoJsonConstants.FIELD_CRS)) {
+            return;
+        }
+
+        JsonNode crsNode = node.get(GeoJsonConstants.FIELD_CRS);
+        if (!crsNode.has(GeoJsonConstants.TYPE) || !crsNode.has(GeoJsonConstants.FIELD_PROPERTIES)) {
+            return;
+        }
+
+        String crsType = crsNode.get(GeoJsonConstants.TYPE).asText();
+        if (!GeoJsonConstants.FIELD_NAME.equalsIgnoreCase(crsType)) {
+            return;
+        }
+
+        JsonNode propsNode = crsNode.get(GeoJsonConstants.FIELD_PROPERTIES);
+        if (!propsNode.has(GeoJsonConstants.FIELD_NAME)) {
+            return;
+        }
+
+        String crsName = propsNode.get(GeoJsonConstants.FIELD_NAME).asText();
+        int srid = parseSridFromName(crsName);
+        if (srid > 0) {
+            geometry.setSRID(srid);
+        }
+    }
+
+    /**
+     * Utility to parse an SRID from a CRS name like "EPSG:4326" or "SR-ORG:12345".
+     * Returns 0 if it cannot be parsed.
+     */
+    private int parseSridFromName(String crsName) {
+        if (crsName == null || !crsName.contains(":")) {
+            return 0;
+        }
+
+        int colonIndex = crsName.indexOf(':');
+        if (colonIndex == crsName.length() - 1) {
+            return 0; // nothing after the colon
+        }
+
+        String sridStr = crsName.substring(colonIndex + 1).trim();
+        try {
+            return Integer.parseInt(sridStr);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
 }
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/serde/GeometrySerializer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/serde/GeometrySerializer.java
index 3207afb..6c0f256 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/serde/GeometrySerializer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/jacksonjts/serde/GeometrySerializer.java
@@ -59,7 +59,7 @@
 
     @Override
     public void serialize(Geometry value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
-        writeGeometry(jsonGenerator, value);
+        writeGeometry(jsonGenerator, value, false);
     }
 
     /**
@@ -68,29 +68,30 @@
      *
      * @param jsonGenerator the JsonGenerator to use for writing the GeoJSON
      * @param value the Geometry object to serialize
+     * @param skipCrs if true, we do NOT write the CRS. Useful to write CRS only with the root object
      * @throws IOException if an input/output error occurs
      */
-    public void writeGeometry(JsonGenerator jsonGenerator, Geometry value) throws IOException {
+    public void writeGeometry(JsonGenerator jsonGenerator, Geometry value, boolean skipCrs) throws IOException {
         if (value instanceof Polygon) {
-            writePolygon(jsonGenerator, (Polygon) value);
+            writePolygon(jsonGenerator, (Polygon) value, skipCrs);
 
         } else if (value instanceof Point) {
-            writePoint(jsonGenerator, (Point) value);
+            writePoint(jsonGenerator, (Point) value, skipCrs);
 
         } else if (value instanceof MultiPoint) {
-            writeMultiPoint(jsonGenerator, (MultiPoint) value);
+            writeMultiPoint(jsonGenerator, (MultiPoint) value, skipCrs);
 
         } else if (value instanceof MultiPolygon) {
-            writeMultiPolygon(jsonGenerator, (MultiPolygon) value);
+            writeMultiPolygon(jsonGenerator, (MultiPolygon) value, skipCrs);
 
         } else if (value instanceof LineString) {
-            writeLineString(jsonGenerator, (LineString) value);
+            writeLineString(jsonGenerator, (LineString) value, skipCrs);
 
         } else if (value instanceof MultiLineString) {
-            writeMultiLineString(jsonGenerator, (MultiLineString) value);
+            writeMultiLineString(jsonGenerator, (MultiLineString) value, skipCrs);
 
         } else if (value instanceof GeometryCollection) {
-            writeGeometryCollection(jsonGenerator, (GeometryCollection) value);
+            writeGeometryCollection(jsonGenerator, (GeometryCollection) value, skipCrs);
 
         } else {
             throw new JsonMappingException(jsonGenerator,
@@ -102,20 +103,24 @@
         }
     }
 
-    private void writeGeometryCollection(JsonGenerator jsonGenerator, GeometryCollection value) throws IOException {
+    private void writeGeometryCollection(JsonGenerator jsonGenerator, GeometryCollection value, boolean skipCrs)
+            throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.GEOMETRY_COLLECTION);
         jsonGenerator.writeArrayFieldStart(GeoJsonConstants.GEOMETRIES);
 
         for (int i = 0; i != value.getNumGeometries(); ++i) {
-            writeGeometry(jsonGenerator, value.getGeometryN(i));
+            writeGeometry(jsonGenerator, value.getGeometryN(i), true);
         }
 
         jsonGenerator.writeEndArray();
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, value);
+        }
         jsonGenerator.writeEndObject();
     }
 
-    private void writeMultiPoint(JsonGenerator jsonGenerator, MultiPoint value) throws IOException {
+    private void writeMultiPoint(JsonGenerator jsonGenerator, MultiPoint value, boolean skipCrs) throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.MULTI_POINT);
         jsonGenerator.writeArrayFieldStart(GeoJsonConstants.COORDINATES);
@@ -125,10 +130,14 @@
         }
 
         jsonGenerator.writeEndArray();
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, value);
+        }
         jsonGenerator.writeEndObject();
     }
 
-    private void writeMultiLineString(JsonGenerator jsonGenerator, MultiLineString value) throws IOException {
+    private void writeMultiLineString(JsonGenerator jsonGenerator, MultiLineString value, boolean skipCrs)
+            throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.MULTI_LINE_STRING);
         jsonGenerator.writeArrayFieldStart(GeoJsonConstants.COORDINATES);
@@ -138,15 +147,14 @@
         }
 
         jsonGenerator.writeEndArray();
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, value);
+        }
         jsonGenerator.writeEndObject();
     }
 
-    @Override
-    public Class<Geometry> handledType() {
-        return Geometry.class;
-    }
-
-    private void writeMultiPolygon(JsonGenerator jsonGenerator, MultiPolygon value) throws IOException {
+    private void writeMultiPolygon(JsonGenerator jsonGenerator, MultiPolygon value, boolean skipCrs)
+            throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.MULTI_POLYGON);
         jsonGenerator.writeArrayFieldStart(GeoJsonConstants.COORDINATES);
@@ -156,15 +164,20 @@
         }
 
         jsonGenerator.writeEndArray();
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, value);
+        }
         jsonGenerator.writeEndObject();
     }
 
-    private void writePolygon(JsonGenerator jsonGenerator, Polygon value) throws IOException {
+    private void writePolygon(JsonGenerator jsonGenerator, Polygon value, boolean skipCrs) throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.POLYGON);
         jsonGenerator.writeFieldName(GeoJsonConstants.COORDINATES);
         writePolygonCoordinates(jsonGenerator, value);
-
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, value);
+        }
         jsonGenerator.writeEndObject();
     }
 
@@ -187,19 +200,26 @@
         jsonGenerator.writeEndArray();
     }
 
-    private void writeLineString(JsonGenerator jsonGenerator, LineString lineString) throws IOException {
+    private void writeLineString(JsonGenerator jsonGenerator, LineString lineString, boolean skipCrs)
+            throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.LINE_STRING);
         jsonGenerator.writeFieldName(GeoJsonConstants.COORDINATES);
         writeLineStringCoordinates(jsonGenerator, lineString);
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, lineString);
+        }
         jsonGenerator.writeEndObject();
     }
 
-    private void writePoint(JsonGenerator jsonGenerator, Point p) throws IOException {
+    private void writePoint(JsonGenerator jsonGenerator, Point p, boolean skipCrs) throws IOException {
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField(GeoJsonConstants.TYPE, GeoJsonConstants.POINT);
         jsonGenerator.writeFieldName(GeoJsonConstants.COORDINATES);
         writePointCoordinates(jsonGenerator, p);
+        if (!skipCrs) {
+            writeCRS(jsonGenerator, p);
+        }
         jsonGenerator.writeEndObject();
     }
 
@@ -228,4 +248,25 @@
         }
     }
 
+    /**
+     * Writes a "crs" object into the JSON, defaults it to 4326 if not present
+     */
+    private void writeCRS(JsonGenerator jsonGenerator, Geometry geometry) throws IOException {
+        int srid = geometry.getSRID();
+
+        if (srid == 0) {
+            srid = GeoJsonConstants.DEFAULT_CRS_4326;
+        }
+
+        String crsName = "EPSG:" + srid;
+
+        jsonGenerator.writeObjectFieldStart("crs");
+        jsonGenerator.writeStringField("type", "name");
+
+        jsonGenerator.writeObjectFieldStart("properties");
+        jsonGenerator.writeStringField("name", crsName);
+        jsonGenerator.writeEndObject();
+        jsonGenerator.writeEndObject();
+    }
+
 }
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/AbstractFunctionDescriptor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/AbstractFunctionDescriptor.java
index 3aea6dc..d18f443 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/AbstractFunctionDescriptor.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/AbstractFunctionDescriptor.java
@@ -31,7 +31,7 @@
 
     private static final long serialVersionUID = 1L;
 
-    protected SourceLocation sourceLoc;
+    protected static SourceLocation sourceLoc;
 
     @Override
     public void setImmutableStates(Object... states) {
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index 27f2160..8f54a8a 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -1118,6 +1118,9 @@
     public static final FunctionIdentifier ST_MBR = FunctionConstants.newAsterix("st-mbr", 1);
     public static final FunctionIdentifier ST_MBR_ENLARGE = FunctionConstants.newAsterix("st-mbr-enlarge", 2);
 
+    public static final FunctionIdentifier ST_TRANSFORM = FunctionConstants.newAsterix("st-transform", 2);
+    public static final FunctionIdentifier ST_TRANSFORM_WITH_WKT = FunctionConstants.newAsterix("st-transform", 3);
+
     // Spatial and temporal type accessors
     public static final FunctionIdentifier ACCESSOR_TEMPORAL_YEAR = FunctionConstants.newAsterix("get-year", 1);
     public static final FunctionIdentifier ACCESSOR_TEMPORAL_MONTH = FunctionConstants.newAsterix("get-month", 1);
@@ -1981,6 +1984,8 @@
         addPrivateFunction(ST_UNION_AGG, AGeometryTypeComputer.INSTANCE, true);
         addPrivateFunction(ST_UNION_SQL_AGG, AGeometryTypeComputer.INSTANCE, true);
         addFunction(ST_POLYGONIZE, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_TRANSFORM, AGeometryTypeComputer.INSTANCE, true);
+        addFunction(ST_TRANSFORM_WITH_WKT, AGeometryTypeComputer.INSTANCE, true);
 
         addPrivateFunction(ST_MBR, ARectangleTypeComputer.INSTANCE, true);
         addPrivateFunction(ST_MBR_ENLARGE, ARectangleTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_cc.yml b/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_cc.yml
index a5b599c..2a38ce5 100644
--- a/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_cc.yml
+++ b/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_cc.yml
@@ -35,5 +35,7 @@
     sleep 1
   args:
     chdir: "{{ binarydir }}"
+  environment:
+    SIS_DATA: "{{ binarydir }}/repo/sis"
   async: 10
   poll: 0
\ No newline at end of file
diff --git a/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_ncservice.yml b/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_ncservice.yml
index 42c7a75..784ae6a 100644
--- a/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_ncservice.yml
+++ b/asterixdb/asterix-server/src/main/opt/ansible/yaml/start_ncservice.yml
@@ -23,5 +23,7 @@
     sleep 1
   args:
     chdir: "{{ binarydir }}"
+  environment:
+    SIS_DATA: "{{ binarydir }}/repo/sis"
   async: 10
   poll: 0
\ No newline at end of file
diff --git a/asterixdb/asterix-server/src/main/opt/local/bin/install-epsg-database.sh b/asterixdb/asterix-server/src/main/opt/local/bin/install-epsg-database.sh
new file mode 100644
index 0000000..3895f7d
--- /dev/null
+++ b/asterixdb/asterix-server/src/main/opt/local/bin/install-epsg-database.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# ------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+# ------------------------------------------------------------
+
+# Set Apache SIS data directory
+SIS_DATA=${SIS_DATA:-"../../../repo/sis"}
+EPSG_JAR_URL="https://repo1.maven.org/maven2/org/apache/sis/non-free/sis-epsg/1.4/sis-epsg-1.4.jar"
+EPSG_JAR="sis-epsg-1.4.jar"
+
+# Create necessary directories
+mkdir -p "$SIS_DATA/Databases/ExternalSources"
+
+# Download the JAR
+echo "Downloading EPSG database JAR..."
+curl -L -o "$EPSG_JAR" "$EPSG_JAR_URL"
+
+# Extract and show license
+echo "Extracting license..."
+unzip -p "$EPSG_JAR" "org/apache/sis/referencing/factory/sql/epsg/LICENSE.txt" > LICENSE.txt
+cat LICENSE.txt
+
+# Prompt for user agreement
+echo "Do you accept the license terms? (yes/no)"
+read -r AGREEMENT
+if [[ "$AGREEMENT" != "yes" ]]; then
+    echo "License agreement not accepted. Exiting."
+    rm -f "$EPSG_JAR" LICENSE.txt
+    exit 1
+fi
+
+# Extract SQL files from JAR
+echo "Extracting EPSG SQL files..."
+unzip -j "$EPSG_JAR" \
+    "org/apache/sis/referencing/factory/sql/epsg/Data.sql" \
+    "org/apache/sis/referencing/factory/sql/epsg/FKeys.sql" \
+    "org/apache/sis/referencing/factory/sql/epsg/Tables.sql" -d .
+
+# Move SQL files to SIS data directory
+mv Data.sql "$SIS_DATA/Databases/ExternalSources/EPSG_Data.sql"
+mv FKeys.sql "$SIS_DATA/Databases/ExternalSources/EPSG_FKeys.sql"
+mv Tables.sql "$SIS_DATA/Databases/ExternalSources/EPSG_Tables.sql"
+
+# Clean up
+rm -f "$EPSG_JAR" LICENSE.txt
+
+echo "EPSG database setup complete!"
+echo "If any EPSG file is updated, delete the directory $SIS_DATA/Databases/SpatialMetadata to force a refresh."
\ No newline at end of file
diff --git a/asterixdb/asterix-server/src/main/opt/local/bin/start-sample-cluster.sh b/asterixdb/asterix-server/src/main/opt/local/bin/start-sample-cluster.sh
index 65ef608..2f2e39f 100755
--- a/asterixdb/asterix-server/src/main/opt/local/bin/start-sample-cluster.sh
+++ b/asterixdb/asterix-server/src/main/opt/local/bin/start-sample-cluster.sh
@@ -102,10 +102,13 @@
 CLUSTERDIR=$(cd "$DIRNAME/.."; echo $PWD)
 INSTALLDIR=$(cd "$CLUSTERDIR/../.."; echo $PWD)
 LOGSDIR=$CLUSTERDIR/logs
+SIS_DATA=$(cd "$DIRNAME/../../../repo/sis" && pwd)
+export SIS_DATA=$SIS_DATA
 
 echo "CLUSTERDIR=$CLUSTERDIR"
 echo "INSTALLDIR=$INSTALLDIR"
 echo "LOGSDIR=$LOGSDIR"
+echo "SIS_DATA=$SIS_DATA"
 echo
 cd "$CLUSTERDIR"
 mkdir -p "$LOGSDIR"
diff --git a/asterixdb/pom.xml b/asterixdb/pom.xml
index aaaeb25..26eef89 100644
--- a/asterixdb/pom.xml
+++ b/asterixdb/pom.xml
@@ -1565,6 +1565,17 @@
         <version>1.19.0</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.sis.core</groupId>
+        <artifactId>sis-referencing</artifactId>
+        <version>1.4</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.derby</groupId>
+        <artifactId>derby</artifactId>
+        <version>10.14.2.0</version>
+        <scope>runtime</scope>
+      </dependency>
+      <dependency>
         <groupId>org.reflections</groupId>
         <artifactId>reflections</artifactId>
         <version>0.9.12</version>

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19549
To unsubscribe, or for help writing mail filters, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: Ia6e37080a581292744ddc9020b214936413c15ac
Gerrit-Change-Number: 19549
Gerrit-PatchSet: 1
Gerrit-Owner: Suryaa Charan Shivakumar <ss...@ucr.edu>
Gerrit-MessageType: newchange