Search Shortcut cmd + k | ctrl + k
duck_geoarrow

DuckDB extension for converting GEOMETRY/WKB to and from GeoArrow native encodings, powered by geoarrow-c.

Maintainer(s): am2222

Installing and Loading

INSTALL duck_geoarrow FROM community;
LOAD duck_geoarrow;

Example

INSTALL duck_geoarrow FROM community;
LOAD duck_geoarrow;

-- Read a GeoArrow-encoded GeoParquet file written by geopandas. A geometry column
-- written with encoding="polygon" arrives as STRUCT(x DOUBLE, y DOUBLE)[][].
SELECT county_name, st_geomfromgeoarrow('polygon', geometry) AS geom
FROM read_parquet('county_regions.parquet');

-- Write GEOMETRY back out as a GeoArrow native encoding
COPY (SELECT county_name, st_asgeoarrowpolygon(geom) AS geometry FROM counties)
TO 'counties.parquet';

-- GEOMETRY -> GeoArrow native encoding, one function per geometry type
SELECT st_asgeoarrowpoint('POINT(30 10)'::GEOMETRY);
-- {'x': 30.0, 'y': 10.0}

SELECT st_asgeoarrowpolygon('POLYGON((0 0, 1 0, 1 1, 0 0))'::GEOMETRY);
-- [[{'x': 0.0, 'y': 0.0}, {'x': 1.0, 'y': 0.0}, {'x': 1.0, 'y': 1.0}, {'x': 0.0, 'y': 0.0}]]

-- GeoArrow native encoding -> GEOMETRY; the type name disambiguates colliding shapes
SELECT st_geomfromgeoarrow('linestring', [{'x': 0.0, 'y': 0.0}, {'x': 1.0, 'y': 1.0}]),
       st_geomfromgeoarrow('multipoint', [{'x': 0.0, 'y': 0.0}, {'x': 1.0, 'y': 1.0}]);
-- LINESTRING (0 0, 1 1)  |  MULTIPOINT (0 0, 1 1)

-- Z and M: reading infers them from the value, writing takes them as an argument
SELECT st_geomfromgeoarrow('point', {'x': 1.0, 'y': 2.0, 'z': 3.0});
-- POINT Z (1 2 3)
SELECT st_asgeoarrowpoint('POINT Z (1 2 3)'::GEOMETRY, 'xyz');
-- {'x': 1.0, 'y': 2.0, 'z': 3.0}

-- Flat struct form: one struct per geometry with parallel coordinate arrays
SELECT st_asgeoarrow('POINT(30 10)'::GEOMETRY);
-- {'geometry_type': 1, 'xs': [30.0], 'ys': [10.0], 'ring_offsets': [], 'geom_offsets': []}

SELECT duck_geoarrow_version();

About duck_geoarrow

duck_geoarrow converts between DuckDB GEOMETRY (or WKB BLOB) and the GeoArrow coordinate encodings, powered by the geoarrow-c library.

Two GeoArrow representations are supported:

  • Native encodings: nested lists of separated coordinates (STRUCT(x, y)[][] for a Polygon, and so on). This is what GeoParquet, geoarrow-pyarrow and geopandas produce, so it is the one to reach for when reading or writing files.
  • A flat struct: one struct per geometry holding parallel coordinate and offset arrays (geometry_type, xs, ys, optional zs / ms, ring_offsets, geom_offsets). Convenient for hand-building geometries in SQL.

Both directions support XY, XYZ, XYM and XYZM.

Functions

Function Direction Notes
st_geomfromgeoarrow(type, value) GeoArrow → GEOMETRY Generic: any native encoding, type given as a string
st_geomfromgeoarrow<type>(value) GeoArrow → GEOMETRY One name per geometry type
st_geomfromgeoarrow(struct) GeoArrow → GEOMETRY Flat struct form
st_asgeoarrow<type>(geom[, dims]) GEOMETRY → GeoArrow Native encoding for one geometry type
st_asgeoarrow(geom[, dims]) GEOMETRY → GeoArrow Flat struct form
duck_geoarrow_version() — Extension and geoarrow-c versions

<type> is one of point, linestring, polygon, multipoint, multilinestring or multipolygon. All conversion functions accept either GEOMETRY or a BLOB holding WKB.

Native encodings

