From 1609cd1cbc4adfe4525acd9abd230b002a5c1beb Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Sun, 11 Oct 2026 19:58:41 +0200 Subject: [PATCH] Check the aggregates over a base value on the typed Spark surface GeneratedSqlSurfaceTest.baseValueAggregatesAnswerWhatMobilityDBAnswers checks that setUnionAgg over integers, bigints, floats, texts, dates and timestamps, extent over integers, bigints, floats, dates and timestamps, and tCount over timestamps answer what MobilityDB answers over the same values with the time zone set to UTC, each value in a partition of its own, so the combine joins the partial states: {1, 2, 3} for the integers 3, 1, 2 and 1, [1, 4) for their extent, {1@2001-01-01 00:00:00+00, 2@2001-01-02 00:00:00+00} for the count of three timestamps two of which are equal. Witness: with the generator of JMEOS main e8c65dc4 the surface registers none of the 12, and the test fails with "aggregate setUnionAgg(int) does not exist". Measured over MobilityDB b2dcdf7d84, the catalog of MEOS-API 9b337a00fe and JMEOS main 67294a87, which carries #176: the 46 tests pass, 18 of them in GeneratedSqlSurfaceTest, with 0 warnings. Why: a set, a span or a count over the integers, dates or timestamps of a table answers on Spark as it does in PostgreSQL. --- .../spark/GeneratedSqlSurfaceTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/test/java/org/mobilitydb/spark/GeneratedSqlSurfaceTest.java b/src/test/java/org/mobilitydb/spark/GeneratedSqlSurfaceTest.java index 1e74ba3b..42e64066 100644 --- a/src/test/java/org/mobilitydb/spark/GeneratedSqlSurfaceTest.java +++ b/src/test/java/org/mobilitydb/spark/GeneratedSqlSurfaceTest.java @@ -407,6 +407,43 @@ void appendAggregatesAnswerWhatMobilityDBAnswersOrderedByTime() { String.valueOf(rootMessage(e))); } + /** The text of an aggregate over the SQL literals given, each in a partition of its own, so + * the combine joins the partial states, as #aggregate reads one over typed values. */ + private static String baseAggregate(String agg, String... values) { + StringBuilder rows = new StringBuilder(); + for (String v : values) { + rows.append(rows.length() == 0 ? "" : ", ").append("(").append(v).append(")"); + } + return (String) scalar("SELECT asText(" + agg + "(v)) FROM (SELECT /*+ REPARTITION(" + + values.length + ") */ v FROM VALUES " + rows + " AS t(v))"); + } + + @Test + void baseValueAggregatesAnswerWhatMobilityDBAnswers() { + // What MobilityDB answers for the same aggregate over the same values with the time zone + // set to UTC. + assertEquals("{1, 2, 3}", baseAggregate("setUnionAgg", "3", "1", "2", "1")); + assertEquals("{10, 20, 30}", baseAggregate("setUnionAgg", + "CAST(30 AS BIGINT)", "CAST(10 AS BIGINT)", "CAST(20 AS BIGINT)")); + assertEquals("{1.5, 2.5}", baseAggregate("setUnionAgg", + "CAST(2.5 AS DOUBLE)", "CAST(1.5 AS DOUBLE)", "CAST(2.5 AS DOUBLE)")); + assertEquals("{\"a\", \"b\"}", baseAggregate("setUnionAgg", "'b'", "'a'", "'b'")); + assertEquals("{2001-01-01, 2001-01-03}", baseAggregate("setUnionAgg", + "DATE '2001-01-03'", "DATE '2001-01-01'")); + assertEquals("{\"2001-01-01 00:00:00+00\", \"2001-01-03 00:00:00+00\"}", + baseAggregate("setUnionAgg", "TIMESTAMP '2001-01-03 00:00:00'", "TIMESTAMP '2001-01-01 00:00:00'")); + assertEquals("[1, 4)", baseAggregate("extent", "3", "1", "2")); + assertEquals("[10, 31)", baseAggregate("extent", "CAST(30 AS BIGINT)", "CAST(10 AS BIGINT)")); + assertEquals("[1.5, 2.5]", baseAggregate("extent", "CAST(2.5 AS DOUBLE)", "CAST(1.5 AS DOUBLE)")); + assertEquals("[2001-01-01, 2001-01-04)", baseAggregate("extent", + "DATE '2001-01-03'", "DATE '2001-01-01'")); + assertEquals("[2001-01-01 00:00:00+00, 2001-01-03 00:00:00+00]", baseAggregate("extent", + "TIMESTAMP '2001-01-03 00:00:00'", "TIMESTAMP '2001-01-01 00:00:00'")); + assertEquals("{1@2001-01-01 00:00:00+00, 2@2001-01-02 00:00:00+00}", baseAggregate("tCount", + "TIMESTAMP '2001-01-02 00:00:00'", "TIMESTAMP '2001-01-01 00:00:00'", + "TIMESTAMP '2001-01-02 00:00:00'")); + } + private static String rootMessage(Throwable e) { while (e.getCause() != null) { e = e.getCause();