Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(query): implement st_makeline() function #15059

Merged
merged 10 commits into from
Mar 26, 2024
93 changes: 93 additions & 0 deletions src/query/functions/src/scalars/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ use databend_common_expression::vectorize_with_builder_2_arg;
use databend_common_expression::FunctionDomain;
use databend_common_expression::FunctionRegistry;
use databend_common_io::parse_to_ewkb;
use geo::Coord;
use geo::Geometry;
use geo::LineString;
use geo::MultiPoint;
use geo::Point;
use geozero::error::GeozeroError;
use geozero::wkb::Ewkb;
use geozero::wkb::FromWkb;
use geozero::wkb::WkbDialect;
use geozero::CoordDimensions;
use geozero::ToWkb;
use geozero::ToWkt;
Expand All @@ -34,6 +40,7 @@ use geozero::ToWkt;
pub fn register(registry: &mut FunctionRegistry) {
// aliases
registry.register_aliases("st_makegeompoint", &["st_geom_point"]);
registry.register_aliases("st_makeline", &["st_make_line"]);
registry.register_aliases("st_geometryfromwkt", &[
"st_geomfromwkt",
"st_geometryfromewkt",
Expand Down Expand Up @@ -67,6 +74,81 @@ pub fn register(registry: &mut FunctionRegistry) {
})
);

registry.register_passthrough_nullable_2_arg::<GeometryType, GeometryType, GeometryType, _, _>(
"st_makeline",
|_, _, _| FunctionDomain::Full,
vectorize_with_builder_2_arg::<GeometryType, GeometryType, GeometryType>(
|left_exp, right_exp, builder, ctx| {
if let Some(validity) = &ctx.validity {
if !validity.get_bit(builder.len()) {
builder.commit_row();
return;
}
}

let geometries: Vec<Geometry> = match binary_to_geometry(&vec![left_exp, right_exp])
kkk25641463 marked this conversation as resolved.
Show resolved Hide resolved
{
Ok(g) => g,
Err(e) => {
ctx.set_error(builder.len(), e.to_string());
return builder.put_str("");
}
};

kkk25641463 marked this conversation as resolved.
Show resolved Hide resolved
let mut coords: Vec<Coord> = vec![];
for geometry in geometries.into_iter() {
match geometry {
Geometry::Point(_) => {
let point: Point = match geometry.try_into() {
Ok(point) => point,
Err(e) => {
ctx.set_error(builder.len(), e.to_string());
return builder.put_str("");
}
};
coords.push(point.into());
}
Geometry::LineString(_) => {
let line: LineString = match geometry.try_into() {
Ok(line) => line,
Err(e) => {
ctx.set_error(builder.len(), e.to_string());
return builder.put_str("");
}
};
coords.append(&mut line.into_inner());
}
Geometry::MultiPoint(_) => {
let multi_point: MultiPoint = match geometry.try_into() {
Ok(multi_point) => multi_point,
Err(e) => {
ctx.set_error(builder.len(), e.to_string());
return builder.put_str("");
}
};
for point in multi_point.into_iter() {
coords.push(point.into());
}
}
_ => {
ctx.set_error(
builder.len(),
"Geometry expression must be a Point, MultiPoint, or LineString.",
);
return builder.put_str("");
}
}
}
let geom = Geometry::from(LineString::new(coords));
kkk25641463 marked this conversation as resolved.
Show resolved Hide resolved
match geom.to_ewkb(CoordDimensions::xy(), None) {
Ok(data) => builder.put_slice(data.as_slice()),
Err(e) => ctx.set_error(builder.len(), e.to_string()),
}
builder.commit_row();
},
),
);

registry.register_passthrough_nullable_1_arg::<StringType, GeometryType, _, _>(
"st_geometryfromwkt",
|_, _| FunctionDomain::MayThrow,
Expand Down Expand Up @@ -244,3 +326,14 @@ pub fn register(registry: &mut FunctionRegistry) {
//
// Ok(srid)
// }
#[inline(always)]
fn binary_to_geometry(binaries: &Vec<&[u8]>) -> Result<Vec<Geometry>, GeozeroError> {
let mut geometries: Vec<Geometry> = Vec::with_capacity(binaries.len());
for binary in binaries.into_iter() {
match Geometry::from_wkb(&mut std::io::Cursor::new(binary), WkbDialect::Ewkb) {
Ok(data) => geometries.push(data),
Err(e) => return Err(e),
};
}
Ok(geometries)
}
25 changes: 21 additions & 4 deletions src/query/functions/tests/it/scalars/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,42 @@

use std::io::Write;

use databend_common_expression::types::Float64Type;
use goldenfile::Mint;

use databend_common_expression::FromData;
use databend_common_expression::types::{BinaryType, Float64Type};
use databend_common_expression::types::Int32Type;
use databend_common_expression::types::StringType;
use databend_common_expression::FromData;
use goldenfile::Mint;

use crate::scalars::run_ast;

#[test]
fn test_geometry() {
let mut mint = Mint::new("tests/it/scalars/testdata");
let file = &mut mint.new_goldenfile("geometry.txt").unwrap();

test_st_makeline(file);
test_st_makepoint(file);
test_to_string(file);
test_st_geometryfromwkt(file);
// test_st_transform(file);
}

fn test_st_makeline(file: &mut impl Write) {
run_ast(file, "st_makeline(
to_geometry('POINT(1.0 2.0)'),
to_geometry('POINT(3.5 4.5)'))", &[]);
run_ast(file, "st_makeline(
to_geometry('POINT(1.0 2.0)'),
to_geometry('LINESTRING(1.0 2.0, 10.1 5.5)'))", &[]);
run_ast(file, "st_makeline(
to_geometry('LINESTRING(1.0 2.0, 10.1 5.5)'),
to_geometry('MULTIPOINT(3.5 4.5, 6.1 7.9)'))", &[]);
run_ast(file, "st_makeline(a, b)", &[
("a", BinaryType::from_data(vec!["LINESTRING(1.0 2.0, 10.1 5.5)".as_bytes()])),
("b", BinaryType::from_data(vec!["MULTIPOINT(3.5 4.5, 6.1 7.9)".as_bytes()])),
]);
}

fn test_st_makepoint(file: &mut impl Write) {
run_ast(file, "st_makegeompoint(7.0, 8.0)", &[]);
run_ast(file, "st_makegeompoint(7.0, -8.0)", &[]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ st_geometryfromtext -> st_geometryfromwkt
st_geomfromewkt -> st_geometryfromwkt
st_geomfromtext -> st_geometryfromwkt
st_geomfromwkt -> st_geometryfromwkt
st_make_line -> st_makeline
str_to_date -> to_date
str_to_timestamp -> to_timestamp
str_to_year -> to_year
Expand Down Expand Up @@ -3500,6 +3501,8 @@ Functions overloads:
3 st_geometryfromwkt(String NULL, Int32 NULL) :: Geometry NULL
0 st_makegeompoint(Float64, Float64) :: Geometry
1 st_makegeompoint(Float64 NULL, Float64 NULL) :: Geometry NULL
0 st_makeline(Geometry, Geometry) :: Geometry
1 st_makeline(Geometry NULL, Geometry NULL) :: Geometry NULL
0 strcmp(String, String) :: Int8
1 strcmp(String NULL, String NULL) :: Int8 NULL
0 string_to_h3(String) :: UInt64
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,26 @@ SELECT a, g FROM t1
#SRID=3857;POINT(1489140.0937656453 6892872.198680114)
#SRID=3857;POINT(500961.30830177927 6829319.683153116)

statement ok
DROP TABLE IF EXISTS t1

statement ok
CREATE TABLE t1 (g1 geometry, g2 geometry)

statement ok
INSERT INTO t1 VALUES(TO_GEOMETRY('POINT(1.0 2.0)'), TO_GEOMETRY('POINT(3.5 4.5)', 32633)),
(TO_GEOMETRY('POINT(1.0 2.0)'), TO_GEOMETRY('LINESTRING(1.0 2.0, 10.1 5.5)')),
(TO_GEOMETRY('LINESTRING(1.0 2.0, 10.1 5.5)'), TO_GEOMETRY('MULTIPOINT(3.5 4.5, 6.1 7.9)'))

query T
SELECT to_string(st_makeline(g1, g2)) FROM t1
----
LINESTRING(1 2,3.5 4.5)
LINESTRING(1 2,1 2,10.1 5.5)
LINESTRING(1 2,10.1 5.5,3.5 4.5,6.1 7.9)

statement ok
SET enable_geo_create_table=0

statement ok
DROP TABLE IF EXISTS t1
DROP TABLE IF EXISTS t1
Loading