duckdb / duckdb/duckdb-spatial
`ST_Dump` inconsistency for EMPTY geometries
- Dominant language
- C
- Stars
- 708
- Forks
- 96
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 5
Description
## Affected Versions
- **DuckDB**: v1.5.5-dev150 (development build)
- **Spatial**: debug build from `duckdb_spatial/` (GEOS-backed)
## Reproducible Script
```python
import duckdb
conn = duckdb.connect(":memory:", config={"allow_unsigned_extensions": True})
conn.execute("INSTALL spatial;")
conn.execute("LOAD spatial;")
# === Bug 1: ST_Dump returns 1 row for singleton EMPTY geometries ===
# ST_NumGeometries returns 0, but len(ST_Dump(...)) returns 1
for wkt in ["POINT EMPTY", "LINESTRING EMPTY", "POLYGON EMPTY"]:
sql = f"""
SELECT
ST_NumGeometries(ST_GeomFromText('{wkt}')) AS ng,
len(ST_Dump(ST_GeomFromText('{wkt}'))) AS dump_len,
ST_IsEmpty(ST_GeomFromText('{wkt}')) AS empty
"""
r = conn.execute(sql).fetchone()
ok = "" if r[0] == r[1] else " <<< BUG"
print(f"{wkt:20} NumGeom={r[0]} DumpLen={r[1]} IsEmpty={r[2]}{ok}")
# === Bug 2: ST_NumGeometries counts typed-empty GC children ===
# IsEmpty=True and NumGeom>0, but Dump returns 0
for wkt in [
"GEOMETRYCOLLECTION(MULTILINESTRING EMPTY)",
"GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY)",
"GEOMETRYCOLLECTION EMPTY",
]:
sql = f"""
SELECT
ST_NumGeometries(ST_GeomFromText('{wkt}')) AS ng,
len(ST_Dump(ST_GeomFromText('{wkt}'))) AS dump_len,
ST_IsEmpty(ST_GeomFromText('{wkt}')) AS empty
"""
r = conn.execute(sql).fetchone()
ok = "" if r[0] == r[1] else " <<< BUG"
print(f"{wkt:55} NumGeom={r[0]} DumpLen={r[1]} IsEmpty={r[2]}{ok}")
```
### Actual Output
```
POINT EMPTY NumGeom=0 DumpLen=1 IsEmpty=True <<< BUG
LINESTRING EMPTY NumGeom=0 DumpLen=1 IsEmpty=True <<< BUG
POLYGON EMPTY NumGeom=0 DumpLen=1 IsEmpty=True <<< BUG
GEOMETRYCOLLECTION(MULTILINESTRING EMPTY) NumGeom=1 DumpLen=0 IsEmpty=True <<< BUG
GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY) NumGeom=1 DumpLen=0 IsEmpty=True <<< BUG
GEOMETRYCOLLECTION EMPTY NumGeom=0 DumpLen=0 IsEmpty=True OK
```
### Expected Output (PostGIS 3.7 / GEOS 3.15 reference)
```
POINT EMPTY NumGeom=0 DumpLen=0 IsEmpty=True OK
LINESTRING EMPTY NumGeom=0 DumpLen=0 IsEmpty=True OK
POLYGON EMPTY NumGeom=0 DumpLen=0 IsEmpty=True OK
GEOMETRYCOLLECTION(MULTILINESTRING EMPTY) NumGeom=0 DumpLen=0 IsEmpty=True OK
GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY) NumGeom=0 DumpLen=0 IsEmpty=True OK
GEOMETRYCOLLECTION EMPTY NumGeom=0 DumpLen=0 IsEmpty=True OK
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating the spatial extension entry points for ST_Dump and ST_NumGeometries in duckdb_spatial/, then run the reproducible Python script against the listed EMPTY geometries. The work is done when ST_Dump and ST_NumGeometries agree for all cases and match the expected output shown in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100