From ff866506ae80df7ad7b6439d53d60308dc1130c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20BIDON?= Date: Fri, 22 Apr 2022 19:24:07 +0200 Subject: [PATCH] added st_makeenvelope builtin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes #80357 Release note (sql change): added builtin st_makeenvelope Signed-off-by: Frédéric BIDON --- docs/generated/sql/functions.md | 4 ++ .../logictest/testdata/logic_test/geospatial | 11 ++++ pkg/sql/sem/builtins/geo_builtins.go | 65 ++++++++++++++++++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/docs/generated/sql/functions.md b/docs/generated/sql/functions.md index b6a692ed61fc..cad14033314f 100644 --- a/docs/generated/sql/functions.md +++ b/docs/generated/sql/functions.md @@ -2203,6 +2203,10 @@ calculated, the result is transformed back into a Geography with SRID 4326.

st_makebox2d(geometry_a: geometry, geometry_b: geometry) → box2d

Creates a box2d from two points. Errors if arguments are not two non-empty points.

+st_makeenvelope(xmin: float, ymin: float, xmax: float, ymax: float) → geometry

Creates a rectangular Polygon from the minimum and maximum values for X and Y with SRID 0.

+
+st_makeenvelope(xmin: float, ymin: float, xmax: float, ymax: float, srid: int) → geometry

Creates a rectangular Polygon from the minimum and maximum values for X and Y with the given SRID.

+
st_makepoint(x: float, y: float) → geometry

Returns a new Point with the given X and Y coordinates.

st_makepoint(x: float, y: float, z: float) → geometry

Returns a new Point with the given X, Y, and Z coordinates.

diff --git a/pkg/sql/logictest/testdata/logic_test/geospatial b/pkg/sql/logictest/testdata/logic_test/geospatial index 2c9733d9114f..d431cde88ea4 100644 --- a/pkg/sql/logictest/testdata/logic_test/geospatial +++ b/pkg/sql/logictest/testdata/logic_test/geospatial @@ -5892,3 +5892,14 @@ FROM ( VALUES ---- false false false false false false + +# ST_MakeEnvelope +query T +SELECT ST_AsEWKT(ST_MakeEnvelope(30.01,50.01,72.01,52.01,4326)) +---- +SRID=4326;POLYGON ((30.010000000000002 50.009999999999998, 30.010000000000002 52.009999999999998, 72.010000000000005 52.009999999999998, 72.010000000000005 50.009999999999998, 30.010000000000002 50.009999999999998)) + +query T +SELECT ST_AsEWKT(ST_MakeEnvelope(30.01,50.01,72.01,52.01)) +---- +POLYGON ((30.010000000000002 50.009999999999998, 30.010000000000002 52.009999999999998, 72.010000000000005 52.009999999999998, 72.010000000000005 50.009999999999998, 30.010000000000002 50.009999999999998)) diff --git a/pkg/sql/sem/builtins/geo_builtins.go b/pkg/sql/sem/builtins/geo_builtins.go index d1053efee2fc..e778d6516ee9 100644 --- a/pkg/sql/sem/builtins/geo_builtins.go +++ b/pkg/sql/sem/builtins/geo_builtins.go @@ -5302,7 +5302,7 @@ The calculations are done on a sphere.`, }, Info: infoBuilder{ info: `Snaps the vertices and segments of input geometry the target geometry's vertices. -Tolerance is used to control where snapping is performed. The result geometry is the input geometry with the vertices snapped. +Tolerance is used to control where snapping is performed. The result geometry is the input geometry with the vertices snapped. If no snapping occurs then the input geometry is returned unchanged.`, }.String(), Volatility: volatility.Immutable, @@ -5558,6 +5558,42 @@ Bottom Left.`, Volatility: volatility.Immutable, }, ), + "st_makeenvelope": makeBuiltin( + defProps(), + tree.Overload{ + Types: tree.ArgTypes{ + {"xmin", types.Float}, + {"ymin", types.Float}, + {"xmax", types.Float}, + {"ymax", types.Float}, + {"srid", types.Int}, + }, + ReturnType: tree.FixedReturnType(types.Geometry), + Fn: func(_ *eval.Context, args tree.Datums) (tree.Datum, error) { + return stEnvelopeFromArgs(args) + }, + Info: infoBuilder{ + info: "Creates a rectangular Polygon from the minimum and maximum values for X and Y with the given SRID.", + }.String(), + Volatility: volatility.Immutable, + }, + tree.Overload{ + Types: tree.ArgTypes{ + {"xmin", types.Float}, + {"ymin", types.Float}, + {"xmax", types.Float}, + {"ymax", types.Float}, + }, + ReturnType: tree.FixedReturnType(types.Geometry), + Fn: func(_ *eval.Context, args tree.Datums) (tree.Datum, error) { + return stEnvelopeFromArgs(args) + }, + Info: infoBuilder{ + info: "Creates a rectangular Polygon from the minimum and maximum values for X and Y with SRID 0.", + }.String(), + Volatility: volatility.Immutable, + }, + ), "st_flipcoordinates": makeBuiltin( defProps(), tree.Overload{ @@ -6768,7 +6804,7 @@ May return a Point or LineString in the case of degenerate inputs.`, return tree.NewDInt(tree.DInt(ret)), nil }, Info: infoBuilder{ - info: `Returns an interger value defining behavior of crossing of lines: + info: `Returns an interger value defining behavior of crossing of lines: 0: lines do not cross, -1: linestring_b crosses linestring_a from right to left, 1: linestring_b crosses linestring_a from left to right, @@ -7502,3 +7538,28 @@ func applyGeoindexConfigStorageParams( } return indexDesc.GeoConfig, nil } + +// stEnvelopeFromArgs builds a rectangle geometry from types.Float bounds as datums +func stEnvelopeFromArgs(args tree.Datums) (tree.Datum, error) { + xmin := float64(tree.MustBeDFloat(args[0])) + ymin := float64(tree.MustBeDFloat(args[1])) + xmax := float64(tree.MustBeDFloat(args[2])) + ymax := float64(tree.MustBeDFloat(args[3])) + + var srid int + if len(args) > 4 { + srid = int(tree.MustBeDInt(args[4])) + } + + extent, err := geo.MakeGeometryFromGeomT( + geom.NewBounds(geom.XY). + Set(xmin, ymin, xmax, ymax). + Polygon(). + SetSRID(srid), + ) + if err != nil { + return nil, err + } + + return tree.NewDGeometry(extent), nil +}