diff --git a/README.md b/README.md index 63b0f51..6c0e1d6 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,9 @@ SparkSession spark = SparkSession.builder().appName("mobilityspark").master("loc GeneratedSpatioTemporalUDFs.registerAll(spark); ``` -Temporal values travel as strings in MEOS hex-WKB, and geometries as hex-EWKB, so any Spark type -system carries them: +Temporal values, spans, span sets and sets travel as their MEOS WKB bytes, a binary column, and a +column of their hex-WKB text reads as well; geometries travel as WKT or EWKT text, and boxes, +circular buffers, network points and poses as their text form: ```sql -- accessors under their canonical MobilityDB SQL names @@ -140,8 +141,8 @@ mvn -B clean test ``` `GeneratedSurfaceTest` drives the generated surface from known hex-WKB literals and asserts that -it *binds and executes*, not merely that it compiles: scalar accessors and I/O round-trips, double -/ boolean / byte marshalling, the cbuffer and npoint families, the JSON-path surface, value-array +it *binds and executes*, not merely that it compiles: scalar accessors and I/O round-trips, the +WKB bytes the functions return and the hex-WKB text they read, double / boolean / byte marshalling, the cbuffer and npoint families, the JSON-path surface, value-array accessors, the N-by-N array UDFs, the canonical `@sqlfn` names with runtime argument-kind dispatch, a folded out-parameter, and the H3 cell prefilter. The operator names are read from the catalog's own `byOperator` and `positionNames` maps rather than hard-coded, so a dialect rename diff --git a/src/main/java/org/mobilitydb/spark/MeosMemory.java b/src/main/java/org/mobilitydb/spark/MeosMemory.java index ef62f8c..c62d480 100644 --- a/src/main/java/org/mobilitydb/spark/MeosMemory.java +++ b/src/main/java/org/mobilitydb/spark/MeosMemory.java @@ -47,7 +47,7 @@ * * Usage: *
- * Pointer tptr = GeneratedFunctions.temporal_from_hexwkb(hex);
+ * Pointer tptr = GeneratedFunctions.temporal_from_wkb(wkb);
* try {
* // ... use tptr ...
* } finally {
diff --git a/src/test/java/org/mobilitydb/spark/GeneratedSurfaceTest.java b/src/test/java/org/mobilitydb/spark/GeneratedSurfaceTest.java
index 8810b2b..844d4b9 100644
--- a/src/test/java/org/mobilitydb/spark/GeneratedSurfaceTest.java
+++ b/src/test/java/org/mobilitydb/spark/GeneratedSurfaceTest.java
@@ -204,10 +204,10 @@ void portable_bare_name_dispatch_surface() {
assertEquals(Boolean.TRUE, scalar(
"SELECT " + position("&<#", "tbox") + "('" + TINT_HEX + "', '" + TINT_HEX + "')"));
// temporal comparison (#=): of a value with itself is a temporal bool, carried as
- // hex-WKB, not the boolean of the traditional =
+ // WKB, not the boolean of the traditional =
Object teq = scalar("SELECT " + op("#=") + "('" + TINT_HEX + "', '" + TINT_HEX + "')");
assertNotNull(teq);
- assertTrue(teq instanceof String, "#= answers a temporal boolean, not " + teq.getClass());
+ assertTrue(teq instanceof byte[], "#= answers a temporal boolean, not " + teq.getClass());
// ever comparison (?=): same value → true
assertEquals(Boolean.TRUE, scalar(
"SELECT " + op("?=") + "('" + TINT_HEX + "', '" + TINT_HEX + "')"));
@@ -275,6 +275,30 @@ void as_hexwkb_family_with_swallowed_size_out_param() {
"SELECT temporal_num_instants(temporal_from_hexwkb('" + hex + "'))")).intValue());
}
+ @Test
+ void values_travel_as_wkb_and_hex_wkb_stays_readable() {
+ String tint = "tint_in('[1@2001-01-01, 2@2001-01-02, 1@2001-01-03]')";
+ // A temporal, and the span a function derives from it, travel as their WKB bytes.
+ Object t = scalar("SELECT " + tint);
+ assertTrue(t instanceof byte[], "a temporal travels as WKB, got " + t.getClass());
+ Object span = scalar("SELECT timeSpan(" + tint + ")");
+ assertTrue(span instanceof byte[], "a span travels as WKB, got " + span.getClass());
+ // The bytes and the hex-WKB text of one value answer alike.
+ assertEquals(3, ((Number) scalar("SELECT numInstants(" + tint + ")")).intValue());
+ assertEquals(3, ((Number) scalar("SELECT numInstants('" + TINT_HEX + "')")).intValue());
+ // Hex-WKB in the big-endian byte order (WKB_EXTENDED | WKB_XDR = 20) is read by its
+ // own order, the type standing in the second and third bytes.
+ assertEquals(3, ((Number) scalar("SELECT numInstants(temporal_as_hexwkb("
+ + tint + ", CAST(20 AS BYTE)))")).intValue());
+ // An aggregate over a column of hex-WKB text answers what it answers over the WKB
+ // of the same value.
+ Object overWkb = scalar("SELECT tint_out(tCount(v)) FROM (SELECT temporal_from_hexwkb('"
+ + TINT_HEX + "') AS v)");
+ assertNotNull(overWkb);
+ assertEquals(overWkb,
+ scalar("SELECT tint_out(tCount(s)) FROM VALUES ('" + TINT_HEX + "') AS t(s)"));
+ }
+
@Test
void bool_result_value_at_timestamptz_folds_the_value_out_param() {
// tint_value_at_timestamptz(temp, t, strict, int *value) returns bool and writes