Geometry type DuckDB type GEOMETRY → GeoArrow GeoArrow → GEOMETRY
Point STRUCT(x, y) st_asgeoarrowpoint st_geomfromgeoarrowpoint
LineString STRUCT(x, y)[] st_asgeoarrowlinestring st_geomfromgeoarrowlinestring
Polygon STRUCT(x, y)[][] st_asgeoarrowpolygon st_geomfromgeoarrowpolygon
MultiPoint STRUCT(x, y)[] st_asgeoarrowmultipoint st_geomfromgeoarrowmultipoint
MultiLineString STRUCT(x, y)[][] st_asgeoarrowmultilinestring st_geomfromgeoarrowmultilinestring
MultiPolygon STRUCT(x, y)[][][] st_asgeoarrowmultipolygon st_geomfromgeoarrowmultipolygon

These are the separated-coordinate layouts from the GeoArrow specification, so the values interoperate directly with other GeoArrow implementations.

The generic st_geomfromgeoarrow(type, value) exists because the DuckDB types collide: LineString and MultiPoint are both STRUCT(x, y)[], and Polygon and MultiLineString are both STRUCT(x, y)[][]. The type name is resolved at bind time, so an unknown type or a mismatched shape is a binder error rather than a runtime one. Names are case- and separator-insensitive and may carry a z, m or zm suffix.

Z and M dimensions

GeoArrow carries extra ordinates in the coordinate struct (STRUCT(x, y, z), STRUCT(x, y, m), STRUCT(x, y, z, m)), and the flat struct gains matching zs / ms lists. Reading needs no extra argument since the value's type says which ordinates are present. Writing takes the dimensions as an argument (xy, xyz, xym, xyzm) because a SQL function's return type must be fixed before any data is seen; omitting it means xy. Dropping ordinates is allowed, inventing them is not: asking for xyz from a 2D geometry raises an error rather than filling in NaNs.

Notes

  • NULL input produces NULL output. A NULL inside a list (a null ring, say) is read as an empty ring, since the GeoArrow native encoding only carries validity at the top level.
  • GeometryCollection, and the geoarrow.box and interleaved-coordinate encodings, are not supported.

Added Functions

