From 5f1f8f05095c729a3cee2e46be333c2557361b03 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Sat, 24 Oct 2026 18:14:24 +0200 Subject: [PATCH] Generate the route operators of a temporal network point The route operators of a temporal network point are generated from the catalog: the group meos_npoint_route, one public MEOS function per SQL signature and argument order, is retired beside the other network point groups. Each of the twenty signatures MobilityDB declares registers under its own name, argument types and result, with its operator: overlapsRid and @@, containsRid and @?, containedRid and ?@, sameRid and @= over a route, a set of routes, a network point and a temporal network point in the orders MobilityDB declares them. Measured: over the catalog of MobilityDB ac8feb51dc, the commit this branch's pin records, the generator writes the same registrations as before but four: containedRid(npoint, tnpoint), sameRid(npoint, tnpoint) and their operators ?@ and @=, which register nothing before; no registration is lost and none is registered twice. No hand registration of these names exists to delete. test/sql/tnpoint.test reads containedRid and sameRid with the network point first against their twins with the temporal value first, over a route both values hold and one neither holds. --- src/generated/generated_temporal_udfs_4.cpp | 46 +++++++++++++++++++++ test/sql/tnpoint.test | 21 ++++++++++ tools/codegen_duck_udfs.py | 3 ++ 3 files changed, 70 insertions(+) diff --git a/src/generated/generated_temporal_udfs_4.cpp b/src/generated/generated_temporal_udfs_4.cpp index 0ebe7e53..c363ef88 100644 --- a/src/generated/generated_temporal_udfs_4.cpp +++ b/src/generated/generated_temporal_udfs_4.cpp @@ -2488,6 +2488,48 @@ static void Gen_same_rid_tnpoint_tnpoint(DataChunk &args, ExpressionState &, Vec }); } +static void Gen_contained_rid_npoint_tnpoint(DataChunk &args, ExpressionState &, Vector &result) { + EnsureMeosThreadInitialized(); + const idx_t rows = args.size(); + for (idx_t c = 0; c < 2; c++) args.data[c].Flatten(rows); + auto in0 = FlatVector::GetData(args.data[0]); + auto in1 = FlatVector::GetData(args.data[1]); + auto out = FlatVector::GetData(result); + auto &outv = FlatVector::Validity(result); + for (idx_t i = 0; i < rows; i++) { + if (!FlatVector::Validity(args.data[0]).RowIsValid(i)) { outv.SetInvalid(i); continue; } + if (!FlatVector::Validity(args.data[1]).RowIsValid(i)) { outv.SetInvalid(i); continue; } + Npoint *p0 = BlobToNpoint(in0[i]); + Temporal *p1 = BlobToTemporal(in1[i]); + bool r = contained_rid_npoint_tnpoint(p0, p1); + free(p0); + free(p1); + out[i] = (bool) r; + } + if (rows == 1) result.SetVectorType(VectorType::CONSTANT_VECTOR); +} + +static void Gen_same_rid_npoint_tnpoint(DataChunk &args, ExpressionState &, Vector &result) { + EnsureMeosThreadInitialized(); + const idx_t rows = args.size(); + for (idx_t c = 0; c < 2; c++) args.data[c].Flatten(rows); + auto in0 = FlatVector::GetData(args.data[0]); + auto in1 = FlatVector::GetData(args.data[1]); + auto out = FlatVector::GetData(result); + auto &outv = FlatVector::Validity(result); + for (idx_t i = 0; i < rows; i++) { + if (!FlatVector::Validity(args.data[0]).RowIsValid(i)) { outv.SetInvalid(i); continue; } + if (!FlatVector::Validity(args.data[1]).RowIsValid(i)) { outv.SetInvalid(i); continue; } + Npoint *p0 = BlobToNpoint(in0[i]); + Temporal *p1 = BlobToTemporal(in1[i]); + bool r = same_rid_npoint_tnpoint(p0, p1); + free(p0); + free(p1); + out[i] = (bool) r; + } + if (rows == 1) result.SetVectorType(VectorType::CONSTANT_VECTOR); +} + static void Gen_contained_rid_bigintset_tnpoint(DataChunk &args, ExpressionState &, Vector &result) { EnsureMeosThreadInitialized(); BinaryExecutor::Execute(args.data[0], args.data[1], result, args.size(), @@ -5441,6 +5483,10 @@ void RegisterGenerated_meos_npoint_route(ExtensionLoader &loader) { RegisterSerializedScalarFunction(loader, ScalarFunction("@=", {NpointTypes::tnpoint(), NpointTypes::npoint()}, LogicalType::BOOLEAN, Gen_same_rid_tnpoint_npoint)); RegisterSerializedScalarFunction(loader, ScalarFunction("sameRid", {NpointTypes::tnpoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_same_rid_tnpoint_tnpoint)); RegisterSerializedScalarFunction(loader, ScalarFunction("@=", {NpointTypes::tnpoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_same_rid_tnpoint_tnpoint)); + RegisterSerializedScalarFunction(loader, ScalarFunction("containedRid", {NpointTypes::npoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_contained_rid_npoint_tnpoint)); + RegisterSerializedScalarFunction(loader, ScalarFunction("?@", {NpointTypes::npoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_contained_rid_npoint_tnpoint)); + RegisterSerializedScalarFunction(loader, ScalarFunction("sameRid", {NpointTypes::npoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_same_rid_npoint_tnpoint)); + RegisterSerializedScalarFunction(loader, ScalarFunction("@=", {NpointTypes::npoint(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_same_rid_npoint_tnpoint)); RegisterSerializedScalarFunction(loader, ScalarFunction("containedRid", {SetTypes::bigintset(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_contained_rid_bigintset_tnpoint)); RegisterSerializedScalarFunction(loader, ScalarFunction("?@", {SetTypes::bigintset(), NpointTypes::tnpoint()}, LogicalType::BOOLEAN, Gen_contained_rid_bigintset_tnpoint)); RegisterSerializedScalarFunction(loader, ScalarFunction("containedRid", {NpointTypes::tnpoint(), SetTypes::bigintset()}, LogicalType::BOOLEAN, Gen_contained_rid_tnpoint_bigintset)); diff --git a/test/sql/tnpoint.test b/test/sql/tnpoint.test index 979e9313..18bca698 100644 --- a/test/sql/tnpoint.test +++ b/test/sql/tnpoint.test @@ -157,3 +157,24 @@ SELECT asText(atStbox(tnpoint '[NPoint(1, 0.2)@2000-01-01, NPoint(1, 0.8)@2000-0 stbox 'STBOX T([2000-01-01,2000-01-02])')); ---- {[NPoint(1,0.2)@2000-01-01 00:00:00+01, NPoint(1,0.5)@2000-01-02 00:00:00+01]} {(NPoint(1,0.5)@2000-01-02 00:00:00+01, NPoint(1,0.8)@2000-01-03 00:00:00+01]} + +# The route operators with the network point first answer as their twins with the +# temporal value first: containedRid(np, temp) asks whether the routes of temp hold the +# route of np, as containsRid(temp, np) does, and sameRid is symmetric. Route 1 is held +# by both values, route 3 by neither, and the second value has two routes. DuckDB reads +# `?` as a prepared-statement parameter, so ?@ is called by its name. +query IIII +SELECT containedRid(npoint 'NPoint(1, 0.5)', tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(2, 0.5)@2001-01-02}'), + containedRid(npoint 'NPoint(3, 0.5)', tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(2, 0.5)@2001-01-02}'), + "?@"(npoint 'NPoint(1, 0.5)', tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(2, 0.5)@2001-01-02}'), + containsRid(tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(2, 0.5)@2001-01-02}', npoint 'NPoint(1, 0.5)'); +---- +true false true true + +query IIII +SELECT sameRid(npoint 'NPoint(1, 0.5)', tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.6)@2001-01-02}'), + sameRid(npoint 'NPoint(1, 0.5)', tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(2, 0.5)@2001-01-02}'), + npoint 'NPoint(1, 0.5)' @= tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.6)@2001-01-02}', + sameRid(tnpoint '{NPoint(1, 0.3)@2001-01-01, NPoint(1, 0.6)@2001-01-02}', npoint 'NPoint(1, 0.5)'); +---- +true false true true diff --git a/tools/codegen_duck_udfs.py b/tools/codegen_duck_udfs.py index 6ceefb17..c70ae8df 100644 --- a/tools/codegen_duck_udfs.py +++ b/tools/codegen_duck_udfs.py @@ -5398,6 +5398,9 @@ def emit_container_scalar(f, ops, rev): "meos_s2cell_set_conversion", "meos_cbuffer_set_constructor", "meos_h3_set_constructor", "meos_json_set_constructor", "meos_npoint_set_constructor", + # The route operators of a temporal network point, one public function per + # signature and argument order: overlapsRid, containsRid, containedRid, sameRid + "meos_npoint_route", "meos_pointcloud_set_constructor", "meos_pose_set_constructor", "meos_posechain_set_constructor", "meos_quadbin_set_constructor", "meos_s2cell_set_constructor",