Skip to content

Commit 3e5c251

Browse files
authored
feat(query): implement ST_POINTN (#15373)
ST_POINTN Signed-off-by: Fan Yang <yangfanlinux@gmail.com>
1 parent 52e0714 commit 3e5c251

File tree

5 files changed

+113
-0
lines changed

5 files changed

+113
-0
lines changed

src/query/functions/src/scalars/geometry.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,74 @@ pub fn register(registry: &mut FunctionRegistry) {
268268
}),
269269
);
270270

271+
registry.register_passthrough_nullable_2_arg::<GeometryType, Int32Type, GeometryType, _, _>(
272+
"st_pointn",
273+
|_, _, _| FunctionDomain::MayThrow,
274+
vectorize_with_builder_2_arg::<GeometryType, Int32Type, GeometryType>(
275+
|geometry, index, builder, ctx| {
276+
if let Some(validity) = &ctx.validity {
277+
if !validity.get_bit(builder.len()) {
278+
builder.commit_row();
279+
return;
280+
}
281+
}
282+
283+
let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() {
284+
Ok(geo) => geo,
285+
Err(e) => {
286+
ctx.set_error(
287+
builder.len(),
288+
ErrorCode::GeometryError(e.to_string()).to_string(),
289+
);
290+
builder.commit_row();
291+
return;
292+
}
293+
};
294+
295+
let point = match <geo_types::Geometry as TryInto<LineString>>::try_into(geo) {
296+
Ok(line_string) => {
297+
let len = line_string.0.len() as i32;
298+
if index >= -len && index < len && index != 0 {
299+
Point(
300+
line_string.0
301+
[if index < 0 { len + index } else { index - 1 } as usize],
302+
)
303+
} else {
304+
ctx.set_error(
305+
builder.len(),
306+
ErrorCode::GeometryError(format!(
307+
"Index { } is out of bounds",
308+
index
309+
))
310+
.to_string(),
311+
);
312+
builder.commit_row();
313+
return;
314+
}
315+
}
316+
Err(e) => {
317+
ctx.set_error(
318+
builder.len(),
319+
ErrorCode::GeometryError(e.to_string()).to_string(),
320+
);
321+
builder.commit_row();
322+
return;
323+
}
324+
};
325+
326+
match geo_types::Geometry::from(point).to_wkb(CoordDimensions::xy()) {
327+
Ok(binary) => builder.put_slice(binary.as_slice()),
328+
Err(e) => ctx.set_error(
329+
builder.len(),
330+
ErrorCode::GeometryError(e.to_string()).to_string(),
331+
),
332+
};
333+
334+
builder.commit_row();
335+
},
336+
),
337+
);
338+
271339
registry.register_combine_nullable_1_arg::<GeometryType, Int32Type, _, _>(
272340
"st_dimension",
273341
|_, _| FunctionDomain::MayThrow,

src/query/functions/tests/it/scalars/geometry.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn test_geometry() {
3939
test_st_makeline(file);
4040
test_st_makepoint(file);
4141
test_st_makepolygon(file);
42+
test_st_pointn(file);
4243
test_to_geometry(file);
4344
test_to_string(file);
4445
test_try_to_geometry(file);
@@ -227,6 +228,19 @@ fn test_st_makepolygon(file: &mut impl Write) {
227228
)]);
228229
}
229230

231+
fn test_st_pointn(file: &mut impl Write) {
232+
run_ast(
233+
file,
234+
"ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), 1)",
235+
&[],
236+
);
237+
run_ast(
238+
file,
239+
"ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), -2)",
240+
&[],
241+
);
242+
}
243+
230244
fn test_to_geometry(file: &mut impl Write) {
231245
run_ast(file, "to_geometry('POINT(1820.12 890.56)')", &[]);
232246
run_ast(file, "to_geometry('SRID=4326;POINT(1820.12 890.56)')", &[]);

src/query/functions/tests/it/scalars/testdata/function_list.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3546,6 +3546,8 @@ Functions overloads:
35463546
1 st_makeline(Geometry NULL, Geometry NULL) :: Geometry NULL
35473547
0 st_makepolygon(Geometry) :: Geometry
35483548
1 st_makepolygon(Geometry NULL) :: Geometry NULL
3549+
0 st_pointn(Geometry, Int32) :: Geometry
3550+
1 st_pointn(Geometry NULL, Int32 NULL) :: Geometry NULL
35493551
0 strcmp(String, String) :: Int8
35503552
1 strcmp(String NULL, String NULL) :: Int8 NULL
35513553
0 string_to_h3(String) :: UInt64

src/query/functions/tests/it/scalars/testdata/geometry.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,24 @@ evaluation (internal):
330330
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
331331

332332

333+
ast : ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), 1)
334+
raw expr : ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), 1)
335+
checked expr : st_pointn<Geometry, Int32>(to_geometry<String>("LINESTRING(1 1, 2 2, 3 3, 4 4)"), to_int32<UInt8>(1_u8))
336+
optimized expr : "POINT(1 1)"
337+
output type : Geometry
338+
output domain : Undefined
339+
output : 'POINT(1 1)'
340+
341+
342+
ast : ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), -2)
343+
raw expr : ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), minus(2))
344+
checked expr : st_pointn<Geometry, Int32>(to_geometry<String>("LINESTRING(1 1, 2 2, 3 3, 4 4)"), to_int32<Int16>(minus<UInt8>(2_u8)))
345+
optimized expr : "POINT(3 3)"
346+
output type : Geometry
347+
output domain : Undefined
348+
output : 'POINT(3 3)'
349+
350+
333351
ast : to_geometry('POINT(1820.12 890.56)')
334352
raw expr : to_geometry('POINT(1820.12 890.56)')
335353
checked expr : to_geometry<String>("POINT(1820.12 890.56)")

tests/sqllogictests/suites/query/functions/02_0060_function_geometry.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,17 @@ SELECT ST_DIMENSION(g) FROM t1;
412412
2
413413
2
414414

415+
query T
416+
SELECT TO_STRING(ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), 2))
417+
----
418+
POINT(2 2)
419+
420+
query T
421+
SELECT TO_STRING(ST_POINTN(TO_GEOMETRY('LINESTRING(1 1, 2 2, 3 3, 4 4)'), -2))
422+
----
423+
POINT(3 3)
424+
425+
415426
statement ok
416427
SET enable_geo_create_table=0
417428

0 commit comments

Comments
 (0)