function_name function_type description comment examples
duck_geoarrow_version scalar Returns the version of the duck_geoarrow extension together with the version of the bundled geoarrow-c library. NULL [duck_geoarrow_version()]
st_asgeoarrow scalar Converts a GEOMETRY or WKB BLOB to the flat GeoArrow encoding, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'); dropping ordinates the geometry carries is allowed, asking for ones it does not have is an error. NULL [st_asgeoarrow('LINESTRING ZM (0 0 1 5, 1 1 2 6)'::GEOMETRY, 'xyzm')]
st_asgeoarrow scalar Converts a GEOMETRY or WKB BLOB to the flat GeoArrow encoding: one STRUCT per geometry holding a geometry_type code alongside parallel coordinate (xs, ys) and offset (ring_offsets, geom_offsets) arrays, with XY coordinates. NULL [st_asgeoarrow('POINT(30 10)'::GEOMETRY)]
st_asgeoarrowlinestring scalar Converts a LineString GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)[]), erroring if the input is not a LineString. NULL [st_asgeoarrowlinestring('LINESTRING (0 0, 4 0)'::GEOMETRY)]
st_asgeoarrowlinestring scalar Converts a LineString GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowlinestring('LINESTRING Z (0 0 1, 4 0 2)'::GEOMETRY, 'xyz')]
st_asgeoarrowmultilinestring scalar Converts a MultiLineString GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)[][]), erroring if the input is not a MultiLineString. NULL [st_asgeoarrowmultilinestring('MULTILINESTRING ((0 0, 4 0), (4 4, 8 8))'::GEOMETRY)]
st_asgeoarrowmultilinestring scalar Converts a MultiLineString GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowmultilinestring('MULTILINESTRING Z ((0 0 1, 4 0 2), (4 4 3, 8 8 4))'::GEOMETRY, 'xyz')]
st_asgeoarrowmultipoint scalar Converts a MultiPoint GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)[]), erroring if the input is not a MultiPoint. NULL [st_asgeoarrowmultipoint('MULTIPOINT (0 0, 4 0)'::GEOMETRY)]
st_asgeoarrowmultipoint scalar Converts a MultiPoint GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowmultipoint('MULTIPOINT Z (0 0 1, 4 0 2)'::GEOMETRY, 'xyz')]
st_asgeoarrowmultipolygon scalar Converts a MultiPolygon GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)[][][]), erroring if the input is not a MultiPolygon. NULL [st_asgeoarrowmultipolygon('MULTIPOLYGON (((0 0, 4 0, 4 4, 0 0)))'::GEOMETRY)]
st_asgeoarrowmultipolygon scalar Converts a MultiPolygon GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowmultipolygon('MULTIPOLYGON Z (((0 0 1, 4 0 2, 4 4 3, 0 0 1)))'::GEOMETRY, 'xyz')]
st_asgeoarrowpoint scalar Converts a Point GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)), erroring if the input is not a Point. NULL [st_asgeoarrowpoint('POINT (30 10)'::GEOMETRY)]
st_asgeoarrowpoint scalar Converts a Point GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowpoint('POINT Z (0 0 1)'::GEOMETRY, 'xyz')]
st_asgeoarrowpolygon scalar Converts a Polygon GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type (STRUCT(x DOUBLE, y DOUBLE)[][]), erroring if the input is not a Polygon. NULL [st_asgeoarrowpolygon('POLYGON ((0 0, 4 0, 4 4, 0 0))'::GEOMETRY)]
st_asgeoarrowpolygon scalar Converts a Polygon GEOMETRY or WKB BLOB into the GeoArrow native encoding for that geometry type, writing the ordinates named by dims ('xy', 'xyz', 'xym' or 'xyzm'). NULL [st_asgeoarrowpolygon('POLYGON Z ((0 0 1, 4 0 2, 4 4 3, 0 0 1))'::GEOMETRY, 'xyz')]
st_geomfromgeoarrow scalar Converts a flat GeoArrow struct back into a GEOMETRY; fields are matched by name, so their order in the struct does not matter, and the zs / ms lists are read when present. NULL [st_geomfromgeoarrow({'geometry_type': 2::UTINYINT, 'xs': [0.0, 1.0, 2.0], 'ys': [0.0, 1.0, 2.0], 'ring_offsets': []::INTEGER[], 'geom_offsets': []::INTEGER[]})]
st_geomfromgeoarrow scalar Converts any GeoArrow native encoding into a GEOMETRY, with geometry_type naming the type as a constant string ('point', 'linestring', 'polygon', 'multipoint', 'multilinestring' or 'multipolygon', optionally with a z, m or zm suffix); the name is required because LineString and MultiPoint, and Polygon and MultiLineString, share one DuckDB type. NULL [st_geomfromgeoarrow('linestring', [{'x': 0.0, 'y': 0.0}, {'x': 1.0, 'y': 1.0}])]
st_geomfromgeoarrowlinestring scalar Converts a GeoArrow native LineString encoding (STRUCT(x DOUBLE, y DOUBLE)[], or its XYZ / XYM / XYZM equivalent) into a LineString GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowlinestring([{'x': 0.0, 'y': 0.0}, {'x': 4.0, 'y': 0.0}])]
st_geomfromgeoarrowmultilinestring scalar Converts a GeoArrow native MultiLineString encoding (STRUCT(x DOUBLE, y DOUBLE)[][], or its XYZ / XYM / XYZM equivalent) into a MultiLineString GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowmultilinestring([[{'x': 0.0, 'y': 0.0}, {'x': 4.0, 'y': 0.0}], [{'x': 4.0, 'y': 4.0}, {'x': 8.0, 'y': 8.0}]])]
st_geomfromgeoarrowmultipoint scalar Converts a GeoArrow native MultiPoint encoding (STRUCT(x DOUBLE, y DOUBLE)[], or its XYZ / XYM / XYZM equivalent) into a MultiPoint GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowmultipoint([{'x': 0.0, 'y': 0.0}, {'x': 4.0, 'y': 0.0}])]
st_geomfromgeoarrowmultipolygon scalar Converts a GeoArrow native MultiPolygon encoding (STRUCT(x DOUBLE, y DOUBLE)[][][], or its XYZ / XYM / XYZM equivalent) into a MultiPolygon GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowmultipolygon([[[{'x': 0.0, 'y': 0.0}, {'x': 4.0, 'y': 0.0}, {'x': 4.0, 'y': 4.0}, {'x': 0.0, 'y': 0.0}]]])]
st_geomfromgeoarrowpoint scalar Converts a GeoArrow native Point encoding (STRUCT(x DOUBLE, y DOUBLE), or its XYZ / XYM / XYZM equivalent) into a Point GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowpoint({'x': 30.0, 'y': 10.0})]
st_geomfromgeoarrowpolygon scalar Converts a GeoArrow native Polygon encoding (STRUCT(x DOUBLE, y DOUBLE)[][], or its XYZ / XYM / XYZM equivalent) into a Polygon GEOMETRY; the value's own type says which ordinates are present, so no dimensions argument is needed. NULL [st_geomfromgeoarrowpolygon([[{'x': 0.0, 'y': 0.0}, {'x': 4.0, 'y': 0.0}, {'x': 4.0, 'y': 4.0}, {'x': 0.0, 'y': 0.0}]])]

Overloaded Functions

This extension does not add any function overloads.

Added Types

This extension does not add any types.

Added Settings

This extension does not add any settings.