Skip to content

Commit

Permalink
builtins: implement ST_MakePoint and ST_MakePointM
Browse files Browse the repository at this point in the history
This patch implements the geometry builtins `ST_MakePoint`
and `ST_MakePointM`.

Release justification: low-risk update to new functionality
Release note (sql change): The geometry builtins `ST_MakePoint`
and `ST_MakePointM` have been implemented and provide a mechanism
for easily creating new points.
  • Loading branch information
Andy Yang committed Feb 25, 2021
1 parent 3bae09b commit 38e2658
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 2 deletions.
6 changes: 6 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,12 @@ calculated, the result is transformed back into a Geography with SRID 4326.</p>
</span></td></tr>
<tr><td><a name="st_makepoint"></a><code>st_makepoint(x: <a href="float.html">float</a>, y: <a href="float.html">float</a>) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Point with the given X and Y coordinates.</p>
</span></td></tr>
<tr><td><a name="st_makepoint"></a><code>st_makepoint(x: <a href="float.html">float</a>, y: <a href="float.html">float</a>, z: <a href="float.html">float</a>) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Point with the given X, Y, and Z coordinates.</p>
</span></td></tr>
<tr><td><a name="st_makepoint"></a><code>st_makepoint(x: <a href="float.html">float</a>, y: <a href="float.html">float</a>, z: <a href="float.html">float</a>, m: <a href="float.html">float</a>) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Point with the given X, Y, Z, and M coordinates.</p>
</span></td></tr>
<tr><td><a name="st_makepointm"></a><code>st_makepointm(x: <a href="float.html">float</a>, y: <a href="float.html">float</a>, m: <a href="float.html">float</a>) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Point with the given X, Y, and M coordinates.</p>
</span></td></tr>
<tr><td><a name="st_makepolygon"></a><code>st_makepolygon(geometry: geometry) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Polygon with the given outer LineString.</p>
</span></td></tr>
<tr><td><a name="st_makepolygon"></a><code>st_makepolygon(outer: geometry, interior: anyelement[]) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a new Polygon with the given outer LineString and interior (hole) LineString(s).</p>
Expand Down
22 changes: 21 additions & 1 deletion pkg/geo/geo.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,27 @@ func MakeGeometryUnsafe(spatialObject geopb.SpatialObject) Geometry {

// MakeGeometryFromPointCoords makes a point from x, y coordinates.
func MakeGeometryFromPointCoords(x, y float64) (Geometry, error) {
s, err := spatialObjectFromGeomT(geom.NewPointFlat(geom.XY, []float64{x, y}), geopb.SpatialObjectType_GeometryType)
return MakeGeometryFromLayoutAndPointCoords(geom.XY, []float64{x, y})
}

// MakeGeometryFromLayoutAndPointCoords makes a point with a given layout and ordered slice of coordinates.
func MakeGeometryFromLayoutAndPointCoords(
layout geom.Layout, flatCoords []float64,
) (Geometry, error) {
// Validate that the stride matches what is expected for the layout.
switch {
case layout == geom.XY && len(flatCoords) == 2:
break
case layout == geom.XYM && len(flatCoords) == 3:
break
case layout == geom.XYZ && len(flatCoords) == 3:
break
case layout == geom.XYZM && len(flatCoords) == 4:
break
default:
return Geometry{}, errors.Newf("mismatch between layout %d and stride %d", layout, len(flatCoords))
}
s, err := spatialObjectFromGeomT(geom.NewPointFlat(layout, flatCoords), geopb.SpatialObjectType_GeometryType)
if err != nil {
return Geometry{}, err
}
Expand Down
21 changes: 21 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/geospatial_zm
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,24 @@ INSERT INTO geom_4d VALUES ('point(1 2)')

statement error pq: object type PointZ does not match column dimensionality GeometryZM
INSERT INTO geom_4d VALUES ('pointz(1 2 3)')

# Builtins for creating Points
query T
select st_astext(st_makepoint(1, 2))
----
POINT (1 2)

query T
select st_astext(st_makepoint(1, 2, 3))
----
POINT Z (1 2 3)

query T
select st_astext(st_makepoint(1, 2, 3, 4))
----
POINT ZM (1 2 3 4)

query T
select st_astext(st_makepointm(1, 2, 3))
----
POINT M (1 2 3)
71 changes: 70 additions & 1 deletion pkg/sql/sem/builtins/geo_builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,76 @@ SELECT ST_S2Covering(geography, 's2_max_level=15,s2_level_mod=3').
tree.VolatilityImmutable,
),
),
"st_makepoint": makeBuiltin(
defProps(),
tree.Overload{
Types: tree.ArgTypes{{"x", types.Float}, {"y", types.Float}},
ReturnType: tree.FixedReturnType(types.Geometry),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
x := float64(tree.MustBeDFloat(args[0]))
y := float64(tree.MustBeDFloat(args[1]))
g, err := geo.MakeGeometryFromLayoutAndPointCoords(geom.XY, []float64{x, y})
if err != nil {
return nil, err
}
return tree.NewDGeometry(g), nil
},
Info: infoBuilder{info: `Returns a new Point with the given X and Y coordinates.`}.String(),
Volatility: tree.VolatilityImmutable,
},
tree.Overload{
Types: tree.ArgTypes{{"x", types.Float}, {"y", types.Float}, {"z", types.Float}},
ReturnType: tree.FixedReturnType(types.Geometry),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
x := float64(tree.MustBeDFloat(args[0]))
y := float64(tree.MustBeDFloat(args[1]))
z := float64(tree.MustBeDFloat(args[2]))
g, err := geo.MakeGeometryFromLayoutAndPointCoords(geom.XYZ, []float64{x, y, z})
if err != nil {
return nil, err
}
return tree.NewDGeometry(g), nil
},
Info: infoBuilder{info: `Returns a new Point with the given X, Y, and Z coordinates.`}.String(),
Volatility: tree.VolatilityImmutable,
},
tree.Overload{
Types: tree.ArgTypes{{"x", types.Float}, {"y", types.Float}, {"z", types.Float}, {"m", types.Float}},
ReturnType: tree.FixedReturnType(types.Geometry),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
x := float64(tree.MustBeDFloat(args[0]))
y := float64(tree.MustBeDFloat(args[1]))
z := float64(tree.MustBeDFloat(args[2]))
m := float64(tree.MustBeDFloat(args[3]))
g, err := geo.MakeGeometryFromLayoutAndPointCoords(geom.XYZM, []float64{x, y, z, m})
if err != nil {
return nil, err
}
return tree.NewDGeometry(g), nil
},
Info: infoBuilder{info: `Returns a new Point with the given X, Y, Z, and M coordinates.`}.String(),
Volatility: tree.VolatilityImmutable,
},
),
"st_makepointm": makeBuiltin(
defProps(),
tree.Overload{
Types: tree.ArgTypes{{"x", types.Float}, {"y", types.Float}, {"m", types.Float}},
ReturnType: tree.FixedReturnType(types.Geometry),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
x := float64(tree.MustBeDFloat(args[0]))
y := float64(tree.MustBeDFloat(args[1]))
m := float64(tree.MustBeDFloat(args[2]))
g, err := geo.MakeGeometryFromLayoutAndPointCoords(geom.XYM, []float64{x, y, m})
if err != nil {
return nil, err
}
return tree.NewDGeometry(g), nil
},
Info: infoBuilder{info: `Returns a new Point with the given X, Y, and M coordinates.`}.String(),
Volatility: tree.VolatilityImmutable,
},
),
"st_makepolygon": makeBuiltin(
defProps(),
geometryOverload1(
Expand Down Expand Up @@ -6245,7 +6315,6 @@ func initGeoBuiltins() {
{"st_geogfromtext", "st_geographyfromtext"},
{"st_geomfromtext", "st_geometryfromtext"},
{"st_numinteriorring", "st_numinteriorrings"},
{"st_makepoint", "st_point"},
{"st_symmetricdifference", "st_symdifference"},
} {
if _, ok := geoBuiltins[alias.builtinName]; !ok {
Expand Down

0 comments on commit 38e2658

Please sign in to comment.