GanosBase Geometry is a spatial geometry extension for AnalyticDB for PostgreSQL. It complies with OpenGIS standards and supports 2D (X, Y), 3D (X, Y, Z), and 4D (X, Y, Z, M) spatial data. GanosBase Geometry is fully compatible with PostGIS, allowing you to smoothly migrate existing applications.GanosBaseGanosBase
With GanosBase Geometry you can:
Store points, line strings, and polygons in a single geometry column
Build GiST (Generalized Search Tree) spatial indexes for fast proximity and containment queries
Use the full set of PostGIS spatial functions and operators
Prerequisites
Before you begin, ensure that you have:
An AnalyticDB for PostgreSQL instance
The
ganos_spatialrefandganos_geometryextensions installed — submit a ticket to request installation
Quick start
The following steps walk through a complete workflow: create a geometry table, add data, build a spatial index, and run spatial queries.
Step 1: Create a geometry table
Two methods are available. Use Method 1 when you know the geometry type up front. Use Method 2 when you need to add a geometry column to an existing table.
Method 1 — Define the geometry column in the CREATE TABLE statement:
CREATE TABLE roads (
id int4,
road_name varchar(25),
geom geometry(LINESTRING, 3857)
) DISTRIBUTED BY (id);Method 2 — Add a geometry column to an existing table:
CREATE TABLE roads (
id int4,
road_name varchar(25)
) DISTRIBUTED BY (id);
SELECT AddGeometryColumn('roads', 'geom', 3857, 'LINESTRING', 2);The SRID 3857 in both examples refers to the Web Mercator projection (EPSG:3857), which represents coordinates in meters. Choose the SRID that matches your data's coordinate reference system.Step 2: Add a geometry constraint
Enforce geometry validity before inserting data:
ALTER TABLE roads
ADD CONSTRAINT geometry_valid_check CHECK (ST_IsValid(geom));Step 3: Insert geometry data
Use ST_GeomFromText to convert Well-Known Text (WKT) strings into geometry values. The function takes the WKT representation and the SRID.
Coordinates are specified as X Y (longitude latitude). Longitude comes first because it represents the x-axis. For SRID 3857, coordinates are in meters, not degrees.
INSERT INTO roads (id, geom, road_name) VALUES
(1, ST_GeomFromText('LINESTRING(191232 243118,191108 243242)', 3857), 'North Fifth-ring Road'),
(2, ST_GeomFromText('LINESTRING(189141 244158,189265 244817)', 3857), 'East Fifth-ring Road'),
(3, ST_GeomFromText('LINESTRING(192783 228138,192612 229814)', 3857), 'South Fifth-ring Road'),
(4, ST_GeomFromText('LINESTRING(189412 252431,189631 259122)', 3857), 'West Fifth-ring Road'),
(5, ST_GeomFromText('LINESTRING(190131 224148,190871 228134)', 3857), 'East Chang''an Avenue'),
(6, ST_GeomFromText('LINESTRING(198231 263418,198213 268322)', 3857), 'West Chang''an Avenue');Verify the inserted rows by reading the geometry back as WKT with ST_AsText:
SELECT id, ST_AsText(geom) AS geom, road_name FROM roads;Expected output:
id | geom | road_name
----+-----------------------------------------+-----------------------
1 | LINESTRING(191232 243118,191108 243242) | North Fifth-ring Road
2 | LINESTRING(189141 244158,189265 244817) | East Fifth-ring Road
3 | LINESTRING(192783 228138,192612 229814) | South Fifth-ring Road
4 | LINESTRING(189412 252431,189631 259122) | West Fifth-ring Road
5 | LINESTRING(190131 224148,190871 228134) | East Chang'an Avenue
6 | LINESTRING(198231 263418,198213 268322) | West Chang'an Avenue
(6 rows)Step 4: Create a GiST spatial index
GiST indexes accelerate spatial queries such as bounding box overlap and containment checks. Create the index on the geometry column, then run VACUUM ANALYZE to update the statistics.
-- Standard 2D index
CREATE INDEX sp_geom_index ON roads USING GIST (geom);
-- N-dimensional index (for 3D or 4D data)
-- CREATE INDEX sp_geom_index_nd ON roads USING GIST (geom gist_geometry_ops_nd);
VACUUM ANALYZE roads (geom);Step 5: Run spatial queries
The following examples use two sample tables. Create these tables and populate them with your own data before running the queries.
bc_roads — road network:
| Column | Type | Description |
|---|---|---|
gid | integer | Unique ID |
name | character varying | Road name |
the_geom | geometry | Location geometry (linestring) |
bc_municipality — municipal boundaries:
| Column | Type | Description |
|---|---|---|
gid | integer | Unique ID |
code | integer | Unique code |
name | character varying | City or town name |
the_geom | geometry | Location geometry (polygon) |
Measure geometry
Use ST_Length and ST_Area to compute distances and areas. Both functions return results in the units of the geometry's coordinate reference system (meters for SRID 3857).
-- Total road length in kilometers
SELECT SUM(ST_Length(the_geom)) / 1000 AS km_roads FROM bc_roads; km_roads
------------------
70842.1243039643
(1 row)-- Area of a specific municipality in hectares
SELECT ST_Area(the_geom) / 10000 AS hectares
FROM bc_municipality
WHERE name = 'PRINCE GEORGE'; hectares
------------------
32657.9103824927
(1 row)Test spatial relationships
GanosBase Geometry supports the full set of PostGIS spatial relationship functions. The table below lists the most common ones.
| Function | Returns true when |
|---|---|
ST_Contains(A, B) | A contains B completely |
ST_Covers(A, B) | A covers B (boundary included) |
ST_Within(A, B) | A is completely inside B |
ST_Intersects(A, B) | A and B share any point |
ST_Disjoint(A, B) | A and B share no points |
ST_Touches(A, B) | A and B share only boundary points |
ST_Overlaps(A, B) | A and B overlap but neither contains the other |
ST_Crosses(A, B) | A and B cross (different dimension intersection) |
ST_Relate(A, B, matrix) | A and B satisfy the given DE-9IM pattern |
Example — find road length per municipality using ST_Contains:
SELECT m.name, SUM(ST_Length(r.the_geom)) / 1000 AS roads_km
FROM bc_roads AS r, bc_municipality AS m
WHERE ST_Contains(m.the_geom, r.the_geom)
GROUP BY m.name
ORDER BY roads_km;Example — compare coverage between two circles using ST_Covers:
SELECT
ST_Covers(smallc, smallc) AS smallinsmall,
ST_Covers(smallc, bigc) AS smallcoversbig,
ST_Covers(bigc, ST_ExteriorRing(bigc)) AS bigcoversexterior,
ST_Contains(bigc, ST_ExteriorRing(bigc)) AS bigcontainsexterior
FROM (
SELECT
ST_Buffer(ST_GeomFromText('POINT(1 2)'), 10) AS smallc,
ST_Buffer(ST_GeomFromText('POINT(1 2)'), 20) AS bigc
) AS foo; smallinsmall | smallcoversbig | bigcoversexterior | bigcontainsexterior
--------------+----------------+-------------------+---------------------
t | f | t | f
(1 row)ST_CoversandST_Containsdiffer in how they handle boundary points.ST_Coversreturns true when A covers the boundary of B;ST_Containsdoes not.
Example — test disjoint points and lines using ST_Disjoint:
-- Point not on line: disjoint
SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 2 0, 0 2 )'::geometry);
-- Result: t
-- Point on line: not disjoint
SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 0 0, 0 2 )'::geometry);
-- Result: fExample — test overlap and intersection using ST_Overlaps:
SELECT ST_Overlaps(a, b) AS a_overlap_b,
ST_Crosses(a, b) AS a_crosses_b,
ST_Intersects(a, b) AS a_intersects_b,
ST_Contains(b, a) AS b_contains_a
FROM (
SELECT ST_GeomFromText('POINT(1 0.5)') AS a,
ST_GeomFromText('LINESTRING(1 0, 1 1, 3 5)') AS b
) AS foo; a_overlap_b | a_crosses_b | a_intersects_b | b_contains_a
-------------+-------------+----------------+--------------
f | f | t | tExample — test a spatial relationship using ST_Relate:
SELECT ST_Relate(ST_GeometryFromText('POINT(1 2)'), ST_Buffer(ST_GeometryFromText('POINT(1 2)'), 2), '0FFFFF212'); st_relate
-----------
tExample — test whether a point touches a line using ST_Touches:
-- Interior point: does not touch (ST_Touches requires boundary contact only)
SELECT ST_Touches('LINESTRING(0 0, 1 1, 0 2)'::geometry, 'POINT(1 1)'::geometry);
-- Result: f
-- Endpoint of line: touches
SELECT ST_Touches('LINESTRING(0 0, 1 1, 0 2)'::geometry, 'POINT(0 2)'::geometry);
-- Result: tExample — check containment for nested circles using ST_Within:
SELECT
ST_Within(smallc, smallc) AS smallinsmall,
ST_Within(smallc, bigc) AS smallinbig,
ST_Within(bigc, smallc) AS biginsmall,
ST_Within(ST_Union(smallc, bigc), bigc) AS unioninbig,
ST_Within(bigc, ST_Union(smallc, bigc)) AS biginunion,
ST_Equals(bigc, ST_Union(smallc, bigc)) AS bigisunion
FROM (
SELECT
ST_Buffer(ST_GeomFromText('POINT(50 50)'), 20) AS smallc,
ST_Buffer(ST_GeomFromText('POINT(50 50)'), 40) AS bigc
) AS foo; smallinsmall | smallinbig | biginsmall | unioninbig | biginunion | bigisunion
--------------+------------+------------+------------+------------+------------
t | t | f | t | t | t
(1 row)Check geometry validity
Use ST_IsSimple to verify that a geometry has no self-intersections, and ST_NRings to count the rings in a polygon.
-- A valid closed ring (simple polygon)
SELECT ST_IsSimple(ST_GeomFromText('POLYGON((1 2, 3 4, 5 6, 1 2))'));
-- Result: t
-- A self-intersecting linestring (not simple)
SELECT ST_IsSimple(ST_GeomFromText('LINESTRING(1 1,2 2,2 3.5,1 3,1 2,2 1)'));
-- Result: f
-- Find the municipality with the largest area that has more than one ring
SELECT gid, name, ST_Area(the_geom) AS area
FROM bc_municipality
WHERE ST_NRings(the_geom) > 1
ORDER BY area DESC
LIMIT 1; gid | name | area
-----+--------+------------------
12 | Anning | 257374619.430216
(1 row)Step 6: Remove the extensions
To uninstall GanosBase Geometry, drop the extensions in this order:
DROP EXTENSION ganos_geometry;
DROP EXTENSION ganos_spatialref;Dropping the extensions removes all geometry functions and operators. Any tables with geometry columns will lose the ability to use spatial functions until the extensions are reinstalled.
SQL reference
GanosBase Geometry is fully compatible with PostGIS. For the complete list of supported functions and operators, see the PostGIS reference.