From 4532e24cf0fe3d47fcd704e36f71491803c069eb Mon Sep 17 00:00:00 2001 From: serprex <159546+serprex@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:30:19 +0000 Subject: [PATCH 1/5] map temporal, uuid, json types via pg-clickhouse-c --- CHANGELOG.md | 3 + src/deparse.c | 28 +++-- src/pglink.c | 3 +- test/expected/functions.out | 72 ++++++------ test/expected/functions_0.out | 72 ++++++------ test/expected/functions_1.out | 72 ++++++------ test/expected/functions_2.out | 72 ++++++------ test/expected/functions_3.out | 72 ++++++------ test/expected/functions_5.out | 72 ++++++------ test/expected/functions_6.out | 72 ++++++------ test/expected/functions_7.out | 72 ++++++------ test/expected/functions_8.out | 72 ++++++------ test/expected/functions_9.out | 72 ++++++------ test/expected/param.out | 199 ++++++++++++++++++++++++++++++++-- test/expected/param_1.out | 199 ++++++++++++++++++++++++++++++++-- test/expected/param_2.out | 199 ++++++++++++++++++++++++++++++++-- test/sql/param.sql | 81 ++++++++++++++ vendor/pg-clickhouse-c | 2 +- 18 files changed, 1039 insertions(+), 395 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cae74b80..b6dcd9ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. It uses the ### ⚡ Improvements +* Added pushdown for datetime arithmetic with interval parameters ([#389]). * Added pushdown for more regression aggregate functions on ClickHouse 26.9+: * [regr_avgx] * [regr_avgy] @@ -34,6 +35,8 @@ All notable changes to this project will be documented in this file. It uses the ### 🐞 Bug Fixes +* Fixed ClickHouse type mappings for temporal, UUID, and JSON casts and + parameters, preserving timestamp precision and UTC semantics ([#389]). * Fixed GCC 15 build failure caused by a `-Wclobbered` error in binary driver connection setup ([#395]). diff --git a/src/deparse.c b/src/deparse.c index c99ca3b2..2c36c1bf 100644 --- a/src/deparse.c +++ b/src/deparse.c @@ -48,6 +48,7 @@ #include "utils/typcache.h" #include "fdw.h" +#include "pg-clickhouse-encode.h" /* Aggregate OIDs absent from fmgroids.h on all PG versions. */ #define F_STRING_AGG_TEXT_TEXT 3538 @@ -1872,12 +1873,14 @@ ch_format_type_extended(Oid type_oid, int32 typemod, uint16 flags) { } break; + case TIMEOID: case TIMESTAMPTZOID: case TIMESTAMPOID: - buf = pstrdup("DateTime"); - break; case DATEOID: - buf = pstrdup("Date"); + case UUIDOID: + case JSONOID: + case JSONBOID: + buf = pgch_ch_type_for(type_oid, with_typemod ? typemod : -1, true, NULL); break; case VARCHAROID: @@ -3411,12 +3414,17 @@ deparseConst(Const* node, deparse_expr_cxt* context, int showtype) { return; } + getTypeOutputInfo(node->consttype, &typoutput, &typIsVarlena); + + /* Bare literal would parse in column timezone, not UTC */ + if (showtype == 0 && typoutput == F_TIMESTAMPTZ_OUT) { + showtype = 1; + } + if (showtype > 0) { appendStringInfoString(buf, "cast("); } - getTypeOutputInfo(node->consttype, &typoutput, &typIsVarlena); - if (typoutput == F_TIMESTAMPTZ_OUT || typoutput == F_TIMESTAMP_OUT) { char ts[MAXDATELEN + 1]; @@ -4355,9 +4363,11 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { appendStringInfoString(buf, "cast("); deparseExpr((Expr*)linitial(node->args), context); - appendStringInfo( - buf, ", 'Nullable(%s)')", deparse_type_name(rettype, coercedTypmod) + appendStringInfoString(buf, ", "); + deparseStringLiteral( + buf, psprintf("Nullable(%s)", deparse_type_name(rettype, coercedTypmod)) ); + appendStringInfoChar(buf, ')'); return; } @@ -5617,7 +5627,9 @@ deparseArrayExpr(ArrayExpr* node, deparse_expr_cxt* context) { /* If the array is empty, we need an explicit cast to the array type. */ if (node->elements == NIL) { - appendStringInfo(buf, ", '%s')", deparse_type_name(node->array_typeid, -1)); + appendStringInfoString(buf, ", "); + deparseStringLiteral(buf, deparse_type_name(node->array_typeid, -1)); + appendStringInfoChar(buf, ')'); } } diff --git a/src/pglink.c b/src/pglink.c index b187ea59..0713ebe0 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -482,11 +482,10 @@ chfdw_datum_to_ch_literal(Datum value, Oid type) { return pstrdup(date); } case TIMEOID: { - /* we expect DateTime on other side */ char time[MAXDATELEN + 1]; chfdw_encode_time(DatumGetTimeADT(value), time); - return psprintf("1970-01-01 %s", time); + return pstrdup(time); } case TIMESTAMPOID: case TIMESTAMPTZOID: { diff --git a/test/expected/functions.out b/test/expected/functions.out index 099f37b4..5b19b819 100644 --- a/test/expected/functions.out +++ b/test/expected/functions.out @@ -1184,11 +1184,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1198,11 +1198,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1212,11 +1212,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1401,11 +1401,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1415,11 +1415,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1429,11 +1429,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1573,11 +1573,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1587,11 +1587,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1601,11 +1601,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1615,11 +1615,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1772,11 +1772,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1838,11 +1838,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_0.out b/test/expected/functions_0.out index 76282643..396a57db 100644 --- a/test/expected/functions_0.out +++ b/test/expected/functions_0.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1756,11 +1756,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1822,11 +1822,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_1.out b/test/expected/functions_1.out index 61ce3eff..e705eb60 100644 --- a/test/expected/functions_1.out +++ b/test/expected/functions_1.out @@ -1184,11 +1184,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1198,11 +1198,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1212,11 +1212,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1401,11 +1401,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1415,11 +1415,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1429,11 +1429,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1573,11 +1573,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1587,11 +1587,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1601,11 +1601,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1615,11 +1615,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1772,11 +1772,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1838,11 +1838,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_2.out b/test/expected/functions_2.out index bb1e1674..665913d7 100644 --- a/test/expected/functions_2.out +++ b/test/expected/functions_2.out @@ -1184,11 +1184,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1198,11 +1198,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1212,11 +1212,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1401,11 +1401,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1415,11 +1415,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1429,11 +1429,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1573,11 +1573,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1587,11 +1587,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1601,11 +1601,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1615,11 +1615,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1772,11 +1772,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1838,11 +1838,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_3.out b/test/expected/functions_3.out index 1657e75e..c9ce3f46 100644 --- a/test/expected/functions_3.out +++ b/test/expected/functions_3.out @@ -1184,11 +1184,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1198,11 +1198,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1212,11 +1212,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1401,11 +1401,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1415,11 +1415,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1429,11 +1429,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1573,11 +1573,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1587,11 +1587,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1601,11 +1601,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1615,11 +1615,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1772,11 +1772,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1838,11 +1838,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_5.out b/test/expected/functions_5.out index 1f3f692d..09598f92 100644 --- a/test/expected/functions_5.out +++ b/test/expected/functions_5.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1768,11 +1768,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1834,11 +1834,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_6.out b/test/expected/functions_6.out index 44d5cdc2..872f0e43 100644 --- a/test/expected/functions_6.out +++ b/test/expected/functions_6.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1756,11 +1756,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1822,11 +1822,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_7.out b/test/expected/functions_7.out index c3de7d84..6d632ef3 100644 --- a/test/expected/functions_7.out +++ b/test/expected/functions_7.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1756,11 +1756,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1822,11 +1822,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_8.out b/test/expected/functions_8.out index 0109be39..3b8d4c43 100644 --- a/test/expected/functions_8.out +++ b/test/expected/functions_8.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1756,11 +1756,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1822,11 +1822,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/functions_9.out b/test/expected/functions_9.out index 467d1f2a..63e94652 100644 --- a/test/expected/functions_9.out +++ b/test/expected/functions_9.out @@ -1180,11 +1180,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; -- Check date_part from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1194,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,11 +1208,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; @@ -1397,11 +1397,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; -- Check extract from date. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; @@ -1411,11 +1411,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; - QUERY PLAN ---------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; @@ -1425,11 +1425,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; - QUERY PLAN --------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; @@ -1569,11 +1569,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1; -- Check to_timestamp(float8). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); @@ -1583,11 +1583,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); @@ -1597,11 +1597,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); @@ -1611,11 +1611,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443); (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t6 Output: i64, f64 - Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03')) + Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC')))) (3 rows) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443); @@ -1756,11 +1756,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; -- Use with other functions. EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)')))) + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1822,11 +1822,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1))) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1))) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1; diff --git a/test/expected/param.out b/test/expected/param.out index 72439efc..1ae74c45 100644 --- a/test/expected/param.out +++ b/test/expected/param.out @@ -36,6 +36,21 @@ CALL clickhouse_perform('param_admin', $$ ['foo'] FROM numbers(1, 110) $$); +CALL clickhouse_perform('param_admin', $$ + CREATE TABLE param_test.typed ( + id Int, + u UUID, + ts DateTime64(3, 'UTC'), + lts DateTime64(3), + d Date32, + f Float64 + ) ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('param_admin', $$ + INSERT INTO param_test.typed VALUES + (1, '188dff2f-0205-4912-8210-2214e84482cd', '2026-09-28 23:59:59.500', '2026-09-28 23:59:59.500', '1960-01-01', 1e-10), + (2, '00000000-0000-0000-0000-000000000002', '2026-09-29 00:00:00.000', '2026-09-29 00:00:00.000', '2026-09-29', 0.5) +$$); -- =================================================================== -- binary foreign tables -- =================================================================== @@ -121,12 +136,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM bin_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM bin_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -318,6 +333,85 @@ SELECT c1, c2 FROM bin_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE bin_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_bin_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM bin_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM bin_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM bin_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM bin_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -326,6 +420,10 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- =================================================================== -- http foreign tables -- =================================================================== @@ -411,12 +509,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM http_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM http_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +706,85 @@ SELECT c1, c2 FROM http_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE http_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_http_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM http_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM http_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM http_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM http_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -616,14 +793,20 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table bin_test.ft1 drop cascades to foreign table bin_test.ft2 +drop cascades to foreign table bin_test.typed DROP USER MAPPING FOR CURRENT_USER SERVER param_http_svr; DROP SERVER param_http_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table http_test.ft1 drop cascades to foreign table http_test.ft2 +drop cascades to foreign table http_test.typed diff --git a/test/expected/param_1.out b/test/expected/param_1.out index 37bbeec8..cb3082e0 100644 --- a/test/expected/param_1.out +++ b/test/expected/param_1.out @@ -36,6 +36,21 @@ CALL clickhouse_perform('param_admin', $$ ['foo'] FROM numbers(1, 110) $$); +CALL clickhouse_perform('param_admin', $$ + CREATE TABLE param_test.typed ( + id Int, + u UUID, + ts DateTime64(3, 'UTC'), + lts DateTime64(3), + d Date32, + f Float64 + ) ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('param_admin', $$ + INSERT INTO param_test.typed VALUES + (1, '188dff2f-0205-4912-8210-2214e84482cd', '2026-09-28 23:59:59.500', '2026-09-28 23:59:59.500', '1960-01-01', 1e-10), + (2, '00000000-0000-0000-0000-000000000002', '2026-09-29 00:00:00.000', '2026-09-29 00:00:00.000', '2026-09-29', 0.5) +$$); -- =================================================================== -- binary foreign tables -- =================================================================== @@ -121,12 +136,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM bin_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM bin_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -318,6 +333,85 @@ SELECT c1, c2 FROM bin_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE bin_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_bin_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM bin_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM bin_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM bin_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM bin_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -326,6 +420,10 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- =================================================================== -- http foreign tables -- =================================================================== @@ -411,12 +509,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM http_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM http_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +706,85 @@ SELECT c1, c2 FROM http_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE http_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_http_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM http_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM http_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM http_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM http_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -616,14 +793,20 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table bin_test.ft1 drop cascades to foreign table bin_test.ft2 +drop cascades to foreign table bin_test.typed DROP USER MAPPING FOR CURRENT_USER SERVER param_http_svr; DROP SERVER param_http_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table http_test.ft1 drop cascades to foreign table http_test.ft2 +drop cascades to foreign table http_test.typed diff --git a/test/expected/param_2.out b/test/expected/param_2.out index 2be2fd7b..74ed1dbe 100644 --- a/test/expected/param_2.out +++ b/test/expected/param_2.out @@ -36,6 +36,21 @@ CALL clickhouse_perform('param_admin', $$ ['foo'] FROM numbers(1, 110) $$); +CALL clickhouse_perform('param_admin', $$ + CREATE TABLE param_test.typed ( + id Int, + u UUID, + ts DateTime64(3, 'UTC'), + lts DateTime64(3), + d Date32, + f Float64 + ) ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('param_admin', $$ + INSERT INTO param_test.typed VALUES + (1, '188dff2f-0205-4912-8210-2214e84482cd', '2026-09-28 23:59:59.500', '2026-09-28 23:59:59.500', '1960-01-01', 1e-10), + (2, '00000000-0000-0000-0000-000000000002', '2026-09-29 00:00:00.000', '2026-09-29 00:00:00.000', '2026-09-29', 0.5) +$$); -- =================================================================== -- binary foreign tables -- =================================================================== @@ -121,12 +136,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM bin_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM bin_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -318,6 +333,85 @@ SELECT c1, c2 FROM bin_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE bin_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_bin_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM bin_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM bin_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM bin_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM bin_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -326,6 +420,10 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- =================================================================== -- http foreign tables -- =================================================================== @@ -411,12 +509,12 @@ RESET enable_sort; -- subquery using immutable function (can be sent to remote) PREPARE st3(int) AS SELECT * FROM http_test.ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM http_test.ft2 t2 WHERE c1 > $1 AND date(c5) = date('1970-01-17'::timestamptz)) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20); - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8 Relations: (ft1 t1) LEFT SEMI JOIN (ft2 t2) - Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date('1970-01-17 08:00:00'))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST + Remote SQL: SELECT r1.c1, r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM param_test.ft1 r1 LEFT SEMI JOIN param_test.ft1 r3 ON (((r3.c1 > 10)) AND ((date(r3.c5) = date(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC'))))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +706,85 @@ SELECT c1, c2 FROM http_test.ft1 WHERE c1 = (SELECT 4); 4 | 4 (1 row) +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE http_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_http_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM http_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + QUERY PLAN +----------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((u = {p1:UUID})) +(3 rows) + +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); + id +---- + 1 +(1 row) + +PREPARE st9(timestamptz) AS SELECT id FROM http_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((ts <= {p1:DateTime64(6, 'UTC')})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st9('2026-09-28 23:59:59.999999+00'); + id +---- + 1 +(1 row) + +EXECUTE st9('2026-09-28 23:59:59.4+00'); + id +---- +(0 rows) + +PREPARE st10(timestamp) AS SELECT id FROM http_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((lts <= {p1:DateTime64(6)})) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st10('2026-09-28 23:59:59.999999'); + id +---- + 1 +(1 row) + +PREPARE st11(date) AS SELECT id FROM http_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((d = {p1:Date32})) +(3 rows) + +EXECUTE st11('1960-01-01'); + id +---- + 1 +(1 row) + +RESET plan_cache_mode; -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -616,14 +793,20 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table bin_test.ft1 drop cascades to foreign table bin_test.ft2 +drop cascades to foreign table bin_test.typed DROP USER MAPPING FOR CURRENT_USER SERVER param_http_svr; DROP SERVER param_http_svr CASCADE; -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to foreign table http_test.ft1 drop cascades to foreign table http_test.ft2 +drop cascades to foreign table http_test.typed diff --git a/test/sql/param.sql b/test/sql/param.sql index 454455b9..fa413e58 100644 --- a/test/sql/param.sql +++ b/test/sql/param.sql @@ -41,6 +41,23 @@ CALL clickhouse_perform('param_admin', $$ FROM numbers(1, 110) $$); +CALL clickhouse_perform('param_admin', $$ + CREATE TABLE param_test.typed ( + id Int, + u UUID, + ts DateTime64(3, 'UTC'), + lts DateTime64(3), + d Date32, + f Float64 + ) ENGINE = MergeTree ORDER BY id +$$); + +CALL clickhouse_perform('param_admin', $$ + INSERT INTO param_test.typed VALUES + (1, '188dff2f-0205-4912-8210-2214e84482cd', '2026-09-28 23:59:59.500', '2026-09-28 23:59:59.500', '1960-01-01', 1e-10), + (2, '00000000-0000-0000-0000-000000000002', '2026-09-29 00:00:00.000', '2026-09-29 00:00:00.000', '2026-09-29', 0.5) +$$); + -- =================================================================== -- binary foreign tables -- =================================================================== @@ -135,6 +152,34 @@ ALTER FOREIGN TABLE bin_test.ft1 OPTIONS (SET table_name 'ft1'); EXPLAIN (VERBOSE, COSTS OFF) SELECT c1, c2 FROM bin_test.ft1 WHERE c1 = (SELECT 4); SELECT c1, c2 FROM bin_test.ft1 WHERE c1 = (SELECT 4); +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE bin_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_bin_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM bin_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); +PREPARE st9(timestamptz) AS SELECT id FROM bin_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); +EXECUTE st9('2026-09-28 23:59:59.999999+00'); +EXECUTE st9('2026-09-28 23:59:59.4+00'); +PREPARE st10(timestamp) AS SELECT id FROM bin_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); +EXECUTE st10('2026-09-28 23:59:59.999999'); +PREPARE st11(date) AS SELECT id FROM bin_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); +EXECUTE st11('1960-01-01'); +RESET plan_cache_mode; + -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -143,6 +188,10 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- =================================================================== -- http foreign tables @@ -238,6 +287,34 @@ ALTER FOREIGN TABLE http_test.ft1 OPTIONS (SET table_name 'ft1'); EXPLAIN (VERBOSE, COSTS OFF) SELECT c1, c2 FROM http_test.ft1 WHERE c1 = (SELECT 4); SELECT c1, c2 FROM http_test.ft1 WHERE c1 = (SELECT 4); +-- uuid, sub-second timestamp, pre-1970 date, and float parameters +CREATE FOREIGN TABLE http_test.typed ( + id int NOT NULL, + u uuid, + ts timestamptz, + lts timestamp, + d date, + f float8 +) SERVER param_http_svr OPTIONS( + database 'param_test', + table_name 'typed' +); +SET plan_cache_mode = force_generic_plan; +PREPARE st8(uuid) AS SELECT id FROM http_test.typed WHERE u = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); +EXECUTE st8('188dff2f-0205-4912-8210-2214e84482cd'); +PREPARE st9(timestamptz) AS SELECT id FROM http_test.typed WHERE ts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st9('2026-09-28 23:59:59.999999+00'); +EXECUTE st9('2026-09-28 23:59:59.999999+00'); +EXECUTE st9('2026-09-28 23:59:59.4+00'); +PREPARE st10(timestamp) AS SELECT id FROM http_test.typed WHERE lts <= $1 ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st10('2026-09-28 23:59:59.999999'); +EXECUTE st10('2026-09-28 23:59:59.999999'); +PREPARE st11(date) AS SELECT id FROM http_test.typed WHERE d = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); +EXECUTE st11('1960-01-01'); +RESET plan_cache_mode; + -- cleanup DEALLOCATE st1; DEALLOCATE st2; @@ -246,6 +323,10 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; diff --git a/vendor/pg-clickhouse-c b/vendor/pg-clickhouse-c index f45f0563..9aa10b06 160000 --- a/vendor/pg-clickhouse-c +++ b/vendor/pg-clickhouse-c @@ -1 +1 @@ -Subproject commit f45f05634627c2c0f148700fbe39f948e91efdea +Subproject commit 9aa10b06f061f41c92cbb720239a0bf44ef2a70e From a31c40c4fb3ec063152160bf0b5da23813f9d801 Mon Sep 17 00:00:00 2001 From: serprex <159546+serprex@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:30:19 +0000 Subject: [PATCH 2/5] push down datetime +/- interval params --- CHANGELOG.md | 2 + src/deparse.c | 123 +++++++++++++++++++++++++++++--------- src/pglink.c | 5 ++ test/expected/param.out | 98 ++++++++++++++++++++++++++++++ test/expected/param_1.out | 98 ++++++++++++++++++++++++++++++ test/expected/param_2.out | 98 ++++++++++++++++++++++++++++++ test/sql/param.sql | 22 +++++++ 7 files changed, 417 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6dcd9ed..4e879c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ All notable changes to this project will be documented in this file. It uses the ### ⚡ Improvements * Added pushdown for datetime arithmetic with interval parameters ([#389]). +* Added pushdown for `point` values and coordinate subscripts; geometric + operators and other geometric types execute locally ([#389]). * Added pushdown for more regression aggregate functions on ClickHouse 26.9+: * [regr_avgx] * [regr_avgy] diff --git a/src/deparse.c b/src/deparse.c index 2c36c1bf..e1f55d8e 100644 --- a/src/deparse.c +++ b/src/deparse.c @@ -875,6 +875,20 @@ classify_notin_subplan(SubPlan* subplan, PlannerInfo* root, Relids relids) { return NOTIN_SHIP_NONE; } +/* Datetime +/- interval Param, which deparseIntervalOp splits into parts */ +static bool +is_interval_param_op(OpExpr* oe) { + CustomObjectDef* cdef; + + if (list_length(oe->args) != 2 || !IsA(lsecond(oe->args), Param)) { + return false; + } + + cdef = chfdw_check_for_custom_operator(oe->opno, NULL); + return cdef && (cdef->cf_type == CF_DATETIME_PL_INTERVAL || + cdef->cf_type == CF_DATETIME_MI_INTERVAL); +} + /* * Check if expression is safe to execute remotely, and return true if so. * @@ -927,6 +941,9 @@ foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { if (var->varattno < 0) { return false; } + } else if (var->varlevelsup == 0 && var->vartype == INTERVALOID) { + /* Outer Var becomes a Param deparseIntervalOp cannot split */ + return false; } } break; case T_Const: @@ -950,6 +967,11 @@ foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { if (p->paramkind == PARAM_MULTIEXPR) { return false; } + + /* Only deparseIntervalOp knows how to apply interval params */ + if (p->paramtype == INTERVALOID) { + return false; + } } break; case T_SubscriptingRef: { SubscriptingRef* ar = (SubscriptingRef*)node; @@ -1061,6 +1083,16 @@ foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { return false; } + if (is_interval_param_op(oe)) { + if (((Param*)lsecond(oe->args))->paramkind == PARAM_MULTIEXPR) { + return false; + } + if (!foreign_expr_walker(linitial(oe->args), glob_cxt, EXPR_CTX_EXACT)) { + return false; + } + break; + } + /* * Recurse to input subexpressions. */ @@ -1866,11 +1898,7 @@ ch_format_type_extended(Oid type_oid, int32 typemod, uint16 flags) { break; case INTERVALOID: - if (with_typemod) { - buf = printTypmod("UInt64", typemod, typeform->typmodout); - } else { - buf = pstrdup("UInt64"); - } + buf = pstrdup("UInt64"); break; case TIMEOID: @@ -3523,31 +3551,42 @@ deparseConst(Const* node, deparse_expr_cxt* context, int showtype) { * in that list as the remote parameter number. During EXPLAIN, there's * no need to identify a parameter number. */ -static void -deparseParam(Param* node, deparse_expr_cxt* context) { - /* - * SubPlan scope: a PARAM_EXEC Param here is (usually) a correlation - * reference, the planner's replacement for an outer-query Var inside the - * subquery (SS_replace_correlation_vars). subplan->parParam and - * subplan->args run in parallel: paramid -> the outer expression that - * feeds it. Inline that expression, deparsed in the PARENT scope so it - * picks up the outer query's aliases. - */ - if (context->subplan != NULL && node->paramkind == PARAM_EXEC) { - ListCell* pp; - ListCell* ap; +/* + * SubPlan scope: a PARAM_EXEC Param here is (usually) a correlation + * reference, the planner's replacement for an outer-query Var inside the + * subquery (SS_replace_correlation_vars). subplan->parParam and + * subplan->args run in parallel: paramid -> the outer expression that + * feeds it. Return that expression, or NULL if not a correlation param. + */ +static Expr* +correlation_arg(Param* node, deparse_expr_cxt* context) { + ListCell* pp; + ListCell* ap; - Assert(context->parent_ctx != NULL); + if (context->subplan == NULL || node->paramkind != PARAM_EXEC) { + return NULL; + } - forboth(pp, context->subplan->parParam, ap, context->subplan->args) { - if (lfirst_int(pp) == node->paramid) { - appendStringInfoChar(context->buf, '('); - deparseExpr((Expr*)lfirst(ap), context->parent_ctx); - appendStringInfoChar(context->buf, ')'); - return; - } + Assert(context->parent_ctx != NULL); + + forboth(pp, context->subplan->parParam, ap, context->subplan->args) { + if (lfirst_int(pp) == node->paramid) { + return (Expr*)lfirst(ap); } - /* Not a correlation param; fall through to normal handling. */ + } + return NULL; +} + +static void +deparseParam(Param* node, deparse_expr_cxt* context) { + Expr* outer = correlation_arg(node, context); + + /* Deparse in PARENT scope to pick up outer query's aliases */ + if (outer) { + appendStringInfoChar(context->buf, '('); + deparseExpr(outer, context->parent_ctx); + appendStringInfoChar(context->buf, ')'); + return; } if (context->params_list) { @@ -3573,6 +3612,15 @@ deparseParam(Param* node, deparse_expr_cxt* context) { } } +/* Interval matches chfdw_datum_to_ch_literal's (month, day, microsecond) */ +static char* +remote_param_type_name(Oid paramtype, int32 paramtypmod) { + if (paramtype == INTERVALOID) { + return pstrdup("Tuple(Int32, Int32, Int64)"); + } + return deparse_type_name(paramtype, paramtypmod); +} + /* * Print the representation of a parameter to be sent to the remote side * by param number and remote data type. @@ -3585,7 +3633,7 @@ printRemoteParam( deparse_expr_cxt* context ) { StringInfo buf = context->buf; - char* ptypename = deparse_type_name(paramtype, paramtypmod); + char* ptypename = remote_param_type_name(paramtype, paramtypmod); appendStringInfo(buf, "{p%d:%s}", paramindex, ptypename); } @@ -3606,7 +3654,7 @@ printRemoteParam( static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt* context) { StringInfo buf = context->buf; - char* ptypename = deparse_type_name(paramtype, paramtypmod); + char* ptypename = remote_param_type_name(paramtype, paramtypmod); appendStringInfo(buf, "((SELECT CAST(null AS Nullable(%s))", ptypename); } @@ -4882,6 +4930,23 @@ deparseIntervalOp(Node* first, Node* second, deparse_expr_cxt* context, bool plu */ bool widen = span && span->time % USECS_PER_SEC != 0; + if (IsA(second, Param) && !correlation_arg((Param*)second, context)) { + static const char* const units[] = { "Month", "Day", "Microsecond" }; + + appendStringInfoString(buf, "(toDateTime64("); + deparseExpr((Expr*)first, context); + appendStringInfoString(buf, ", 6)"); + for (size_t i = 0; i < lengthof(units); i++) { + appendStringInfo( + buf, " %c toInterval%s(tupleElement(", plus ? '+' : '-', units[i] + ); + deparseExpr((Expr*)second, context); + appendStringInfo(buf, ", %zu))", i + 1); + } + appendStringInfoChar(buf, ')'); + return; + } + appendStringInfoString(buf, widen ? "(toDateTime64(" : "("); deparseExpr((Expr*)first, context); if (widen) { diff --git a/src/pglink.c b/src/pglink.c index 0713ebe0..7b9a4b2c 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -495,6 +495,11 @@ chfdw_datum_to_ch_literal(Datum value, Oid type) { chfdw_encode_timestamp(DatumGetTimestamp(value), ts); return pstrdup(ts); } + case INTERVALOID: { + Interval* span = DatumGetIntervalP(value); + + return psprintf("(%d,%d," INT64_FORMAT ")", span->month, span->day, span->time); + } default: ereport( ERROR, diff --git a/test/expected/param.out b/test/expected/param.out index 1ae74c45..7f822f00 100644 --- a/test/expected/param.out +++ b/test/expected/param.out @@ -411,6 +411,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM bin_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM bin_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -424,6 +471,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- =================================================================== -- http foreign tables -- =================================================================== @@ -784,6 +833,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM http_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM http_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -797,6 +893,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/expected/param_1.out b/test/expected/param_1.out index cb3082e0..3a679538 100644 --- a/test/expected/param_1.out +++ b/test/expected/param_1.out @@ -411,6 +411,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM bin_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM bin_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -424,6 +471,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- =================================================================== -- http foreign tables -- =================================================================== @@ -784,6 +833,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM http_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM http_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -797,6 +893,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/expected/param_2.out b/test/expected/param_2.out index 74ed1dbe..a050d43c 100644 --- a/test/expected/param_2.out +++ b/test/expected/param_2.out @@ -411,6 +411,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM bin_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM bin_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -424,6 +471,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- =================================================================== -- http foreign tables -- =================================================================== @@ -784,6 +833,53 @@ EXECUTE st11('1960-01-01'); 1 (1 row) +PREPARE st12(interval) AS SELECT id FROM http_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(ts, 6) + toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) + toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) + toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) >= cast('2026-10-29 00:00:00' as DateTime64(6, 'UTC')))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st12('1 month 0.5 seconds'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st12('1 month'); + id +---- + 2 +(1 row) + +PREPARE st13(interval) AS SELECT id FROM http_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE (((toDateTime64(d, 6) - toIntervalMonth(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 1)) - toIntervalDay(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 2)) - toIntervalMicrosecond(tupleElement({p1:Tuple(Int32, Int32, Int64)}, 3))) < '1959-12-31 00:00:00')) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE st13('1 day 1 microsecond'); + id +---- + 1 +(1 row) + +EXECUTE st13('1 day'); + id +---- +(0 rows) + +EXECUTE st13('-1 year'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -797,6 +893,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/sql/param.sql b/test/sql/param.sql index fa413e58..c0633af6 100644 --- a/test/sql/param.sql +++ b/test/sql/param.sql @@ -178,6 +178,15 @@ EXECUTE st10('2026-09-28 23:59:59.999999'); PREPARE st11(date) AS SELECT id FROM bin_test.typed WHERE d = $1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); EXECUTE st11('1960-01-01'); +PREPARE st12(interval) AS SELECT id FROM bin_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); +EXECUTE st12('1 month 0.5 seconds'); +EXECUTE st12('1 month'); +PREPARE st13(interval) AS SELECT id FROM bin_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); +EXECUTE st13('1 day 1 microsecond'); +EXECUTE st13('1 day'); +EXECUTE st13('-1 year'); RESET plan_cache_mode; -- cleanup @@ -192,6 +201,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- =================================================================== -- http foreign tables @@ -313,6 +324,15 @@ EXECUTE st10('2026-09-28 23:59:59.999999'); PREPARE st11(date) AS SELECT id FROM http_test.typed WHERE d = $1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st11('1960-01-01'); EXECUTE st11('1960-01-01'); +PREPARE st12(interval) AS SELECT id FROM http_test.typed WHERE ts + $1 >= '2026-10-29 00:00:00+00' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st12('1 month 0.5 seconds'); +EXECUTE st12('1 month 0.5 seconds'); +EXECUTE st12('1 month'); +PREPARE st13(interval) AS SELECT id FROM http_test.typed WHERE d - $1 < '1959-12-31' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); +EXECUTE st13('1 day 1 microsecond'); +EXECUTE st13('1 day'); +EXECUTE st13('-1 year'); RESET plan_cache_mode; -- cleanup @@ -327,6 +347,8 @@ DEALLOCATE st8; DEALLOCATE st9; DEALLOCATE st10; DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; From 117d8b99c11065ea380f6824fa5d7d02bc46b735 Mon Sep 17 00:00:00 2001 From: serprex <159546+serprex@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:30:19 +0000 Subject: [PATCH 3/5] render float params as shortest round-trip literals --- CHANGELOG.md | 2 + src/deparse.c | 23 ++++++++++ src/include/fdw.h | 2 + src/pglink.c | 9 +++- test/expected/param.out | 96 +++++++++++++++++++++++++++++++++++++++ test/expected/param_1.out | 96 +++++++++++++++++++++++++++++++++++++++ test/expected/param_2.out | 96 +++++++++++++++++++++++++++++++++++++++ test/sql/param.sql | 22 +++++++++ 8 files changed, 344 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e879c2f..525effff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ All notable changes to this project will be documented in this file. It uses the * Fixed ClickHouse type mappings for temporal, UUID, and JSON casts and parameters, preserving timestamp precision and UTC semantics ([#389]). +* Fixed floating-point parameter precision loss by using shortest round-trip + literals ([#389]). * Fixed GCC 15 build failure caused by a `-Wclobbered` error in binary driver connection setup ([#395]). diff --git a/src/deparse.c b/src/deparse.c index e1f55d8e..cbc1dd51 100644 --- a/src/deparse.c +++ b/src/deparse.c @@ -24,6 +24,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#include "common/shortest_dec.h" #include "fmgr.h" #include "lib/stringinfo.h" #include "miscadmin.h" @@ -50,6 +51,8 @@ #include "fdw.h" #include "pg-clickhouse-encode.h" +#include + /* Aggregate OIDs absent from fmgroids.h on all PG versions. */ #define F_STRING_AGG_TEXT_TEXT 3538 @@ -3206,6 +3209,26 @@ deparseByteaLiteral(StringInfo buf, Datum value) { appendStringInfoChar(buf, '\''); } +/* + * Append shortest decimal text that reads back as original float value + * Ignore extra_float_digits; use forms ClickHouse accepts as Float64 + */ +void +chfdw_append_float_literal(StringInfo buf, double v) { + char num[DOUBLE_SHORTEST_DECIMAL_LEN]; + + if (isnan(v)) { + appendStringInfoString(buf, "nan"); + } else if (isinf(v)) { + appendStringInfoString(buf, v < 0 ? "-inf" : "inf"); + } else if (v == 0 && signbit(v)) { + appendStringInfoString(buf, "-0."); + } else { + double_to_shortest_decimal_buf(v, num); + appendStringInfoString(buf, num); + } +} + static void emitArrayElement( StringInfo buf, diff --git a/src/include/fdw.h b/src/include/fdw.h index d26da879..c50aa5d0 100644 --- a/src/include/fdw.h +++ b/src/include/fdw.h @@ -331,6 +331,8 @@ extern const char* chfdw_get_jointype_name(JoinType jointype); char* chfdw_array_to_ch_literal(Datum arr); +void +chfdw_append_float_literal(StringInfo buf, double v); /* chfdw_is_equal_op's classification of a comparison operator's name. */ typedef enum CHEqualOp { diff --git a/src/pglink.c b/src/pglink.c index 7b9a4b2c..a89cfcef 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -425,10 +425,13 @@ http_native_cursor(void* conn, const ch_query* query) { */ extern char* chfdw_datum_to_ch_literal(Datum value, Oid type) { + StringInfoData buf; + if (type_is_array(type)) { return chfdw_array_to_ch_literal(value); } + initStringInfo(&buf); switch (type) { case BOOLOID: case INT2OID: @@ -437,9 +440,11 @@ chfdw_datum_to_ch_literal(Datum value, Oid type) { case INT8OID: return psprintf(INT64_FORMAT, DatumGetInt64(value)); case FLOAT4OID: - return psprintf("%f", DatumGetFloat4(value)); + chfdw_append_float_literal(&buf, DatumGetFloat4(value)); + return buf.data; case FLOAT8OID: - return psprintf("%f", DatumGetFloat8(value)); + chfdw_append_float_literal(&buf, DatumGetFloat8(value)); + return buf.data; case NUMERICOID: return DatumGetCString(DirectFunctionCall1(numeric_out, value)); case BPCHAROID: diff --git a/test/expected/param.out b/test/expected/param.out index 7f822f00..aadd3c9f 100644 --- a/test/expected/param.out +++ b/test/expected/param.out @@ -458,6 +458,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM bin_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM bin_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -473,6 +519,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -880,6 +928,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM http_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM http_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -895,6 +989,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/expected/param_1.out b/test/expected/param_1.out index 3a679538..39a77d95 100644 --- a/test/expected/param_1.out +++ b/test/expected/param_1.out @@ -458,6 +458,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM bin_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM bin_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -473,6 +519,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -880,6 +928,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM http_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM http_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -895,6 +989,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/expected/param_2.out b/test/expected/param_2.out index a050d43c..a9a222d3 100644 --- a/test/expected/param_2.out +++ b/test/expected/param_2.out @@ -458,6 +458,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM bin_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on bin_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM bin_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -473,6 +519,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -880,6 +928,52 @@ EXECUTE st13('-1 year'); ---- (0 rows) +PREPARE st14(float8) AS SELECT id FROM http_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); + QUERY PLAN +-------------------------------------------------------------------------- + Foreign Scan on http_test.typed + Output: id + Remote SQL: SELECT id FROM param_test.typed WHERE ((f = {p1:Float64})) +(3 rows) + +EXECUTE st14(1e-10); + id +---- + 1 +(1 row) + +PREPARE st15(float8) AS SELECT id FROM http_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15('-0'); + id +---- + 1 + 2 +(2 rows) + +EXECUTE st15(0.25); + id +---- + 2 +(1 row) + +EXECUTE st15('Infinity'); + id +---- +(0 rows) + +EXECUTE st15('NaN'); + id +---- +(0 rows) + RESET plan_cache_mode; -- cleanup DEALLOCATE st1; @@ -895,6 +989,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; DROP SERVER param_bin_svr CASCADE; diff --git a/test/sql/param.sql b/test/sql/param.sql index c0633af6..5b9798e6 100644 --- a/test/sql/param.sql +++ b/test/sql/param.sql @@ -187,6 +187,15 @@ EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); EXECUTE st13('1 day 1 microsecond'); EXECUTE st13('1 day'); EXECUTE st13('-1 year'); +PREPARE st14(float8) AS SELECT id FROM bin_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); +EXECUTE st14(1e-10); +PREPARE st15(float8) AS SELECT id FROM bin_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); +EXECUTE st15('-0'); +EXECUTE st15(0.25); +EXECUTE st15('Infinity'); +EXECUTE st15('NaN'); RESET plan_cache_mode; -- cleanup @@ -203,6 +212,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables @@ -333,6 +344,15 @@ EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st13('1 day 1 microsecond'); EXECUTE st13('1 day 1 microsecond'); EXECUTE st13('1 day'); EXECUTE st13('-1 year'); +PREPARE st14(float8) AS SELECT id FROM http_test.typed WHERE f = $1; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st14(1e-10); +EXECUTE st14(1e-10); +PREPARE st15(float8) AS SELECT id FROM http_test.typed WHERE f > $1 ORDER BY id; +EXECUTE st15('-Infinity'); +EXECUTE st15('-0'); +EXECUTE st15(0.25); +EXECUTE st15('Infinity'); +EXECUTE st15('NaN'); RESET plan_cache_mode; -- cleanup @@ -349,6 +369,8 @@ DEALLOCATE st10; DEALLOCATE st11; DEALLOCATE st12; DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; From 3f544639e144be8c63cb95b6b45564d131e86e3a Mon Sep 17 00:00:00 2001 From: serprex <159546+serprex@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:30:19 +0000 Subject: [PATCH 4/5] push down point values, keep other geometry local --- src/deparse.c | 78 ++++++++- src/include/fdw.h | 4 + src/pglink.c | 3 + src/shipable.c | 43 +++++ test/expected/geometry.out | 350 +++++++++++++++++++++++++++++++++++++ test/sql/geometry.sql | 132 ++++++++++++++ 6 files changed, 608 insertions(+), 2 deletions(-) create mode 100644 test/expected/geometry.out create mode 100644 test/sql/geometry.sql diff --git a/src/deparse.c b/src/deparse.c index cbc1dd51..b97d403d 100644 --- a/src/deparse.c +++ b/src/deparse.c @@ -43,6 +43,7 @@ #include "utils/date.h" #include "utils/datetime.h" #include "utils/fmgroids.h" +#include "utils/geo_decls.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -908,6 +909,34 @@ is_interval_param_op(OpExpr* oe) { * EXPR_CTX_TRUTH only while every enclosing node treats NULL and FALSE * identically. */ +/* + * Return 1-based ClickHouse tuple index for point[0] or point[1], else 0. + * PostgreSQL returns NULL for other indexes, where tupleElement fails + */ +static int +point_subscript_index(SubscriptingRef* ar) { + Const* c; + + if (ar->refcontainertype != POINTOID || ar->reflowerindexpr != NIL || + list_length(ar->refupperindexpr) != 1) { + return 0; + } + + c = (Const*)linitial(ar->refupperindexpr); + if (!IsA(c, Const) || c->consttype != INT4OID || c->constisnull) { + return 0; + } + + switch (DatumGetInt32(c->constvalue)) { + case 0: + return 1; + case 1: + return 2; + default: + return 0; + } +} + static bool foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { bool check_type = true; @@ -984,7 +1013,7 @@ foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { return false; } - if (!type_is_array(ar->refcontainertype)) { + if (!type_is_array(ar->refcontainertype) && point_subscript_index(ar) == 0) { return false; } @@ -1347,6 +1376,12 @@ foreign_expr_walker(Node* node, foreign_glob_cxt* glob_cxt, ExprTruthCtx ctx) { case T_CoerceViaIO: { CoerceViaIO* me = (CoerceViaIO*)node; + /* ClickHouse text forms of geometric types differ from PostgreSQL's */ + if (chfdw_is_geometric_type(me->resulttype) || + chfdw_is_geometric_type(exprType((Node*)me->arg))) { + return false; + } + if (!foreign_expr_walker((Node*)me->arg, glob_cxt, EXPR_CTX_EXACT)) { return false; } @@ -1911,6 +1946,11 @@ ch_format_type_extended(Oid type_oid, int32 typemod, uint16 flags) { case UUIDOID: case JSONOID: case JSONBOID: + case POINTOID: + case POLYGONOID: + case BOXOID: + case CIRCLEOID: + case LINEOID: buf = pgch_ch_type_for(type_oid, with_typemod ? typemod : -1, true, NULL); break; @@ -1924,6 +1964,12 @@ ch_format_type_extended(Oid type_oid, int32 typemod, uint16 flags) { case TEXTOID: buf = pstrdup("String"); break; + + /* pg-clickhouse-c reads back LineString as path, but CH < 24.6 lacks it */ + case PATHOID: + case LSEGOID: + buf = pstrdup("Array(Point)"); + break; } if (buf == NULL) { @@ -3229,6 +3275,18 @@ chfdw_append_float_literal(StringInfo buf, double v) { } } +/* Shippability admits only point among geometric types */ +void +chfdw_append_point_literal(StringInfo buf, Datum val) { + Point* p = DatumGetPointP(val); + + appendStringInfoChar(buf, '('); + chfdw_append_float_literal(buf, p->x); + appendStringInfoChar(buf, ','); + chfdw_append_float_literal(buf, p->y); + appendStringInfoChar(buf, ')'); +} + static void emitArrayElement( StringInfo buf, @@ -3472,6 +3530,11 @@ deparseConst(Const* node, deparse_expr_cxt* context, int showtype) { showtype = 1; } + /* Bare tuple of integers is no geometry type for ClickHouse functions */ + if (showtype == 0 && chfdw_is_geometric_type(node->consttype)) { + showtype = 1; + } + if (showtype > 0) { appendStringInfoString(buf, "cast("); } @@ -3511,6 +3574,9 @@ deparseConst(Const* node, deparse_expr_cxt* context, int showtype) { } else if (node->consttype == BYTEAOID) { deparseByteaLiteral(buf, node->constvalue); goto cleanup; + } else if (node->consttype == POINTOID) { + chfdw_append_point_literal(buf, node->constvalue); + goto cleanup; } else if (deparseStringDatum(buf, node->constvalue, typoutput)) { goto cleanup; } else { @@ -3974,7 +4040,15 @@ deparseGuardedNotIn(SubPlan* subplan, deparse_expr_cxt* context) { */ static void deparseSubscriptingRef(SubscriptingRef* node, deparse_expr_cxt* context) { - StringInfo buf = context->buf; + StringInfo buf = context->buf; + int point_index = point_subscript_index(node); + + if (point_index != 0) { + appendStringInfoString(buf, "tupleElement("); + deparseExpr(node->refexpr, context); + appendStringInfo(buf, ", %d)", point_index); + return; + } if (node->reflowerindexpr != NIL) { /* diff --git a/src/include/fdw.h b/src/include/fdw.h index c50aa5d0..7d79245f 100644 --- a/src/include/fdw.h +++ b/src/include/fdw.h @@ -333,6 +333,8 @@ char* chfdw_array_to_ch_literal(Datum arr); void chfdw_append_float_literal(StringInfo buf, double v); +void +chfdw_append_point_literal(StringInfo buf, Datum val); /* chfdw_is_equal_op's classification of a comparison operator's name. */ typedef enum CHEqualOp { @@ -347,6 +349,8 @@ chfdw_is_equal_op(Oid opno); /* in shippable.c */ extern bool chfdw_is_builtin(Oid objectId); +extern bool +chfdw_is_geometric_type(Oid type_oid); /* * Connection cache hash table entry diff --git a/src/pglink.c b/src/pglink.c index a89cfcef..511867f4 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -433,6 +433,9 @@ chfdw_datum_to_ch_literal(Datum value, Oid type) { initStringInfo(&buf); switch (type) { + case POINTOID: + chfdw_append_point_literal(&buf, value); + return buf.data; case BOOLOID: case INT2OID: case INT4OID: diff --git a/src/shipable.c b/src/shipable.c index 5e3a46e2..a5c6073c 100644 --- a/src/shipable.c +++ b/src/shipable.c @@ -25,6 +25,7 @@ #include "utils/builtins.h" #include "utils/hsearch.h" #include "utils/inval.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" /* Hash table for caching the results of shippability lookups */ @@ -144,6 +145,38 @@ chfdw_is_builtin(Oid objectId) { return (objectId < FirstUnpinnedObjectId); } +bool +chfdw_is_geometric_type(Oid type_oid) { + Oid elem_oid = get_element_type(type_oid); + + switch (OidIsValid(elem_oid) ? elem_oid : type_oid) { + case POINTOID: + case LSEGOID: + case PATHOID: + case BOXOID: + case POLYGONOID: + case LINEOID: + case CIRCLEOID: + return true; + default: + return false; + } +} + +/* + * PostgreSQL geometric operators use fuzzy comparisons and algorithms + * ClickHouse does not share, so expressions on these types must run locally + */ +static bool +is_geometric_operator(Oid opno) { + Oid left; + Oid right; + + op_input_types(opno, &left, &right); + return chfdw_is_geometric_type(left) || chfdw_is_geometric_type(right) || + chfdw_is_geometric_type(get_op_rettype(opno)); +} + static bool regex_flags_ok(Datum value, bool global_ok) { text* t = DatumGetTextPP(value); @@ -406,6 +439,16 @@ chfdw_is_shippable( * dropping the implicit wrapper, regardless of the underlying funcid. */ if (chfdw_is_builtin(objectId)) { + /* + * Empty Ring and LineString read back as NULL polygon and path, so + * only point values ship + */ + if (classId == TypeRelationId) { + return objectId == POINTOID || !chfdw_is_geometric_type(objectId); + } + if (classId == OperatorRelationId) { + return !is_geometric_operator(objectId); + } if (classId != ProcedureRelationId) { return true; } diff --git a/test/expected/geometry.out b/test/expected/geometry.out new file mode 100644 index 00000000..ab719563 --- /dev/null +++ b/test/expected/geometry.out @@ -0,0 +1,350 @@ +SET datestyle = 'ISO'; +CREATE SERVER geo_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(driver 'binary'); +CREATE USER MAPPING FOR CURRENT_USER SERVER geo_bin_svr; +CREATE SERVER geo_http_svr FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER geo_http_svr; +CALL clickhouse_perform('geo_http_svr', 'DROP DATABASE IF EXISTS geo_test'); +CALL clickhouse_perform('geo_http_svr', 'CREATE DATABASE geo_test'); +CALL clickhouse_perform('geo_http_svr', $$ + CREATE TABLE geo_test.shapes ( + id Int32, + p Point, + r Ring + ) ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('geo_http_svr', $$ + INSERT INTO geo_test.shapes VALUES + (1, (1.5, 2), [(0, 0), (1, 0), (1, 1)]), + (2, (-0., 1e-7), []), + (3, (inf, -3), [(2, 2)]) +$$); +-- =================================================================== +-- binary +-- =================================================================== +CREATE SCHEMA geo_bin; +CREATE FOREIGN TABLE geo_bin.shapes (id int, p point, r polygon) + SERVER geo_bin_svr OPTIONS (database 'geo_test', table_name 'shapes'); +SELECT id, p, r FROM geo_bin.shapes ORDER BY id; + id | p | r +----+---------------+--------------------- + 1 | (1.5,2) | ((0,0),(1,0),(1,1)) + 2 | (-0,1e-07) | + 3 | (Infinity,-3) | ((2,2)) +(3 rows) + +-- point subscripts push down as tupleElement +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, p[0], p[1] FROM geo_bin.shapes WHERE p[0] > 1 ORDER BY id; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id, p[0], p[1] + Remote SQL: SELECT id, p FROM geo_test.shapes WHERE ((tupleElement(p, 1) > 1)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id, p[0], p[1] FROM geo_bin.shapes WHERE p[0] > 1 ORDER BY id; + id | p | p +----+----------+---- + 1 | 1.5 | 2 + 3 | Infinity | -3 +(2 rows) + +-- out of range subscript is NULL, evaluated locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p[2] IS NULL ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id + Filter: (shapes.p[2] IS NULL) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_bin.shapes WHERE p[2] IS NULL ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +-- point literal +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Foreign Scan on geo_bin.shapes + Output: id + Remote SQL: SELECT id FROM geo_test.shapes WHERE ((tupleElement(CASE WHEN (id = 1) THEN p ELSE cast((-0.5,1e+300) as Point) END, 2) > 2)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id FROM geo_bin.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + id +---- + 2 + 3 +(2 rows) + +-- point parameter +SET plan_cache_mode = force_generic_plan; +PREPARE geo1(point) AS SELECT id FROM geo_bin.shapes WHERE p[0] = $1[0] ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE geo1('(1.5,7)'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ + Foreign Scan on geo_bin.shapes + Output: id + Remote SQL: SELECT id FROM geo_test.shapes WHERE ((tupleElement(p, 1) = tupleElement({p1:Point}, 1))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE geo1('(1.5,7)'); + id +---- + 1 +(1 row) + +EXECUTE geo1('(Infinity,0)'); + id +---- + 3 +(1 row) + +DEALLOCATE geo1; +RESET plan_cache_mode; +-- geometric operators, casts and NULL tests on polygon run locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id + Filter: (shapes.p ~= '(1.5000001,2)'::point) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_bin.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; + id +---- + 1 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p::text = '(1.5,2)' ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id + Filter: ((shapes.p)::text = '(1.5,2)'::text) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_bin.shapes WHERE p::text = '(1.5,2)' ORDER BY id; + id +---- + 1 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE r IS NULL ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id + Filter: (shapes.r IS NULL) + Remote SQL: SELECT id, r FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_bin.shapes WHERE r IS NULL ORDER BY id; + id +---- + 2 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE npoints(r) = 1 ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_bin.shapes + Output: id + Filter: (npoints(shapes.r) = 1) + Remote SQL: SELECT id, r FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_bin.shapes WHERE npoints(r) = 1 ORDER BY id; + id +---- + 3 +(1 row) + +-- =================================================================== +-- http +-- =================================================================== +CREATE SCHEMA geo_http; +CREATE FOREIGN TABLE geo_http.shapes (id int, p point, r polygon) + SERVER geo_http_svr OPTIONS (database 'geo_test', table_name 'shapes'); +SELECT id, p, r FROM geo_http.shapes ORDER BY id; + id | p | r +----+---------------+--------------------- + 1 | (1.5,2) | ((0,0),(1,0),(1,1)) + 2 | (-0,1e-07) | + 3 | (Infinity,-3) | ((2,2)) +(3 rows) + +-- point subscripts push down as tupleElement +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, p[0], p[1] FROM geo_http.shapes WHERE p[0] > 1 ORDER BY id; + QUERY PLAN +------------------------------------------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id, p[0], p[1] + Remote SQL: SELECT id, p FROM geo_test.shapes WHERE ((tupleElement(p, 1) > 1)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id, p[0], p[1] FROM geo_http.shapes WHERE p[0] > 1 ORDER BY id; + id | p | p +----+----------+---- + 1 | 1.5 | 2 + 3 | Infinity | -3 +(2 rows) + +-- out of range subscript is NULL, evaluated locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p[2] IS NULL ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id + Filter: (shapes.p[2] IS NULL) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_http.shapes WHERE p[2] IS NULL ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +-- point literal +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Foreign Scan on geo_http.shapes + Output: id + Remote SQL: SELECT id FROM geo_test.shapes WHERE ((tupleElement(CASE WHEN (id = 1) THEN p ELSE cast((-0.5,1e+300) as Point) END, 2) > 2)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id FROM geo_http.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + id +---- + 2 + 3 +(2 rows) + +-- point parameter +SET plan_cache_mode = force_generic_plan; +PREPARE geo1(point) AS SELECT id FROM geo_http.shapes WHERE p[0] = $1[0] ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE geo1('(1.5,7)'); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ + Foreign Scan on geo_http.shapes + Output: id + Remote SQL: SELECT id FROM geo_test.shapes WHERE ((tupleElement(p, 1) = tupleElement({p1:Point}, 1))) ORDER BY id ASC NULLS LAST +(3 rows) + +EXECUTE geo1('(1.5,7)'); + id +---- + 1 +(1 row) + +EXECUTE geo1('(Infinity,0)'); + id +---- + 3 +(1 row) + +DEALLOCATE geo1; +RESET plan_cache_mode; +-- geometric operators, casts and NULL tests on polygon run locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id + Filter: (shapes.p ~= '(1.5000001,2)'::point) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_http.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; + id +---- + 1 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p::text = '(1.5,2)' ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id + Filter: ((shapes.p)::text = '(1.5,2)'::text) + Remote SQL: SELECT id, p FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_http.shapes WHERE p::text = '(1.5,2)' ORDER BY id; + id +---- + 1 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE r IS NULL ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id + Filter: (shapes.r IS NULL) + Remote SQL: SELECT id, r FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_http.shapes WHERE r IS NULL ORDER BY id; + id +---- + 2 +(1 row) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE npoints(r) = 1 ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------- + Foreign Scan on geo_http.shapes + Output: id + Filter: (npoints(shapes.r) = 1) + Remote SQL: SELECT id, r FROM geo_test.shapes ORDER BY id ASC NULLS LAST +(4 rows) + +SELECT id FROM geo_http.shapes WHERE npoints(r) = 1 ORDER BY id; + id +---- + 3 +(1 row) + +-- Clean up. +CALL clickhouse_perform('geo_http_svr', 'DROP DATABASE geo_test'); +DROP SCHEMA geo_bin CASCADE; +NOTICE: drop cascades to foreign table geo_bin.shapes +DROP SCHEMA geo_http CASCADE; +NOTICE: drop cascades to foreign table geo_http.shapes +DROP USER MAPPING FOR CURRENT_USER SERVER geo_bin_svr; +DROP SERVER geo_bin_svr CASCADE; +DROP USER MAPPING FOR CURRENT_USER SERVER geo_http_svr; +DROP SERVER geo_http_svr CASCADE; diff --git a/test/sql/geometry.sql b/test/sql/geometry.sql new file mode 100644 index 00000000..e90bb6a8 --- /dev/null +++ b/test/sql/geometry.sql @@ -0,0 +1,132 @@ +SET datestyle = 'ISO'; +CREATE SERVER geo_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(driver 'binary'); +CREATE USER MAPPING FOR CURRENT_USER SERVER geo_bin_svr; + +CREATE SERVER geo_http_svr FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER geo_http_svr; + +CALL clickhouse_perform('geo_http_svr', 'DROP DATABASE IF EXISTS geo_test'); +CALL clickhouse_perform('geo_http_svr', 'CREATE DATABASE geo_test'); +CALL clickhouse_perform('geo_http_svr', $$ + CREATE TABLE geo_test.shapes ( + id Int32, + p Point, + r Ring + ) ENGINE = MergeTree ORDER BY id +$$); + +CALL clickhouse_perform('geo_http_svr', $$ + INSERT INTO geo_test.shapes VALUES + (1, (1.5, 2), [(0, 0), (1, 0), (1, 1)]), + (2, (-0., 1e-7), []), + (3, (inf, -3), [(2, 2)]) +$$); + +-- =================================================================== +-- binary +-- =================================================================== +CREATE SCHEMA geo_bin; +CREATE FOREIGN TABLE geo_bin.shapes (id int, p point, r polygon) + SERVER geo_bin_svr OPTIONS (database 'geo_test', table_name 'shapes'); + +SELECT id, p, r FROM geo_bin.shapes ORDER BY id; + +-- point subscripts push down as tupleElement +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, p[0], p[1] FROM geo_bin.shapes WHERE p[0] > 1 ORDER BY id; +SELECT id, p[0], p[1] FROM geo_bin.shapes WHERE p[0] > 1 ORDER BY id; + +-- out of range subscript is NULL, evaluated locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p[2] IS NULL ORDER BY id; +SELECT id FROM geo_bin.shapes WHERE p[2] IS NULL ORDER BY id; + +-- point literal +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; +SELECT id FROM geo_bin.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + +-- point parameter +SET plan_cache_mode = force_generic_plan; +PREPARE geo1(point) AS SELECT id FROM geo_bin.shapes WHERE p[0] = $1[0] ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE geo1('(1.5,7)'); +EXECUTE geo1('(1.5,7)'); +EXECUTE geo1('(Infinity,0)'); +DEALLOCATE geo1; +RESET plan_cache_mode; + +-- geometric operators, casts and NULL tests on polygon run locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; +SELECT id FROM geo_bin.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE p::text = '(1.5,2)' ORDER BY id; +SELECT id FROM geo_bin.shapes WHERE p::text = '(1.5,2)' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE r IS NULL ORDER BY id; +SELECT id FROM geo_bin.shapes WHERE r IS NULL ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_bin.shapes WHERE npoints(r) = 1 ORDER BY id; +SELECT id FROM geo_bin.shapes WHERE npoints(r) = 1 ORDER BY id; + +-- =================================================================== +-- http +-- =================================================================== +CREATE SCHEMA geo_http; +CREATE FOREIGN TABLE geo_http.shapes (id int, p point, r polygon) + SERVER geo_http_svr OPTIONS (database 'geo_test', table_name 'shapes'); + +SELECT id, p, r FROM geo_http.shapes ORDER BY id; + +-- point subscripts push down as tupleElement +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, p[0], p[1] FROM geo_http.shapes WHERE p[0] > 1 ORDER BY id; +SELECT id, p[0], p[1] FROM geo_http.shapes WHERE p[0] > 1 ORDER BY id; + +-- out of range subscript is NULL, evaluated locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p[2] IS NULL ORDER BY id; +SELECT id FROM geo_http.shapes WHERE p[2] IS NULL ORDER BY id; + +-- point literal +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; +SELECT id FROM geo_http.shapes + WHERE (CASE WHEN id = 1 THEN p ELSE point '(-0.5,1e300)' END)[1] > 2 ORDER BY id; + +-- point parameter +SET plan_cache_mode = force_generic_plan; +PREPARE geo1(point) AS SELECT id FROM geo_http.shapes WHERE p[0] = $1[0] ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) EXECUTE geo1('(1.5,7)'); +EXECUTE geo1('(1.5,7)'); +EXECUTE geo1('(Infinity,0)'); +DEALLOCATE geo1; +RESET plan_cache_mode; + +-- geometric operators, casts and NULL tests on polygon run locally +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; +SELECT id FROM geo_http.shapes WHERE p ~= point '(1.5000001,2)' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE p::text = '(1.5,2)' ORDER BY id; +SELECT id FROM geo_http.shapes WHERE p::text = '(1.5,2)' ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE r IS NULL ORDER BY id; +SELECT id FROM geo_http.shapes WHERE r IS NULL ORDER BY id; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM geo_http.shapes WHERE npoints(r) = 1 ORDER BY id; +SELECT id FROM geo_http.shapes WHERE npoints(r) = 1 ORDER BY id; + +-- Clean up. +CALL clickhouse_perform('geo_http_svr', 'DROP DATABASE geo_test'); +DROP SCHEMA geo_bin CASCADE; +DROP SCHEMA geo_http CASCADE; +DROP USER MAPPING FOR CURRENT_USER SERVER geo_bin_svr; +DROP SERVER geo_bin_svr CASCADE; +DROP USER MAPPING FOR CURRENT_USER SERVER geo_http_svr; +DROP SERVER geo_http_svr CASCADE; From 4bc093a91e024547e26fa755170068ca1c13a6dc Mon Sep 17 00:00:00 2001 From: serprex <159546+serprex@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:30:20 +0000 Subject: [PATCH 5/5] map ::numeric to Nullable(Decimal(76, 38)) --- CHANGELOG.md | 4 +++ src/deparse.c | 19 +++++----- test/expected/aggregates.out | 48 ++++++++++++------------- test/expected/aggregates_1.out | 48 ++++++++++++------------- test/expected/aggregates_2.out | 48 ++++++++++++------------- test/expected/aggregates_3.out | 48 ++++++++++++------------- test/expected/aggregates_4.out | 54 ++++++++++++++++------------ test/expected/aggregates_5.out | 54 ++++++++++++++++------------ test/expected/functions.out | 24 ++++++------- test/expected/functions_0.out | 48 ++++++++++++++----------- test/expected/functions_1.out | 24 ++++++------- test/expected/functions_2.out | 24 ++++++------- test/expected/functions_3.out | 24 ++++++------- test/expected/functions_5.out | 24 ++++++------- test/expected/functions_6.out | 24 ++++++------- test/expected/functions_7.out | 24 ++++++------- test/expected/functions_8.out | 24 ++++++------- test/expected/functions_9.out | 53 ++++++++++++++++----------- test/expected/subplan_pushdown.out | 20 +++++------ test/expected/subplan_pushdown_1.out | 20 +++++------ test/expected/subplan_pushdown_2.out | 20 +++++------ test/expected/subplan_pushdown_3.out | 20 +++++------ 22 files changed, 370 insertions(+), 326 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 525effff..ace024f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,11 +41,15 @@ All notable changes to this project will be documented in this file. It uses the parameters, preserving timestamp precision and UTC semantics ([#389]). * Fixed floating-point parameter precision loss by using shortest round-trip literals ([#389]). +* Fixed unconstrained `numeric` casts to use `Nullable(Decimal(76, 38))`, + avoiding errors and fractional precision loss ([#389]). * Fixed GCC 15 build failure caused by a `-Wclobbered` error in binary driver connection setup ([#395]). [v0.11.1]: https://github.com/ClickHouse/pg_clickhouse/compare/v0.11.0...v0.11.1 [CloudNativePG]: https://cloudnative-pg.io/ "Run PostgreSQL The Kubernetes way" + [#389]: https://github.com/ClickHouse/pg_clickhouse/pull/389 + "ClickHouse/pg_clickhouse#389 Fix uuid, temporal, float & numeric type mapping, push down interval params & points" [#395]: https://github.com/ClickHouse/pg_clickhouse/pull/395 "ClickHouse/pg_clickhouse#395 Fix gcc15 Wclobbered warning" [regr_avgx](https://clickhouse.com/docs/reference/functions/aggregate-functions/regr_avgx) diff --git a/src/deparse.c b/src/deparse.c index b97d403d..691d1cf6 100644 --- a/src/deparse.c +++ b/src/deparse.c @@ -1924,14 +1924,10 @@ ch_format_type_extended(Oid type_oid, int32 typemod, uint16 flags) { case NUMERICOID: if (with_typemod) { - /* - * Unconstrained numeric potentially much larger than ClickHouse can - do; max it out when no precision specified. - */ - buf = typemod < 0 ? "Decimal(76, 38)" - : printTypmod("Decimal", typemod, typeform->typmodout); + buf = printTypmod("Decimal", typemod, typeform->typmodout); } else { - buf = pstrdup("Decimal"); + /* ClickHouse reads bare Decimal as Decimal(10, 0), use max precision */ + buf = pstrdup("Decimal(76, 38)"); } break; @@ -4501,14 +4497,17 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { */ if (node->funcformat == COERCE_EXPLICIT_CAST) { Oid rettype = node->funcresulttype; + Expr* arg = linitial(node->args); int32 coercedTypmod; + /* ClickHouse multiplies Float32 by 10^scale in Float32, breaks at scale 38 */ + bool widen = rettype == NUMERICOID && exprType((Node*)arg) == FLOAT4OID; /* Get the typmod if this is a length-coercion function */ (void)exprIsLengthCoercion((Node*)node, &coercedTypmod); - appendStringInfoString(buf, "cast("); - deparseExpr((Expr*)linitial(node->args), context); - appendStringInfoString(buf, ", "); + appendStringInfoString(buf, widen ? "cast(toFloat64(" : "cast("); + deparseExpr(arg, context); + appendStringInfoString(buf, widen ? "), " : ", "); deparseStringLiteral( buf, psprintf("Nullable(%s)", deparse_type_name(rettype, coercedTypmod)) ); diff --git a/test/expected/aggregates.out b/test/expected/aggregates.out index 4ab3e562..f99edfe5 100644 --- a/test/expected/aggregates.out +++ b/test/expected/aggregates.out @@ -1788,30 +1788,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) -- var_pop(int2), var_samp(int2), variance(int2) @@ -1950,30 +1950,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) -- any_value pushdown (binary) diff --git a/test/expected/aggregates_1.out b/test/expected/aggregates_1.out index c87802c7..fa72aa89 100644 --- a/test/expected/aggregates_1.out +++ b/test/expected/aggregates_1.out @@ -1788,30 +1788,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) -- var_pop(int2), var_samp(int2), variance(int2) @@ -1950,30 +1950,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) NOTICE: drop cascades to 2 other objects diff --git a/test/expected/aggregates_2.out b/test/expected/aggregates_2.out index dde1fb94..58395744 100644 --- a/test/expected/aggregates_2.out +++ b/test/expected/aggregates_2.out @@ -1804,30 +1804,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) -- var_pop(int2), var_samp(int2), variance(int2) @@ -1966,30 +1966,30 @@ FDW options: (database 'agg_test', table_name 'hits', engine 'MergeTree') (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) -- any_value pushdown (binary) diff --git a/test/expected/aggregates_3.out b/test/expected/aggregates_3.out index c79c4e56..1b0cfed7 100644 --- a/test/expected/aggregates_3.out +++ b/test/expected/aggregates_3.out @@ -1794,30 +1794,30 @@ DETAIL: Remote Query: SELECT datestamp, groupConcat(', ')(path) FROM agg_test.h (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - stddev | stddev_samp | stddev_pop -------------------+------------------+------------------ - 151.218385125619 | 151.218385125619 | 130.958963038045 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 (1 row) -- var_pop(int2), var_samp(int2), variance(int2) @@ -1956,30 +1956,30 @@ DETAIL: Remote Query: SELECT datestamp, groupConcat(', ')(path) FROM agg_test.h (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) - var_pop | var_samp | variance -----------+----------+---------- - 17150.25 | 22867 | 22867 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 (1 row) -- any_value pushdown (binary) diff --git a/test/expected/aggregates_4.out b/test/expected/aggregates_4.out index e271aa18..510df944 100644 --- a/test/expected/aggregates_4.out +++ b/test/expected/aggregates_4.out @@ -1794,27 +1794,32 @@ DETAIL: Remote Query: SELECT datestamp, groupConcat(', ')(path) FROM agg_test.h (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)') -DETAIL: Remote Query: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 +(1 row) + + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: Code: 42. DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)'). (NUMBER_OF_ARGUMENTS_DOESNT_MATCH) -DETAIL: Remote Query: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers -CONTEXT: HTTP status code: 500 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 +(1 row) + -- var_pop(int2), var_samp(int2), variance(int2) QUERY PLAN ------------------------------------------------------------------------------------- @@ -1951,27 +1956,32 @@ CONTEXT: HTTP status code: 500 (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)') -DETAIL: Remote Query: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 +(1 row) + + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: Code: 42. DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)'). (NUMBER_OF_ARGUMENTS_DOESNT_MATCH) -DETAIL: Remote Query: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers -CONTEXT: HTTP status code: 500 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 +(1 row) + -- any_value pushdown (binary) QUERY PLAN ----------------------------------------------------------------------------------------------- diff --git a/test/expected/aggregates_5.out b/test/expected/aggregates_5.out index f74c1910..dab60a37 100644 --- a/test/expected/aggregates_5.out +++ b/test/expected/aggregates_5.out @@ -1785,27 +1785,32 @@ DETAIL: Remote Query: SELECT groupBitXor(cast(duration, 'Nullable(Int32)')) FRO (1 row) -- stddev(numeric), stddev_samp(numeric), stddev_pop(numeric) - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)') -DETAIL: Remote Query: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 +(1 row) + + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (stddev((b)::numeric)), (stddev_samp((b)::numeric)), (stddev_pop((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), stddev_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: Code: 42. DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)'). (NUMBER_OF_ARGUMENTS_DOESNT_MATCH) -DETAIL: Remote Query: SELECT stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_samp(cast(b, 'Nullable(Decimal)')), stddev_pop(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers -CONTEXT: HTTP status code: 500 + stddev | stddev_samp | stddev_pop +------------------+------------------+----------------- + 151.389360803998 | 151.389360803998 | 131.10703231895 +(1 row) + -- var_pop(int2), var_samp(int2), variance(int2) QUERY PLAN ------------------------------------------------------------------------------------- @@ -1942,27 +1947,32 @@ CONTEXT: HTTP status code: 500 (1 row) -- var_pop(numeric), var_samp(numeric), variance(numeric) - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)') -DETAIL: Remote Query: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 +(1 row) + + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (var_pop((b)::numeric)), (var_samp((b)::numeric)), (variance((b)::numeric)) Relations: Aggregate on (agg_numbers) - Remote SQL: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers + Remote SQL: SELECT var_pop(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')), var_samp(cast(toFloat64(b), 'Nullable(Decimal(76, 38))')) FROM agg_test.agg_numbers (4 rows) -ERROR: pg_clickhouse: Code: 42. DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing CAST(b, 'Nullable(Decimal)'). (NUMBER_OF_ARGUMENTS_DOESNT_MATCH) -DETAIL: Remote Query: SELECT var_pop(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')), var_samp(cast(b, 'Nullable(Decimal)')) FROM agg_test.agg_numbers -CONTEXT: HTTP status code: 500 + var_pop | var_samp | variance +------------------+------------------+------------------ + 17189.0539234823 | 22918.7385646431 | 22918.7385646431 +(1 row) + -- any_value pushdown (binary) QUERY PLAN ----------------------------------------------------------------------------------------------- diff --git a/test/expected/functions.out b/test/expected/functions.out index 5b19b819..141dad42 100644 --- a/test/expected/functions.out +++ b/test/expected/functions.out @@ -2219,11 +2219,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2331,11 +2331,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2378,11 +2378,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2393,11 +2393,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_0.out b/test/expected/functions_0.out index 396a57db..9651f0f1 100644 --- a/test/expected/functions_0.out +++ b/test/expected/functions_0.out @@ -2189,16 +2189,16 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing (CAST(a, 'Nullable(Decimal)') % 3) = 0 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST +ERROR: pg_clickhouse: DB::Exception: Illegal types Decimal(76, 38) and UInt8 of arguments of function modulo: While processing (CAST(a, 'Nullable(Decimal(76, 38))') % 3) = 0 +DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE pow(a::numeric, 2::numeric) = 25; QUERY PLAN @@ -2296,16 +2296,19 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing abs(CAST(a, 'Nullable(Decimal)')) = 5 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + a +--- + 5 +(1 row) + -- factorial(int8) pushes down. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE factorial(a) = 120; @@ -2340,28 +2343,33 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing round(CAST(a, 'Nullable(Decimal)'), 0) = 5 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + a +--- + 5 +(1 row) + EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing round(CAST(a, 'Nullable(Decimal)') / 3, 2) = 1.67 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + a +--- +(0 rows) + -- Trig functions push down at f64 = 0 where PG and CH agree exactly. EXPLAIN (VERBOSE, COSTS OFF) SELECT i64 FROM t6 WHERE i64 = 0 AND sin(f64) = 0; diff --git a/test/expected/functions_1.out b/test/expected/functions_1.out index e705eb60..5660e8bc 100644 --- a/test/expected/functions_1.out +++ b/test/expected/functions_1.out @@ -2219,11 +2219,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2331,11 +2331,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2378,11 +2378,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2393,11 +2393,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_2.out b/test/expected/functions_2.out index 665913d7..57faf237 100644 --- a/test/expected/functions_2.out +++ b/test/expected/functions_2.out @@ -2219,11 +2219,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2331,11 +2331,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2378,11 +2378,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2393,11 +2393,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_3.out b/test/expected/functions_3.out index c9ce3f46..e50f3221 100644 --- a/test/expected/functions_3.out +++ b/test/expected/functions_3.out @@ -2219,11 +2219,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2331,11 +2331,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2378,11 +2378,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2393,11 +2393,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_5.out b/test/expected/functions_5.out index 09598f92..8ea95380 100644 --- a/test/expected/functions_5.out +++ b/test/expected/functions_5.out @@ -2215,11 +2215,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2327,11 +2327,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2374,11 +2374,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2389,11 +2389,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_6.out b/test/expected/functions_6.out index 872f0e43..52cfc4ed 100644 --- a/test/expected/functions_6.out +++ b/test/expected/functions_6.out @@ -2203,11 +2203,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2315,11 +2315,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2362,11 +2362,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2377,11 +2377,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_7.out b/test/expected/functions_7.out index 6d632ef3..3fe0d494 100644 --- a/test/expected/functions_7.out +++ b/test/expected/functions_7.out @@ -2203,11 +2203,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2315,11 +2315,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2362,11 +2362,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2377,11 +2377,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_8.out b/test/expected/functions_8.out index 3b8d4c43..b7049fb4 100644 --- a/test/expected/functions_8.out +++ b/test/expected/functions_8.out @@ -2199,11 +2199,11 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; @@ -2311,11 +2311,11 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; @@ -2358,11 +2358,11 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; @@ -2373,11 +2373,11 @@ SELECT a FROM t3 WHERE round(a::numeric) = 5; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; diff --git a/test/expected/functions_9.out b/test/expected/functions_9.out index 63e94652..0ce5a457 100644 --- a/test/expected/functions_9.out +++ b/test/expected/functions_9.out @@ -2196,16 +2196,21 @@ SELECT i64 FROM t6 WHERE power(f64, 2::float8) < 1 ORDER BY i64; -- https://github.com/ClickHouse/ClickHouse/issues/115327 EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal(76, 38))'), 3) = 0)) ORDER BY a ASC NULLS LAST (3 rows) SELECT a FROM t3 WHERE mod(a::numeric, 3::numeric) = 0 ORDER BY a; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing (CAST(a, 'Nullable(Decimal)') % 3) = 0 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((modulo(cast(a, 'Nullable(Decimal)'), 3) = 0)) ORDER BY a ASC NULLS LAST + a +--- + 3 + 6 + 9 +(3 rows) + EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE pow(a::numeric, 2::numeric) = 25; QUERY PLAN @@ -2303,16 +2308,19 @@ SELECT i64 FROM t6 WHERE abs(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE abs(a::numeric) = 5; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal(76, 38))')) = 5)) (3 rows) SELECT a FROM t3 WHERE abs(a::numeric) = 5; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing abs(CAST(a, 'Nullable(Decimal)')) = 5 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((abs(cast(a, 'Nullable(Decimal)')) = 5)) + a +--- + 5 +(1 row) + -- factorial(int8) pushes down. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE factorial(a) = 120; @@ -2347,28 +2355,33 @@ SELECT i64 FROM t6 WHERE round(f64) = 0; EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round(a::numeric) = 5; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal(76, 38))'), 0) = 5)) (3 rows) SELECT a FROM t3 WHERE round(a::numeric) = 5; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing round(CAST(a, 'Nullable(Decimal)'), 0) = 5 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((round(cast(a, 'Nullable(Decimal)'), 0) = 5)) + a +--- + 5 +(1 row) + EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t3 Output: a - Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + Remote SQL: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal(76, 38))') / 3), 2) = 1.67)) (3 rows) SELECT a FROM t3 WHERE round((a::numeric) / 3, 2) = 1.67; -ERROR: pg_clickhouse: DB::Exception: Decimal data type family must have exactly two arguments: precision and scale: While processing round(CAST(a, 'Nullable(Decimal)') / 3, 2) = 1.67 -DETAIL: Remote Query: SELECT a FROM functions_test.t3 WHERE ((round((cast(a, 'Nullable(Decimal)') / 3), 2) = 1.67)) + a +--- +(0 rows) + -- Trig functions push down at f64 = 0 where PG and CH agree exactly. EXPLAIN (VERBOSE, COSTS OFF) SELECT i64 FROM t6 WHERE i64 = 0 AND sin(f64) = 0; diff --git a/test/expected/subplan_pushdown.out b/test/expected/subplan_pushdown.out index 9ceffdd8..4b708188 100644 --- a/test/expected/subplan_pushdown.out +++ b/test/expected/subplan_pushdown.out @@ -57,11 +57,11 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT item_id, price FROM items WHERE price > (SELECT avg(price) FROM items) ORDER BY item_id; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on subplan_test.items Output: items.item_id, items.price - Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan expr_1 -> Foreign Scan Output: (avg(items_1.price)) @@ -209,12 +209,12 @@ SELECT grp, sum(price * qty) AS value FROM items GROUP BY grp HAVING sum(price * qty) > (SELECT sum(price * qty) * 0.2 FROM items) ORDER BY value DESC; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: items.grp, (sum((items.price * (items.qty)::numeric))) Relations: Aggregate on (items) - Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal})) ORDER BY sum((price * qty)) DESC NULLS FIRST + Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal(76, 38)})) ORDER BY sum((price * qty)) DESC NULLS FIRST InitPlan expr_1 -> Foreign Scan Output: ((sum((items_1.price * (items_1.qty)::numeric)) * 0.2)) @@ -240,16 +240,16 @@ SELECT item_id FROM items WHERE price > (SELECT avg(price) FROM items WHERE qty > (SELECT avg(qty) FROM items)) ORDER BY item_id; - QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on subplan_test.items Output: items.item_id - Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan expr_1 -> Foreign Scan Output: (avg(items_2.price)) Relations: Aggregate on (items) - Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal})) + Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal(76, 38)})) InitPlan expr_2 -> Foreign Scan Output: (avg(items_1.qty)) diff --git a/test/expected/subplan_pushdown_1.out b/test/expected/subplan_pushdown_1.out index da5d5969..19cda93b 100644 --- a/test/expected/subplan_pushdown_1.out +++ b/test/expected/subplan_pushdown_1.out @@ -57,11 +57,11 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT item_id, price FROM items WHERE price > (SELECT avg(price) FROM items) ORDER BY item_id; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on subplan_test.items Output: items.item_id, items.price - Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 1 -> Foreign Scan Output: (avg(items_1.price)) @@ -212,12 +212,12 @@ SELECT grp, sum(price * qty) AS value FROM items GROUP BY grp HAVING sum(price * qty) > (SELECT sum(price * qty) * 0.2 FROM items) ORDER BY value DESC; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: items.grp, (sum((items.price * (items.qty)::numeric))) Relations: Aggregate on (items) - Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal})) ORDER BY sum((price * qty)) DESC NULLS FIRST + Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal(76, 38)})) ORDER BY sum((price * qty)) DESC NULLS FIRST InitPlan 1 -> Foreign Scan Output: ((sum((items_1.price * (items_1.qty)::numeric)) * 0.2)) @@ -243,16 +243,16 @@ SELECT item_id FROM items WHERE price > (SELECT avg(price) FROM items WHERE qty > (SELECT avg(qty) FROM items)) ORDER BY item_id; - QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on subplan_test.items Output: items.item_id - Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 2 -> Foreign Scan Output: (avg(items_2.price)) Relations: Aggregate on (items) - Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal})) + Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal(76, 38)})) InitPlan 1 -> Foreign Scan Output: (avg(items_1.qty)) diff --git a/test/expected/subplan_pushdown_2.out b/test/expected/subplan_pushdown_2.out index 3236b86a..f43dbbc7 100644 --- a/test/expected/subplan_pushdown_2.out +++ b/test/expected/subplan_pushdown_2.out @@ -57,11 +57,11 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT item_id, price FROM items WHERE price > (SELECT avg(price) FROM items) ORDER BY item_id; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on subplan_test.items Output: items.item_id, items.price - Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 1 (returns $0) -> Foreign Scan Output: (avg(items_1.price)) @@ -212,12 +212,12 @@ SELECT grp, sum(price * qty) AS value FROM items GROUP BY grp HAVING sum(price * qty) > (SELECT sum(price * qty) * 0.2 FROM items) ORDER BY value DESC; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: items.grp, (sum((items.price * (items.qty)::numeric))) Relations: Aggregate on (items) - Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal})) ORDER BY sum((price * qty)) DESC NULLS FIRST + Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal(76, 38)})) ORDER BY sum((price * qty)) DESC NULLS FIRST InitPlan 1 (returns $0) -> Foreign Scan Output: ((sum((items_1.price * (items_1.qty)::numeric)) * 0.2)) @@ -243,16 +243,16 @@ SELECT item_id FROM items WHERE price > (SELECT avg(price) FROM items WHERE qty > (SELECT avg(qty) FROM items)) ORDER BY item_id; - QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on subplan_test.items Output: items.item_id - Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 2 (returns $1) -> Foreign Scan Output: (avg(items_2.price)) Relations: Aggregate on (items) - Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal})) + Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal(76, 38)})) InitPlan 1 (returns $0) -> Foreign Scan Output: (avg(items_1.qty)) diff --git a/test/expected/subplan_pushdown_3.out b/test/expected/subplan_pushdown_3.out index c02bc8c7..dc703c40 100644 --- a/test/expected/subplan_pushdown_3.out +++ b/test/expected/subplan_pushdown_3.out @@ -57,11 +57,11 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT item_id, price FROM items WHERE price > (SELECT avg(price) FROM items) ORDER BY item_id; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on subplan_test.items Output: items.item_id, items.price - Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id, price FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 1 (returns $0) -> Foreign Scan Output: (avg(items_1.price)) @@ -212,12 +212,12 @@ SELECT grp, sum(price * qty) AS value FROM items GROUP BY grp HAVING sum(price * qty) > (SELECT sum(price * qty) * 0.2 FROM items) ORDER BY value DESC; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: items.grp, (sum((items.price * (items.qty)::numeric))) Relations: Aggregate on (items) - Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal})) ORDER BY sum((price * qty)) DESC NULLS FIRST + Remote SQL: SELECT grp, sum((price * qty)) FROM subplan_test.items GROUP BY grp HAVING ((sum((price * qty)) > {p1:Decimal(76, 38)})) ORDER BY sum((price * qty)) DESC NULLS FIRST InitPlan 1 (returns $0) -> Foreign Scan Output: ((sum((items_1.price * (items_1.qty)::numeric)) * 0.2)) @@ -243,16 +243,16 @@ SELECT item_id FROM items WHERE price > (SELECT avg(price) FROM items WHERE qty > (SELECT avg(qty) FROM items)) ORDER BY item_id; - QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on subplan_test.items Output: items.item_id - Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal})) ORDER BY item_id ASC NULLS LAST + Remote SQL: SELECT item_id FROM subplan_test.items WHERE ((price > {p1:Decimal(76, 38)})) ORDER BY item_id ASC NULLS LAST InitPlan 2 (returns $1) -> Foreign Scan Output: (avg(items_2.price)) Relations: Aggregate on (items) - Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal})) + Remote SQL: SELECT avg(price) FROM subplan_test.items WHERE ((qty > {p1:Decimal(76, 38)})) InitPlan 1 (returns $0) -> Foreign Scan Output: (avg(items_1.qty))