From fe7b8d51e38ea691968de6a5863534978f836ad7 Mon Sep 17 00:00:00 2001
From: Erik Grinaker
Date: Sat, 12 Sep 2020 15:56:22 +0200
Subject: [PATCH] builtins: implement ST_Boundary, ST_Difference, and ST_Relate
with BNR
Release note (sql change): Implement the geometry builtins
`ST_Boundary`, `ST_Difference`, and `ST_Relate` (BNR variant).
---
docs/generated/sql/functions.md | 9 +
pkg/geo/geomfn/de9im.go | 9 +
pkg/geo/geomfn/de9im_test.go | 34 ++
pkg/geo/geomfn/topology_operations.go | 29 ++
pkg/geo/geomfn/topology_operations_test.go | 63 +++
pkg/geo/geos/geos.cc | 81 +++
pkg/geo/geos/geos.go | 42 ++
pkg/geo/geos/geos.h | 5 +
.../logictest/testdata/logic_test/geospatial | 463 ++++++++++++------
pkg/sql/sem/builtins/geo_builtins.go | 62 ++-
10 files changed, 650 insertions(+), 147 deletions(-)
diff --git a/docs/generated/sql/functions.md b/docs/generated/sql/functions.md
index fda6c5445730..94414c42a364 100644
--- a/docs/generated/sql/functions.md
+++ b/docs/generated/sql/functions.md
@@ -1377,6 +1377,9 @@ has no relationship with the commit order of concurrent transactions.
st_box2dfromgeohash(geohash: string, precision: int) → box2d | Return a Box2D from a GeoHash string with supplied precision.
@@ -1549,6 +1552,9 @@ from the given Geometry.
st_dfullywithinexclusive(geometry_a: geometry, geometry_b: geometry, distance: float) → bool | Returns true if every pair of points comprising geometry_a and geometry_b are within distance units, exclusive. In other words, the ST_MaxDistance between geometry_a and geometry_b is less than distance units.
This function variant will attempt to utilize any available spatial index.
|
+st_difference(geometry_a: geometry, geometry_b: geometry) → geometry | Returns the difference of two Geometries.
+This function utilizes the GEOS module.
+ |
st_dimension(geometry: geometry) → int | Returns the number of topological dimensions of a given Geometry.
|
st_disjoint(geometry_a: geometry, geometry_b: geometry) → bool | Returns true if geometry_a does not overlap, touch or is within geometry_b.
@@ -1987,6 +1993,9 @@ Negative azimuth values and values greater than 2π (360 degrees) are supported.
st_relate(geometry_a: geometry, geometry_b: geometry) → string | Returns the DE-9IM spatial relation between geometry_a and geometry_b.
This function utilizes the GEOS module.
|
+st_relate(geometry_a: geometry, geometry_b: geometry, bnr: int) → string | Returns the DE-9IM spatial relation between geometry_a and geometry_b using the given boundary node rule (1:OGC/MOD2, 2:Endpoint, 3:MultivalentEndpoint, 4:MonovalentEndpoint).
+This function utilizes the GEOS module.
+ |
st_relate(geometry_a: geometry, geometry_b: geometry, pattern: string) → bool | Returns whether the DE-9IM spatial relation between geometry_a and geometry_b matches the DE-9IM pattern.
This function utilizes the GEOS module.
|
diff --git a/pkg/geo/geomfn/de9im.go b/pkg/geo/geomfn/de9im.go
index e3aa1d0ad094..40b4318d5e71 100644
--- a/pkg/geo/geomfn/de9im.go
+++ b/pkg/geo/geomfn/de9im.go
@@ -25,6 +25,15 @@ func Relate(a geo.Geometry, b geo.Geometry) (string, error) {
return geos.Relate(a.EWKB(), b.EWKB())
}
+// RelateBoundaryNodeRule returns the DE-9IM relation between A and B using
+// the given boundary node rule (as specified by GEOS).
+func RelateBoundaryNodeRule(a, b geo.Geometry, bnr int) (string, error) {
+ if a.SRID() != b.SRID() {
+ return "", geo.NewMismatchingSRIDsError(a.SpatialObject(), b.SpatialObject())
+ }
+ return geos.RelateBoundaryNodeRule(a.EWKB(), b.EWKB(), bnr)
+}
+
// RelatePattern returns whether the DE-9IM relation between A and B matches.
func RelatePattern(a geo.Geometry, b geo.Geometry, pattern string) (bool, error) {
if a.SRID() != b.SRID() {
diff --git a/pkg/geo/geomfn/de9im_test.go b/pkg/geo/geomfn/de9im_test.go
index 6849b900dec1..9203899a10c3 100644
--- a/pkg/geo/geomfn/de9im_test.go
+++ b/pkg/geo/geomfn/de9im_test.go
@@ -36,6 +36,40 @@ func TestRelate(t *testing.T) {
}
}
+func TestRelateBoundaryNodeRule(t *testing.T) {
+ testCases := []struct {
+ a geo.Geometry
+ b geo.Geometry
+ bnr int
+ expected string
+ }{
+ {leftRect, rightRect, 1, "FF2F11212"},
+ {leftRect, rightRect, 2, "FF2F11212"},
+ {leftRect, rightRect, 3, "1F2F002F2"},
+ {leftRect, rightRect, 4, "FF2F11212"},
+ }
+
+ for i, tc := range testCases {
+ t.Run(fmt.Sprintf("tc:%d", i), func(t *testing.T) {
+ ret, err := RelateBoundaryNodeRule(tc.a, tc.b, tc.bnr)
+ require.NoError(t, err)
+ require.Equal(t, tc.expected, ret)
+ })
+ }
+
+ t.Run("errors on invalid BNR", func(t *testing.T) {
+ _, err := RelateBoundaryNodeRule(leftRect, rightRect, 0)
+ require.Error(t, err)
+ _, err = RelateBoundaryNodeRule(leftRect, rightRect, 5)
+ require.Error(t, err)
+ })
+
+ t.Run("errors if SRIDs mismatch", func(t *testing.T) {
+ _, err := RelateBoundaryNodeRule(mismatchingSRIDGeometryA, mismatchingSRIDGeometryB, 1)
+ requireMismatchingSRIDError(t, err)
+ })
+}
+
func TestMatchesDE9IM(t *testing.T) {
testCases := []struct {
str string
diff --git a/pkg/geo/geomfn/topology_operations.go b/pkg/geo/geomfn/topology_operations.go
index 6254da502169..b7f20ad23a61 100644
--- a/pkg/geo/geomfn/topology_operations.go
+++ b/pkg/geo/geomfn/topology_operations.go
@@ -15,6 +15,19 @@ import (
"github.com/cockroachdb/cockroach/pkg/geo/geos"
)
+// Boundary returns the boundary of a given Geometry.
+func Boundary(g geo.Geometry) (geo.Geometry, error) {
+ // follow PostGIS behavior
+ if g.Empty() {
+ return g, nil
+ }
+ boundaryEWKB, err := geos.Boundary(g.EWKB())
+ if err != nil {
+ return geo.Geometry{}, err
+ }
+ return geo.ParseGeometryFromEWKB(boundaryEWKB)
+}
+
// Centroid returns the Centroid of a given Geometry.
func Centroid(g geo.Geometry) (geo.Geometry, error) {
centroidEWKB, err := geos.Centroid(g.EWKB())
@@ -45,6 +58,22 @@ func ConvexHull(g geo.Geometry) (geo.Geometry, error) {
return geo.ParseGeometryFromEWKB(convexHullEWKB)
}
+// Difference returns the difference between two given Geometries.
+func Difference(a, b geo.Geometry) (geo.Geometry, error) {
+ // follow PostGIS behavior
+ if a.Empty() || b.Empty() {
+ return a, nil
+ }
+ if a.SRID() != b.SRID() {
+ return geo.Geometry{}, geo.NewMismatchingSRIDsError(a.SpatialObject(), b.SpatialObject())
+ }
+ diffEWKB, err := geos.Difference(a.EWKB(), b.EWKB())
+ if err != nil {
+ return geo.Geometry{}, err
+ }
+ return geo.ParseGeometryFromEWKB(diffEWKB)
+}
+
// Simplify returns a simplified Geometry.
func Simplify(g geo.Geometry, tolerance float64) (geo.Geometry, error) {
simplifiedEWKB, err := geos.Simplify(g.EWKB(), tolerance)
diff --git a/pkg/geo/geomfn/topology_operations_test.go b/pkg/geo/geomfn/topology_operations_test.go
index 0c250ab0672e..53a4da5d1f86 100644
--- a/pkg/geo/geomfn/topology_operations_test.go
+++ b/pkg/geo/geomfn/topology_operations_test.go
@@ -20,6 +20,36 @@ import (
"github.com/twpayne/go-geom"
)
+func TestBoundary(t *testing.T) {
+ testCases := []struct {
+ wkt string
+ expected string
+ }{
+ {"POINT EMPTY", "POINT EMPTY"},
+ {"POINT (1 1)", "GEOMETRYCOLLECTION EMPTY"},
+ {"LINESTRING EMPTY", "LINESTRING EMPTY"},
+ {"LINESTRING (100 150, 50 60, 70 80, 160 170)", "MULTIPOINT (100 150, 160 170)"},
+ {"SRID=4000;LINESTRING (100 150, 50 60, 70 80, 160 170)", "SRID=4000;MULTIPOINT (100 150, 160 170)"},
+ {
+ "POLYGON ((10 130, 50 190, 110 190, 140 150, 150 80, 100 10, 20 40, 10 130), (70 40, 100 50, 120 80, 80 110, 50 90, 70 40))",
+ "MULTILINESTRING ((10 130, 50 190, 110 190, 140 150, 150 80, 100 10, 20 40, 10 130), (70 40, 100 50, 120 80, 80 110, 50 90, 70 40))",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.wkt, func(t *testing.T) {
+ g, err := geo.ParseGeometry(tc.wkt)
+ require.NoError(t, err)
+ ret, err := Boundary(g)
+ require.NoError(t, err)
+
+ wkt, err := geo.SpatialObjectToEWKT(ret.SpatialObject(), 0)
+ require.NoError(t, err)
+ require.EqualValues(t, tc.expected, wkt)
+ })
+ }
+}
+
func TestCentroid(t *testing.T) {
testCases := []struct {
wkt string
@@ -93,6 +123,39 @@ func TestConvexHull(t *testing.T) {
}
}
+func TestDifference(t *testing.T) {
+ testCases := []struct {
+ wkt1 string
+ wkt2 string
+ expected string
+ }{
+ {"POINT EMPTY", "LINESTRING EMPTY", "POINT EMPTY"},
+ {"LINESTRING EMPTY", "POINT EMPTY", "LINESTRING EMPTY"},
+ {"LINESTRING (50 100, 50 200)", "LINESTRING(50 50, 50 150)", "LINESTRING (50 150, 50 200)"},
+ {"SRID=4000;LINESTRING (50 100, 50 200)", "SRID=4000;LINESTRING(50 50, 50 150)", "SRID=4000;LINESTRING (50 150, 50 200)"},
+ }
+
+ for _, tc := range testCases {
+ t.Run(fmt.Sprintf("%v - %v", tc.wkt2, tc.wkt1), func(t *testing.T) {
+ g1, err := geo.ParseGeometry(tc.wkt1)
+ require.NoError(t, err)
+ g2, err := geo.ParseGeometry(tc.wkt2)
+ require.NoError(t, err)
+ ret, err := Difference(g1, g2)
+ require.NoError(t, err)
+
+ wkt, err := geo.SpatialObjectToEWKT(ret.SpatialObject(), 0)
+ require.NoError(t, err)
+ require.EqualValues(t, tc.expected, wkt)
+ })
+ }
+
+ t.Run("errors if SRIDs mismatch", func(t *testing.T) {
+ _, err := Difference(mismatchingSRIDGeometryA, mismatchingSRIDGeometryB)
+ requireMismatchingSRIDError(t, err)
+ })
+}
+
func TestSimplify(t *testing.T) {
testCases := []struct {
wkt string
diff --git a/pkg/geo/geos/geos.cc b/pkg/geo/geos/geos.cc
index d5918342c9a9..31d5595e11da 100644
--- a/pkg/geo/geos/geos.cc
+++ b/pkg/geo/geos/geos.cc
@@ -97,8 +97,11 @@ typedef int (*CR_GEOS_Length_r)(CR_GEOS_Handle, CR_GEOS_Geometry, double*);
typedef int (*CR_GEOS_Normalize_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_LineMerge_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
+typedef CR_GEOS_Geometry (*CR_GEOS_Boundary_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_Centroid_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_ConvexHull_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
+typedef CR_GEOS_Geometry (*CR_GEOS_Difference_r)(CR_GEOS_Handle, CR_GEOS_Geometry,
+ CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_Simplify_r)(CR_GEOS_Handle, CR_GEOS_Geometry, double);
typedef CR_GEOS_Geometry (*CR_GEOS_TopologyPreserveSimplify_r)(CR_GEOS_Handle, CR_GEOS_Geometry,
double);
@@ -125,6 +128,8 @@ typedef char (*CR_GEOS_Touches_r)(CR_GEOS_Handle, CR_GEOS_Geometry, CR_GEOS_Geom
typedef char (*CR_GEOS_Within_r)(CR_GEOS_Handle, CR_GEOS_Geometry, CR_GEOS_Geometry);
typedef char* (*CR_GEOS_Relate_r)(CR_GEOS_Handle, CR_GEOS_Geometry, CR_GEOS_Geometry);
+typedef char* (*CR_GEOS_RelateBoundaryNodeRule_r)(CR_GEOS_Handle, CR_GEOS_Geometry,
+ CR_GEOS_Geometry, int);
typedef char (*CR_GEOS_RelatePattern_r)(CR_GEOS_Handle, CR_GEOS_Geometry, CR_GEOS_Geometry,
const char*);
@@ -190,8 +195,10 @@ struct CR_GEOS {
CR_GEOS_Normalize_r GEOSNormalize_r;
CR_GEOS_LineMerge_r GEOSLineMerge_r;
+ CR_GEOS_Boundary_r GEOSBoundary_r;
CR_GEOS_Centroid_r GEOSGetCentroid_r;
CR_GEOS_ConvexHull_r GEOSConvexHull_r;
+ CR_GEOS_Difference_r GEOSDifference_r;
CR_GEOS_Simplify_r GEOSSimplify_r;
CR_GEOS_TopologyPreserveSimplify_r GEOSTopologyPreserveSimplify_r;
CR_GEOS_Union_r GEOSUnion_r;
@@ -215,6 +222,7 @@ struct CR_GEOS {
CR_GEOS_Within_r GEOSWithin_r;
CR_GEOS_Relate_r GEOSRelate_r;
+ CR_GEOS_RelateBoundaryNodeRule_r GEOSRelateBoundaryNodeRule_r;
CR_GEOS_RelatePattern_r GEOSRelatePattern_r;
CR_GEOS_WKBWriter_create_r GEOSWKBWriter_create_r;
@@ -276,6 +284,8 @@ struct CR_GEOS {
INIT(GEOSNormalize_r);
INIT(GEOSLineMerge_r);
INIT(GEOSisSimple_r);
+ INIT(GEOSBoundary_r);
+ INIT(GEOSDifference_r);
INIT(GEOSGetCentroid_r);
INIT(GEOSConvexHull_r);
INIT(GEOSSimplify_r);
@@ -297,6 +307,7 @@ struct CR_GEOS {
INIT(GEOSTouches_r);
INIT(GEOSWithin_r);
INIT(GEOSRelate_r);
+ INIT(GEOSRelateBoundaryNodeRule_r);
INIT(GEOSRelatePattern_r);
INIT(GEOSSharedPaths_r);
INIT(GEOSWKTReader_create_r);
@@ -705,6 +716,24 @@ CR_GEOS_Status CR_GEOS_MakeValid(CR_GEOS* lib, CR_GEOS_Slice g, CR_GEOS_String*
// Topology operators.
//
+CR_GEOS_Status CR_GEOS_Boundary(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* boundaryEWKB) {
+ std::string error;
+ auto handle = initHandleWithErrorBuffer(lib, &error);
+ auto geom = CR_GEOS_GeometryFromSlice(lib, handle, a);
+ *boundaryEWKB = {.data = NULL, .len = 0};
+ if (geom != nullptr) {
+ auto boundaryGeom = lib->GEOSBoundary_r(handle, geom);
+ if (boundaryGeom != nullptr) {
+ auto srid = lib->GEOSGetSRID_r(handle, geom);
+ CR_GEOS_writeGeomToEWKB(lib, handle, boundaryGeom, boundaryEWKB, srid);
+ lib->GEOSGeom_destroy_r(handle, boundaryGeom);
+ }
+ lib->GEOSGeom_destroy_r(handle, geom);
+ }
+ lib->GEOS_finish_r(handle);
+ return toGEOSString(error.data(), error.length());
+}
+
CR_GEOS_Status CR_GEOS_Centroid(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* centroidEWKB) {
std::string error;
auto handle = initHandleWithErrorBuffer(lib, &error);
@@ -741,6 +770,31 @@ CR_GEOS_Status CR_GEOS_ConvexHull(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String*
return toGEOSString(error.data(), error.length());
}
+CR_GEOS_Status CR_GEOS_Difference(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
+ CR_GEOS_String* diffEWKB) {
+ std::string error;
+ auto handle = initHandleWithErrorBuffer(lib, &error);
+ auto geomA = CR_GEOS_GeometryFromSlice(lib, handle, a);
+ auto geomB = CR_GEOS_GeometryFromSlice(lib, handle, b);
+ *diffEWKB = {.data = NULL, .len = 0};
+ if (geomA != nullptr && geomB != nullptr) {
+ auto diffGeom = lib->GEOSDifference_r(handle, geomA, geomB);
+ if (diffGeom != nullptr) {
+ auto srid = lib->GEOSGetSRID_r(handle, geomA);
+ CR_GEOS_writeGeomToEWKB(lib, handle, diffGeom, diffEWKB, srid);
+ lib->GEOSGeom_destroy_r(handle, diffGeom);
+ }
+ }
+ if (geomA != nullptr) {
+ lib->GEOSGeom_destroy_r(handle, geomA);
+ }
+ if (geomB != nullptr) {
+ lib->GEOSGeom_destroy_r(handle, geomB);
+ }
+ lib->GEOS_finish_r(handle);
+ return toGEOSString(error.data(), error.length());
+}
+
CR_GEOS_Status CR_GEOS_Simplify(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* simplifyEWKB,
double tolerance) {
std::string error;
@@ -1017,6 +1071,33 @@ CR_GEOS_Status CR_GEOS_Relate(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b, CR
return toGEOSString(error.data(), error.length());
}
+CR_GEOS_Status CR_GEOS_RelateBoundaryNodeRule(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
+ int bnr, CR_GEOS_String* ret) {
+ std::string error;
+ auto handle = initHandleWithErrorBuffer(lib, &error);
+
+ auto wkbReader = lib->GEOSWKBReader_create_r(handle);
+ auto geomA = lib->GEOSWKBReader_read_r(handle, wkbReader, a.data, a.len);
+ auto geomB = lib->GEOSWKBReader_read_r(handle, wkbReader, b.data, b.len);
+ lib->GEOSWKBReader_destroy_r(handle, wkbReader);
+
+ if (geomA != nullptr && geomB != nullptr) {
+ auto r = lib->GEOSRelateBoundaryNodeRule_r(handle, geomA, geomB, bnr);
+ if (r != NULL) {
+ *ret = toGEOSString(r, strlen(r));
+ lib->GEOSFree_r(handle, r);
+ }
+ }
+ if (geomA != nullptr) {
+ lib->GEOSGeom_destroy_r(handle, geomA);
+ }
+ if (geomB != nullptr) {
+ lib->GEOSGeom_destroy_r(handle, geomB);
+ }
+ lib->GEOS_finish_r(handle);
+ return toGEOSString(error.data(), error.length());
+}
+
CR_GEOS_Status CR_GEOS_RelatePattern(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
CR_GEOS_Slice pattern, char* ret) {
std::string error;
diff --git a/pkg/geo/geos/geos.go b/pkg/geo/geos/geos.go
index dc3a79412818..fff842ea63a4 100644
--- a/pkg/geo/geos/geos.go
+++ b/pkg/geo/geos/geos.go
@@ -326,6 +326,32 @@ func Area(ewkb geopb.EWKB) (float64, error) {
return float64(area), nil
}
+// Boundary returns the boundary of an EWKB.
+func Boundary(ewkb geopb.EWKB) (geopb.EWKB, error) {
+ g, err := ensureInitInternal()
+ if err != nil {
+ return nil, err
+ }
+ var cEWKB C.CR_GEOS_String
+ if err := statusToError(C.CR_GEOS_Boundary(g, goToCSlice(ewkb), &cEWKB)); err != nil {
+ return nil, err
+ }
+ return cStringToSafeGoBytes(cEWKB), nil
+}
+
+// Difference returns the difference between two EWKB.
+func Difference(ewkb1 geopb.EWKB, ewkb2 geopb.EWKB) (geopb.EWKB, error) {
+ g, err := ensureInitInternal()
+ if err != nil {
+ return nil, err
+ }
+ var diffEWKB C.CR_GEOS_String
+ if err := statusToError(C.CR_GEOS_Difference(g, goToCSlice(ewkb1), goToCSlice(ewkb2), &diffEWKB)); err != nil {
+ return nil, err
+ }
+ return cStringToSafeGoBytes(diffEWKB), nil
+}
+
// Length returns the length of an EWKB.
func Length(ewkb geopb.EWKB) (float64, error) {
g, err := ensureInitInternal()
@@ -685,6 +711,22 @@ func Relate(a geopb.EWKB, b geopb.EWKB) (string, error) {
return string(cStringToSafeGoBytes(ret)), nil
}
+// RelateBoundaryNodeRule returns the DE-9IM relation between A and B given a boundary node rule.
+func RelateBoundaryNodeRule(a geopb.EWKB, b geopb.EWKB, bnr int) (string, error) {
+ g, err := ensureInitInternal()
+ if err != nil {
+ return "", err
+ }
+ var ret C.CR_GEOS_String
+ if err := statusToError(C.CR_GEOS_RelateBoundaryNodeRule(g, goToCSlice(a), goToCSlice(b), C.int(bnr), &ret)); err != nil {
+ return "", err
+ }
+ if ret.data == nil {
+ return "", errors.Newf("expected DE-9IM string but found nothing")
+ }
+ return string(cStringToSafeGoBytes(ret)), nil
+}
+
// RelatePattern whether A and B have a DE-9IM relation matching the given pattern.
func RelatePattern(a geopb.EWKB, b geopb.EWKB, pattern string) (bool, error) {
g, err := ensureInitInternal()
diff --git a/pkg/geo/geos/geos.h b/pkg/geo/geos/geos.h
index 80369af9ba65..d5035ddf76a2 100644
--- a/pkg/geo/geos/geos.h
+++ b/pkg/geo/geos/geos.h
@@ -97,8 +97,11 @@ CR_GEOS_Status CR_GEOS_IsSimple(CR_GEOS* lib, CR_GEOS_Slice a, char* ret);
// Topology operators.
//
+CR_GEOS_Status CR_GEOS_Boundary(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* boundaryEWKB);
CR_GEOS_Status CR_GEOS_Centroid(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* centroidEWKB);
CR_GEOS_Status CR_GEOS_ConvexHull(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* convexHullEWKB);
+CR_GEOS_Status CR_GEOS_Difference(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
+ CR_GEOS_String* diffEWKB);
CR_GEOS_Status CR_GEOS_Simplify(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* simplifyEWKB,
double tolerance);
CR_GEOS_Status CR_GEOS_TopologyPreserveSimplify(CR_GEOS* lib, CR_GEOS_Slice a,
@@ -146,6 +149,8 @@ CR_GEOS_Status CR_GEOS_Within(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b, ch
//
CR_GEOS_Status CR_GEOS_Relate(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b, CR_GEOS_String* ret);
+CR_GEOS_Status CR_GEOS_RelateBoundaryNodeRule(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
+ int bnr, CR_GEOS_String* ret);
CR_GEOS_Status CR_GEOS_RelatePattern(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
CR_GEOS_Slice pattern, char* ret);
diff --git a/pkg/sql/logictest/testdata/logic_test/geospatial b/pkg/sql/logictest/testdata/logic_test/geospatial
index 8feeb4b63667..884489b51836 100644
--- a/pkg/sql/logictest/testdata/logic_test/geospatial
+++ b/pkg/sql/logictest/testdata/logic_test/geospatial
@@ -1190,6 +1190,24 @@ Square (left) POINT (-0.5 0.5) POINT (-0.5 0.5) PO
Square (right) POINT (0.5 0.5) POINT (0.5 0.5) POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
Square overlapping left and right square POINT (0.45 0.5) POINT (0.45 0.5) POLYGON ((-0.1 0, -0.1 1, 1 1, 1 0, -0.1 0))
+query TT
+SELECT
+ a.dsc,
+ ST_AsEWKT(ST_Boundary(a.geom))
+FROM geom_operators_test a
+WHERE NOT ST_IsCollection(a.geom)
+ORDER BY a.dsc
+----
+Empty LineString LINESTRING EMPTY
+Empty Point POINT EMPTY
+Faraway point GEOMETRYCOLLECTION EMPTY
+Line going through left and right square MULTIPOINT (-0.5 0.5, 0.5 0.5)
+Point middle of Left Square GEOMETRYCOLLECTION EMPTY
+Point middle of Right Square GEOMETRYCOLLECTION EMPTY
+Square (left) LINESTRING (-1 0, 0 0, 0 1, -1 1, -1 0)
+Square (right) LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)
+Square overlapping left and right square LINESTRING (-0.1 0, 1 0, 1 1, -0.1 1, -0.1 0)
+
query TTT
SELECT
a.dsc,
@@ -1945,6 +1963,160 @@ Square overlapping left and right square Square (left)
Square overlapping left and right square Square (right) LINESTRING (-0.1 0, 1 1) LINESTRING (0 0, 0 0)
Square overlapping left and right square Square overlapping left and right square LINESTRING (-0.1 0, 1 1) LINESTRING (-0.1 0, -0.1 0)
+# ST_Difference
+query TTT
+SELECT
+ a.dsc,
+ b.dsc,
+ ST_AsText(ST_Difference(a.geom, b.geom))
+FROM geom_operators_test a, geom_operators_test b
+ORDER BY a.dsc, b.dsc
+----
+Empty GeometryCollection Empty GeometryCollection GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Empty LineString GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Empty Point GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Faraway point GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Line going through left and right square GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection NULL NULL
+Empty GeometryCollection Nested Geometry Collection GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Point middle of Left Square GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Point middle of Right Square GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Square (left) GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Square (right) GEOMETRYCOLLECTION EMPTY
+Empty GeometryCollection Square overlapping left and right square GEOMETRYCOLLECTION EMPTY
+Empty LineString Empty GeometryCollection LINESTRING EMPTY
+Empty LineString Empty LineString LINESTRING EMPTY
+Empty LineString Empty Point LINESTRING EMPTY
+Empty LineString Faraway point LINESTRING EMPTY
+Empty LineString Line going through left and right square LINESTRING EMPTY
+Empty LineString NULL NULL
+Empty LineString Nested Geometry Collection LINESTRING EMPTY
+Empty LineString Point middle of Left Square LINESTRING EMPTY
+Empty LineString Point middle of Right Square LINESTRING EMPTY
+Empty LineString Square (left) LINESTRING EMPTY
+Empty LineString Square (right) LINESTRING EMPTY
+Empty LineString Square overlapping left and right square LINESTRING EMPTY
+Empty Point Empty GeometryCollection POINT EMPTY
+Empty Point Empty LineString POINT EMPTY
+Empty Point Empty Point POINT EMPTY
+Empty Point Faraway point POINT EMPTY
+Empty Point Line going through left and right square POINT EMPTY
+Empty Point NULL NULL
+Empty Point Nested Geometry Collection POINT EMPTY
+Empty Point Point middle of Left Square POINT EMPTY
+Empty Point Point middle of Right Square POINT EMPTY
+Empty Point Square (left) POINT EMPTY
+Empty Point Square (right) POINT EMPTY
+Empty Point Square overlapping left and right square POINT EMPTY
+Faraway point Empty GeometryCollection POINT (5 5)
+Faraway point Empty LineString POINT (5 5)
+Faraway point Empty Point POINT (5 5)
+Faraway point Faraway point POINT EMPTY
+Faraway point Line going through left and right square POINT (5 5)
+Faraway point NULL NULL
+Faraway point Nested Geometry Collection POINT (5 5)
+Faraway point Point middle of Left Square POINT (5 5)
+Faraway point Point middle of Right Square POINT (5 5)
+Faraway point Square (left) POINT (5 5)
+Faraway point Square (right) POINT (5 5)
+Faraway point Square overlapping left and right square POINT (5 5)
+Line going through left and right square Empty GeometryCollection LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Empty LineString LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Empty Point LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Faraway point LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Line going through left and right square LINESTRING EMPTY
+Line going through left and right square NULL NULL
+Line going through left and right square Nested Geometry Collection LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Point middle of Left Square LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Point middle of Right Square LINESTRING (-0.5 0.5, 0.5 0.5)
+Line going through left and right square Square (left) LINESTRING (0 0.5, 0.5 0.5)
+Line going through left and right square Square (right) LINESTRING (-0.5 0.5, 0 0.5)
+Line going through left and right square Square overlapping left and right square LINESTRING (-0.5 0.5, -0.1 0.5)
+NULL Empty GeometryCollection NULL
+NULL Empty LineString NULL
+NULL Empty Point NULL
+NULL Faraway point NULL
+NULL Line going through left and right square NULL
+NULL NULL NULL
+NULL Nested Geometry Collection NULL
+NULL Point middle of Left Square NULL
+NULL Point middle of Right Square NULL
+NULL Square (left) NULL
+NULL Square (right) NULL
+NULL Square overlapping left and right square NULL
+Nested Geometry Collection Empty GeometryCollection GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (POINT (0 0)))
+Nested Geometry Collection Empty LineString GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (POINT (0 0)))
+Nested Geometry Collection Empty Point GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (POINT (0 0)))
+Nested Geometry Collection Faraway point POINT (0 0)
+Nested Geometry Collection Line going through left and right square POINT (0 0)
+Nested Geometry Collection NULL NULL
+Nested Geometry Collection Nested Geometry Collection POINT EMPTY
+Nested Geometry Collection Point middle of Left Square POINT (0 0)
+Nested Geometry Collection Point middle of Right Square POINT (0 0)
+Nested Geometry Collection Square (left) POINT EMPTY
+Nested Geometry Collection Square (right) POINT EMPTY
+Nested Geometry Collection Square overlapping left and right square POINT EMPTY
+Point middle of Left Square Empty GeometryCollection POINT (-0.5 0.5)
+Point middle of Left Square Empty LineString POINT (-0.5 0.5)
+Point middle of Left Square Empty Point POINT (-0.5 0.5)
+Point middle of Left Square Faraway point POINT (-0.5 0.5)
+Point middle of Left Square Line going through left and right square POINT EMPTY
+Point middle of Left Square NULL NULL
+Point middle of Left Square Nested Geometry Collection POINT (-0.5 0.5)
+Point middle of Left Square Point middle of Left Square POINT EMPTY
+Point middle of Left Square Point middle of Right Square POINT (-0.5 0.5)
+Point middle of Left Square Square (left) POINT EMPTY
+Point middle of Left Square Square (right) POINT (-0.5 0.5)
+Point middle of Left Square Square overlapping left and right square POINT (-0.5 0.5)
+Point middle of Right Square Empty GeometryCollection POINT (0.5 0.5)
+Point middle of Right Square Empty LineString POINT (0.5 0.5)
+Point middle of Right Square Empty Point POINT (0.5 0.5)
+Point middle of Right Square Faraway point POINT (0.5 0.5)
+Point middle of Right Square Line going through left and right square POINT EMPTY
+Point middle of Right Square NULL NULL
+Point middle of Right Square Nested Geometry Collection POINT (0.5 0.5)
+Point middle of Right Square Point middle of Left Square POINT (0.5 0.5)
+Point middle of Right Square Point middle of Right Square POINT EMPTY
+Point middle of Right Square Square (left) POINT (0.5 0.5)
+Point middle of Right Square Square (right) POINT EMPTY
+Point middle of Right Square Square overlapping left and right square POINT EMPTY
+Square (left) Empty GeometryCollection POLYGON ((-1 0, 0 0, 0 1, -1 1, -1 0))
+Square (left) Empty LineString POLYGON ((-1 0, 0 0, 0 1, -1 1, -1 0))
+Square (left) Empty Point POLYGON ((-1 0, 0 0, 0 1, -1 1, -1 0))
+Square (left) Faraway point POLYGON ((-1 0, -1 1, 0 1, 0 0, -1 0))
+Square (left) Line going through left and right square POLYGON ((0 0.5, 0 0, -1 0, -1 1, 0 1, 0 0.5))
+Square (left) NULL NULL
+Square (left) Nested Geometry Collection POLYGON ((-1 0, -1 1, 0 1, 0 0, -1 0))
+Square (left) Point middle of Left Square POLYGON ((-1 0, -1 1, 0 1, 0 0, -1 0))
+Square (left) Point middle of Right Square POLYGON ((-1 0, -1 1, 0 1, 0 0, -1 0))
+Square (left) Square (left) POLYGON EMPTY
+Square (left) Square (right) POLYGON ((0 0, -1 0, -1 1, 0 1, 0 0))
+Square (left) Square overlapping left and right square POLYGON ((-0.1 0, -1 0, -1 1, -0.1 1, -0.1 0))
+Square (right) Empty GeometryCollection POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
+Square (right) Empty LineString POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
+Square (right) Empty Point POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
+Square (right) Faraway point POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
+Square (right) Line going through left and right square POLYGON ((0 0.5, 0 1, 1 1, 1 0, 0 0, 0 0.5))
+Square (right) NULL NULL
+Square (right) Nested Geometry Collection POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
+Square (right) Point middle of Left Square POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
+Square (right) Point middle of Right Square POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
+Square (right) Square (left) POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))
+Square (right) Square (right) POLYGON EMPTY
+Square (right) Square overlapping left and right square POLYGON EMPTY
+Square overlapping left and right square Empty GeometryCollection POLYGON ((-0.1 0, 1 0, 1 1, -0.1 1, -0.1 0))
+Square overlapping left and right square Empty LineString POLYGON ((-0.1 0, 1 0, 1 1, -0.1 1, -0.1 0))
+Square overlapping left and right square Empty Point POLYGON ((-0.1 0, 1 0, 1 1, -0.1 1, -0.1 0))
+Square overlapping left and right square Faraway point POLYGON ((-0.1 0, -0.1 1, 1 1, 1 0, -0.1 0))
+Square overlapping left and right square Line going through left and right square POLYGON ((-0.1 0.5, -0.1 1, 1 1, 1 0, -0.1 0, -0.1 0.5))
+Square overlapping left and right square NULL NULL
+Square overlapping left and right square Nested Geometry Collection POLYGON ((-0.1 0, -0.1 1, 1 1, 1 0, -0.1 0))
+Square overlapping left and right square Point middle of Left Square POLYGON ((-0.1 0, -0.1 1, 1 1, 1 0, -0.1 0))
+Square overlapping left and right square Point middle of Right Square POLYGON ((-0.1 0, -0.1 1, 1 1, 1 0, -0.1 0))
+Square overlapping left and right square Square (left) POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))
+Square overlapping left and right square Square (right) POLYGON ((0 0, -0.1 0, -0.1 1, 0 1, 0 0))
+Square overlapping left and right square Square overlapping left and right square POLYGON EMPTY
+
# Binary predicates
query TTBBBBBBBBBBB
SELECT
@@ -2625,160 +2797,161 @@ FROM ( VALUES
true
false
-query TTTB
+query TTTTB
SELECT
a.dsc,
b.dsc,
ST_Relate(a.geom, b.geom),
+ ST_Relate(a.geom, b.geom, 3),
ST_Relate(a.geom, b.geom, 'T**FF*FF*')
FROM geom_operators_test a
JOIN geom_operators_test b ON (1=1)
ORDER BY a.dsc, b.dsc
----
-Empty GeometryCollection Empty GeometryCollection FFFFFFFF2 false
-Empty GeometryCollection Empty LineString FFFFFFFF2 false
-Empty GeometryCollection Empty Point FFFFFFFF2 false
-Empty GeometryCollection Faraway point FFFFFF0F2 false
-Empty GeometryCollection Line going through left and right square FFFFFF102 false
-Empty GeometryCollection NULL NULL NULL
-Empty GeometryCollection Nested Geometry Collection FFFFFF0F2 false
-Empty GeometryCollection Point middle of Left Square FFFFFF0F2 false
-Empty GeometryCollection Point middle of Right Square FFFFFF0F2 false
-Empty GeometryCollection Square (left) FFFFFF212 false
-Empty GeometryCollection Square (right) FFFFFF212 false
-Empty GeometryCollection Square overlapping left and right square FFFFFF212 false
-Empty LineString Empty GeometryCollection FFFFFFFF2 false
-Empty LineString Empty LineString FFFFFFFF2 false
-Empty LineString Empty Point FFFFFFFF2 false
-Empty LineString Faraway point FFFFFF0F2 false
-Empty LineString Line going through left and right square FFFFFF102 false
-Empty LineString NULL NULL NULL
-Empty LineString Nested Geometry Collection FFFFFF0F2 false
-Empty LineString Point middle of Left Square FFFFFF0F2 false
-Empty LineString Point middle of Right Square FFFFFF0F2 false
-Empty LineString Square (left) FFFFFF212 false
-Empty LineString Square (right) FFFFFF212 false
-Empty LineString Square overlapping left and right square FFFFFF212 false
-Empty Point Empty GeometryCollection FFFFFFFF2 false
-Empty Point Empty LineString FFFFFFFF2 false
-Empty Point Empty Point FFFFFFFF2 false
-Empty Point Faraway point FFFFFF0F2 false
-Empty Point Line going through left and right square FFFFFF102 false
-Empty Point NULL NULL NULL
-Empty Point Nested Geometry Collection FFFFFF0F2 false
-Empty Point Point middle of Left Square FFFFFF0F2 false
-Empty Point Point middle of Right Square FFFFFF0F2 false
-Empty Point Square (left) FFFFFF212 false
-Empty Point Square (right) FFFFFF212 false
-Empty Point Square overlapping left and right square FFFFFF212 false
-Faraway point Empty GeometryCollection FF0FFFFF2 false
-Faraway point Empty LineString FF0FFFFF2 false
-Faraway point Empty Point FF0FFFFF2 false
-Faraway point Faraway point 0FFFFFFF2 true
-Faraway point Line going through left and right square FF0FFF102 false
-Faraway point NULL NULL NULL
-Faraway point Nested Geometry Collection FF0FFF0F2 false
-Faraway point Point middle of Left Square FF0FFF0F2 false
-Faraway point Point middle of Right Square FF0FFF0F2 false
-Faraway point Square (left) FF0FFF212 false
-Faraway point Square (right) FF0FFF212 false
-Faraway point Square overlapping left and right square FF0FFF212 false
-Line going through left and right square Empty GeometryCollection FF1FF0FF2 false
-Line going through left and right square Empty LineString FF1FF0FF2 false
-Line going through left and right square Empty Point FF1FF0FF2 false
-Line going through left and right square Faraway point FF1FF00F2 false
-Line going through left and right square Line going through left and right square 1FFF0FFF2 false
-Line going through left and right square NULL NULL NULL
-Line going through left and right square Nested Geometry Collection FF1FF00F2 false
-Line going through left and right square Point middle of Left Square FF10F0FF2 false
-Line going through left and right square Point middle of Right Square FF10F0FF2 false
-Line going through left and right square Square (left) 1010F0212 false
-Line going through left and right square Square (right) 1010F0212 false
-Line going through left and right square Square overlapping left and right square 1010F0212 false
-NULL Empty GeometryCollection NULL NULL
-NULL Empty LineString NULL NULL
-NULL Empty Point NULL NULL
-NULL Faraway point NULL NULL
-NULL Line going through left and right square NULL NULL
-NULL NULL NULL NULL
-NULL Nested Geometry Collection NULL NULL
-NULL Point middle of Left Square NULL NULL
-NULL Point middle of Right Square NULL NULL
-NULL Square (left) NULL NULL
-NULL Square (right) NULL NULL
-NULL Square overlapping left and right square NULL NULL
-Nested Geometry Collection Empty GeometryCollection FF0FFFFF2 false
-Nested Geometry Collection Empty LineString FF0FFFFF2 false
-Nested Geometry Collection Empty Point FF0FFFFF2 false
-Nested Geometry Collection Faraway point FF0FFF0F2 false
-Nested Geometry Collection Line going through left and right square FF0FFF102 false
-Nested Geometry Collection NULL NULL NULL
-Nested Geometry Collection Nested Geometry Collection 0FFFFFFF2 true
-Nested Geometry Collection Point middle of Left Square FF0FFF0F2 false
-Nested Geometry Collection Point middle of Right Square FF0FFF0F2 false
-Nested Geometry Collection Square (left) F0FFFF212 false
-Nested Geometry Collection Square (right) F0FFFF212 false
-Nested Geometry Collection Square overlapping left and right square F0FFFF212 false
-Point middle of Left Square Empty GeometryCollection FF0FFFFF2 false
-Point middle of Left Square Empty LineString FF0FFFFF2 false
-Point middle of Left Square Empty Point FF0FFFFF2 false
-Point middle of Left Square Faraway point FF0FFF0F2 false
-Point middle of Left Square Line going through left and right square F0FFFF102 false
-Point middle of Left Square NULL NULL NULL
-Point middle of Left Square Nested Geometry Collection FF0FFF0F2 false
-Point middle of Left Square Point middle of Left Square 0FFFFFFF2 true
-Point middle of Left Square Point middle of Right Square FF0FFF0F2 false
-Point middle of Left Square Square (left) 0FFFFF212 false
-Point middle of Left Square Square (right) FF0FFF212 false
-Point middle of Left Square Square overlapping left and right square FF0FFF212 false
-Point middle of Right Square Empty GeometryCollection FF0FFFFF2 false
-Point middle of Right Square Empty LineString FF0FFFFF2 false
-Point middle of Right Square Empty Point FF0FFFFF2 false
-Point middle of Right Square Faraway point FF0FFF0F2 false
-Point middle of Right Square Line going through left and right square F0FFFF102 false
-Point middle of Right Square NULL NULL NULL
-Point middle of Right Square Nested Geometry Collection FF0FFF0F2 false
-Point middle of Right Square Point middle of Left Square FF0FFF0F2 false
-Point middle of Right Square Point middle of Right Square 0FFFFFFF2 true
-Point middle of Right Square Square (left) FF0FFF212 false
-Point middle of Right Square Square (right) 0FFFFF212 false
-Point middle of Right Square Square overlapping left and right square 0FFFFF212 false
-Square (left) Empty GeometryCollection FF2FF1FF2 false
-Square (left) Empty LineString FF2FF1FF2 false
-Square (left) Empty Point FF2FF1FF2 false
-Square (left) Faraway point FF2FF10F2 false
-Square (left) Line going through left and right square 1020F1102 false
-Square (left) NULL NULL NULL
-Square (left) Nested Geometry Collection FF20F1FF2 false
-Square (left) Point middle of Left Square 0F2FF1FF2 true
-Square (left) Point middle of Right Square FF2FF10F2 false
-Square (left) Square (left) 2FFF1FFF2 false
-Square (left) Square (right) FF2F11212 false
-Square (left) Square overlapping left and right square 212111212 false
-Square (right) Empty GeometryCollection FF2FF1FF2 false
-Square (right) Empty LineString FF2FF1FF2 false
-Square (right) Empty Point FF2FF1FF2 false
-Square (right) Faraway point FF2FF10F2 false
-Square (right) Line going through left and right square 1020F1102 false
-Square (right) NULL NULL NULL
-Square (right) Nested Geometry Collection FF20F1FF2 false
-Square (right) Point middle of Left Square FF2FF10F2 false
-Square (right) Point middle of Right Square 0F2FF1FF2 true
-Square (right) Square (left) FF2F11212 false
-Square (right) Square (right) 2FFF1FFF2 false
-Square (right) Square overlapping left and right square 2FF11F212 false
-Square overlapping left and right square Empty GeometryCollection FF2FF1FF2 false
-Square overlapping left and right square Empty LineString FF2FF1FF2 false
-Square overlapping left and right square Empty Point FF2FF1FF2 false
-Square overlapping left and right square Faraway point FF2FF10F2 false
-Square overlapping left and right square Line going through left and right square 1020F1102 false
-Square overlapping left and right square NULL NULL NULL
-Square overlapping left and right square Nested Geometry Collection FF20F1FF2 false
-Square overlapping left and right square Point middle of Left Square FF2FF10F2 false
-Square overlapping left and right square Point middle of Right Square 0F2FF1FF2 true
-Square overlapping left and right square Square (left) 212111212 false
-Square overlapping left and right square Square (right) 212F11FF2 false
-Square overlapping left and right square Square overlapping left and right square 2FFF1FFF2 false
+Empty GeometryCollection Empty GeometryCollection FFFFFFFF2 FFFFFFFF2 false
+Empty GeometryCollection Empty LineString FFFFFFFF2 FFFFFFFF2 false
+Empty GeometryCollection Empty Point FFFFFFFF2 FFFFFFFF2 false
+Empty GeometryCollection Faraway point FFFFFF0F2 FFFFFF0F2 false
+Empty GeometryCollection Line going through left and right square FFFFFF102 FFFFFF102 false
+Empty GeometryCollection NULL NULL NULL NULL
+Empty GeometryCollection Nested Geometry Collection FFFFFF0F2 FFFFFF0F2 false
+Empty GeometryCollection Point middle of Left Square FFFFFF0F2 FFFFFF0F2 false
+Empty GeometryCollection Point middle of Right Square FFFFFF0F2 FFFFFF0F2 false
+Empty GeometryCollection Square (left) FFFFFF212 FFFFFF212 false
+Empty GeometryCollection Square (right) FFFFFF212 FFFFFF212 false
+Empty GeometryCollection Square overlapping left and right square FFFFFF212 FFFFFF212 false
+Empty LineString Empty GeometryCollection FFFFFFFF2 FFFFFFFF2 false
+Empty LineString Empty LineString FFFFFFFF2 FFFFFFFF2 false
+Empty LineString Empty Point FFFFFFFF2 FFFFFFFF2 false
+Empty LineString Faraway point FFFFFF0F2 FFFFFF0F2 false
+Empty LineString Line going through left and right square FFFFFF102 FFFFFF102 false
+Empty LineString NULL NULL NULL NULL
+Empty LineString Nested Geometry Collection FFFFFF0F2 FFFFFF0F2 false
+Empty LineString Point middle of Left Square FFFFFF0F2 FFFFFF0F2 false
+Empty LineString Point middle of Right Square FFFFFF0F2 FFFFFF0F2 false
+Empty LineString Square (left) FFFFFF212 FFFFFF212 false
+Empty LineString Square (right) FFFFFF212 FFFFFF212 false
+Empty LineString Square overlapping left and right square FFFFFF212 FFFFFF212 false
+Empty Point Empty GeometryCollection FFFFFFFF2 FFFFFFFF2 false
+Empty Point Empty LineString FFFFFFFF2 FFFFFFFF2 false
+Empty Point Empty Point FFFFFFFF2 FFFFFFFF2 false
+Empty Point Faraway point FFFFFF0F2 FFFFFF0F2 false
+Empty Point Line going through left and right square FFFFFF102 FFFFFF102 false
+Empty Point NULL NULL NULL NULL
+Empty Point Nested Geometry Collection FFFFFF0F2 FFFFFF0F2 false
+Empty Point Point middle of Left Square FFFFFF0F2 FFFFFF0F2 false
+Empty Point Point middle of Right Square FFFFFF0F2 FFFFFF0F2 false
+Empty Point Square (left) FFFFFF212 FFFFFF212 false
+Empty Point Square (right) FFFFFF212 FFFFFF212 false
+Empty Point Square overlapping left and right square FFFFFF212 FFFFFF212 false
+Faraway point Empty GeometryCollection FF0FFFFF2 FF0FFFFF2 false
+Faraway point Empty LineString FF0FFFFF2 FF0FFFFF2 false
+Faraway point Empty Point FF0FFFFF2 FF0FFFFF2 false
+Faraway point Faraway point 0FFFFFFF2 0FFFFFFF2 true
+Faraway point Line going through left and right square FF0FFF102 FF0FFF102 false
+Faraway point NULL NULL NULL NULL
+Faraway point Nested Geometry Collection FF0FFF0F2 FF0FFF0F2 false
+Faraway point Point middle of Left Square FF0FFF0F2 FF0FFF0F2 false
+Faraway point Point middle of Right Square FF0FFF0F2 FF0FFF0F2 false
+Faraway point Square (left) FF0FFF212 FF0FFF212 false
+Faraway point Square (right) FF0FFF212 FF0FFF212 false
+Faraway point Square overlapping left and right square FF0FFF212 FF0FFF212 false
+Line going through left and right square Empty GeometryCollection FF1FF0FF2 FF1FF0FF2 false
+Line going through left and right square Empty LineString FF1FF0FF2 FF1FF0FF2 false
+Line going through left and right square Empty Point FF1FF0FF2 FF1FF0FF2 false
+Line going through left and right square Faraway point FF1FF00F2 FF1FF00F2 false
+Line going through left and right square Line going through left and right square 1FFF0FFF2 1FFFFFFF2 false
+Line going through left and right square NULL NULL NULL NULL
+Line going through left and right square Nested Geometry Collection FF1FF00F2 FF1FF00F2 false
+Line going through left and right square Point middle of Left Square FF10F0FF2 0F1FFFFF2 false
+Line going through left and right square Point middle of Right Square FF10F0FF2 0F1FFFFF2 false
+Line going through left and right square Square (left) 1010F0212 101FFF202 false
+Line going through left and right square Square (right) 1010F0212 101FFF202 false
+Line going through left and right square Square overlapping left and right square 1010F0212 101FFF202 false
+NULL Empty GeometryCollection NULL NULL NULL
+NULL Empty LineString NULL NULL NULL
+NULL Empty Point NULL NULL NULL
+NULL Faraway point NULL NULL NULL
+NULL Line going through left and right square NULL NULL NULL
+NULL NULL NULL NULL NULL
+NULL Nested Geometry Collection NULL NULL NULL
+NULL Point middle of Left Square NULL NULL NULL
+NULL Point middle of Right Square NULL NULL NULL
+NULL Square (left) NULL NULL NULL
+NULL Square (right) NULL NULL NULL
+NULL Square overlapping left and right square NULL NULL NULL
+Nested Geometry Collection Empty GeometryCollection FF0FFFFF2 FF0FFFFF2 false
+Nested Geometry Collection Empty LineString FF0FFFFF2 FF0FFFFF2 false
+Nested Geometry Collection Empty Point FF0FFFFF2 FF0FFFFF2 false
+Nested Geometry Collection Faraway point FF0FFF0F2 FF0FFF0F2 false
+Nested Geometry Collection Line going through left and right square FF0FFF102 FF0FFF102 false
+Nested Geometry Collection NULL NULL NULL NULL
+Nested Geometry Collection Nested Geometry Collection 0FFFFFFF2 0FFFFFFF2 true
+Nested Geometry Collection Point middle of Left Square FF0FFF0F2 FF0FFF0F2 false
+Nested Geometry Collection Point middle of Right Square FF0FFF0F2 FF0FFF0F2 false
+Nested Geometry Collection Square (left) F0FFFF212 F0FFFF212 false
+Nested Geometry Collection Square (right) F0FFFF212 F0FFFF212 false
+Nested Geometry Collection Square overlapping left and right square F0FFFF212 F0FFFF212 false
+Point middle of Left Square Empty GeometryCollection FF0FFFFF2 FF0FFFFF2 false
+Point middle of Left Square Empty LineString FF0FFFFF2 FF0FFFFF2 false
+Point middle of Left Square Empty Point FF0FFFFF2 FF0FFFFF2 false
+Point middle of Left Square Faraway point FF0FFF0F2 FF0FFF0F2 false
+Point middle of Left Square Line going through left and right square F0FFFF102 0FFFFF1F2 false
+Point middle of Left Square NULL NULL NULL NULL
+Point middle of Left Square Nested Geometry Collection FF0FFF0F2 FF0FFF0F2 false
+Point middle of Left Square Point middle of Left Square 0FFFFFFF2 0FFFFFFF2 true
+Point middle of Left Square Point middle of Right Square FF0FFF0F2 FF0FFF0F2 false
+Point middle of Left Square Square (left) 0FFFFF212 0FFFFF212 false
+Point middle of Left Square Square (right) FF0FFF212 FF0FFF212 false
+Point middle of Left Square Square overlapping left and right square FF0FFF212 FF0FFF212 false
+Point middle of Right Square Empty GeometryCollection FF0FFFFF2 FF0FFFFF2 false
+Point middle of Right Square Empty LineString FF0FFFFF2 FF0FFFFF2 false
+Point middle of Right Square Empty Point FF0FFFFF2 FF0FFFFF2 false
+Point middle of Right Square Faraway point FF0FFF0F2 FF0FFF0F2 false
+Point middle of Right Square Line going through left and right square F0FFFF102 0FFFFF1F2 false
+Point middle of Right Square NULL NULL NULL NULL
+Point middle of Right Square Nested Geometry Collection FF0FFF0F2 FF0FFF0F2 false
+Point middle of Right Square Point middle of Left Square FF0FFF0F2 FF0FFF0F2 false
+Point middle of Right Square Point middle of Right Square 0FFFFFFF2 0FFFFFFF2 true
+Point middle of Right Square Square (left) FF0FFF212 FF0FFF212 false
+Point middle of Right Square Square (right) 0FFFFF212 0FFFFF212 false
+Point middle of Right Square Square overlapping left and right square 0FFFFF212 0FFFFF212 false
+Square (left) Empty GeometryCollection FF2FF1FF2 FF2FF1FF2 false
+Square (left) Empty LineString FF2FF1FF2 FF2FF1FF2 false
+Square (left) Empty Point FF2FF1FF2 FF2FF1FF2 false
+Square (left) Faraway point FF2FF10F2 FF2FF10F2 false
+Square (left) Line going through left and right square 1020F1102 1F20F01F2 false
+Square (left) NULL NULL NULL NULL
+Square (left) Nested Geometry Collection FF20F1FF2 FF20F1FF2 false
+Square (left) Point middle of Left Square 0F2FF1FF2 0F2FF1FF2 true
+Square (left) Point middle of Right Square FF2FF10F2 FF2FF10F2 false
+Square (left) Square (left) 2FFF1FFF2 2FFF0FFF2 false
+Square (left) Square (right) FF2F11212 1F2F002F2 false
+Square (left) Square overlapping left and right square 212111212 2F2F002F2 false
+Square (right) Empty GeometryCollection FF2FF1FF2 FF2FF1FF2 false
+Square (right) Empty LineString FF2FF1FF2 FF2FF1FF2 false
+Square (right) Empty Point FF2FF1FF2 FF2FF1FF2 false
+Square (right) Faraway point FF2FF10F2 FF2FF10F2 false
+Square (right) Line going through left and right square 1020F1102 1F20F01F2 false
+Square (right) NULL NULL NULL NULL
+Square (right) Nested Geometry Collection FF20F1FF2 FF20F1FF2 false
+Square (right) Point middle of Left Square FF2FF10F2 FF2FF10F2 false
+Square (right) Point middle of Right Square 0F2FF1FF2 0F2FF1FF2 true
+Square (right) Square (left) FF2F11212 1F2F0F202 false
+Square (right) Square (right) 2FFF1FFF2 2FFF0FFF2 false
+Square (right) Square overlapping left and right square 2FF11F212 2FFF0F202 false
+Square overlapping left and right square Empty GeometryCollection FF2FF1FF2 FF2FF1FF2 false
+Square overlapping left and right square Empty LineString FF2FF1FF2 FF2FF1FF2 false
+Square overlapping left and right square Empty Point FF2FF1FF2 FF2FF1FF2 false
+Square overlapping left and right square Faraway point FF2FF10F2 FF2FF10F2 false
+Square overlapping left and right square Line going through left and right square 1020F1102 1F20F01F2 false
+Square overlapping left and right square NULL NULL NULL NULL
+Square overlapping left and right square Nested Geometry Collection FF20F1FF2 FF20F1FF2 false
+Square overlapping left and right square Point middle of Left Square FF2FF10F2 FF2FF10F2 false
+Square overlapping left and right square Point middle of Right Square 0F2FF1FF2 0F2FF1FF2 true
+Square overlapping left and right square Square (left) 212111212 2F2F0F202 false
+Square overlapping left and right square Square (right) 212F11FF2 2F2F00FF2 false
+Square overlapping left and right square Square overlapping left and right square 2FFF1FFF2 2FFF0FFF2 false
# ST_Envelope
query TT
diff --git a/pkg/sql/sem/builtins/geo_builtins.go b/pkg/sql/sem/builtins/geo_builtins.go
index 4cca86775c30..9c2afc0ee36b 100644
--- a/pkg/sql/sem/builtins/geo_builtins.go
+++ b/pkg/sql/sem/builtins/geo_builtins.go
@@ -3001,6 +3001,30 @@ Note if geometries are the same, it will return the LineString with the minimum
}.String(),
Volatility: tree.VolatilityImmutable,
},
+ tree.Overload{
+ Types: tree.ArgTypes{
+ {"geometry_a", types.Geometry},
+ {"geometry_b", types.Geometry},
+ {"bnr", types.Int},
+ },
+ ReturnType: tree.FixedReturnType(types.String),
+ Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
+ a := tree.MustBeDGeometry(args[0])
+ b := tree.MustBeDGeometry(args[1])
+ bnr := tree.MustBeDInt(args[2])
+ ret, err := geomfn.RelateBoundaryNodeRule(a.Geometry, b.Geometry, int(bnr))
+ if err != nil {
+ return nil, err
+ }
+ return tree.NewDString(ret), nil
+ },
+ Info: infoBuilder{
+ info: `Returns the DE-9IM spatial relation between geometry_a and geometry_b using the given ` +
+ `boundary node rule (1:OGC/MOD2, 2:Endpoint, 3:MultivalentEndpoint, 4:MonovalentEndpoint).`,
+ libraryUsage: usesGEOS,
+ }.String(),
+ Volatility: tree.VolatilityImmutable,
+ },
),
"st_relatematch": makeBuiltin(
defProps(),
@@ -3143,6 +3167,24 @@ For flags=1, validity considers self-intersecting rings forming holes as valid a
// Topology operations
//
+ "st_boundary": makeBuiltin(
+ defProps(),
+ geometryOverload1(
+ func(ctx *tree.EvalContext, g *tree.DGeometry) (tree.Datum, error) {
+ centroid, err := geomfn.Boundary(g.Geometry)
+ if err != nil {
+ return nil, err
+ }
+ return tree.NewDGeometry(centroid), err
+ },
+ types.Geometry,
+ infoBuilder{
+ info: "Returns the closure of the combinatorial boundary of this Geometry.",
+ libraryUsage: usesGEOS,
+ },
+ tree.VolatilityImmutable,
+ ),
+ ),
"st_centroid": makeBuiltin(
defProps(),
append(
@@ -3215,6 +3257,24 @@ For flags=1, validity considers self-intersecting rings forming holes as valid a
tree.VolatilityImmutable,
),
),
+ "st_difference": makeBuiltin(
+ defProps(),
+ geometryOverload2(
+ func(ctx *tree.EvalContext, a, b *tree.DGeometry) (tree.Datum, error) {
+ diff, err := geomfn.Difference(a.Geometry, b.Geometry)
+ if err != nil {
+ return nil, err
+ }
+ return tree.NewDGeometry(diff), err
+ },
+ types.Geometry,
+ infoBuilder{
+ info: "Returns the difference of two Geometries.",
+ libraryUsage: usesGEOS,
+ },
+ tree.VolatilityImmutable,
+ ),
+ ),
"st_pointonsurface": makeBuiltin(
defProps(),
geometryOverload1(
@@ -4826,7 +4886,6 @@ The swap_ordinate_string parameter is a 2-character string naming the ordinates
"st_aslatlontext": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48882}),
"st_assvg": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48883}),
"st_astwkb": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48886}),
- "st_boundary": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48888}),
"st_boundingdiagonal": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48889}),
"st_buildarea": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48892}),
"st_chaikinsmoothing": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48894}),
@@ -4838,7 +4897,6 @@ The swap_ordinate_string parameter is a 2-character string naming the ordinates
"st_clusterwithin": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48901}),
"st_concavehull": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48906}),
"st_delaunaytriangles": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48915}),
- "st_difference": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 48917}),
"st_dump": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 49785}),
"st_dumppoints": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 49786}),
"st_dumprings": makeBuiltin(tree.FunctionProperties{UnsupportedWithIssue: 49787}),
| |