diff --git a/CHANGELOG.md b/CHANGELOG.md index 30a76880..075faac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ 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]). +* Pushed down `point` values and coordinate subscripts. Don't push down other + geometric operators, casts, and expressions ([#389]). * Added pushdown for more regression aggregate functions on ClickHouse 26.9+: * [regr_avgx] * [regr_avgy] @@ -34,6 +37,26 @@ All notable changes to this project will be documented in this file. It uses the ### 🐞 Bug Fixes +* Fixed ClickHouse type mappings for date, time, timestamp, UUID, and JSON + casts and parameters, preserving timestamp precision and UTC semantics for + `timestamptz` ([#389]). +* Set ClickHouse `session_timezone` to PostgreSQL `TimeZone` on ClickHouse + 23.6 and later. This makes ClickHouse interpret unzoned timestamp literals + and parameters using PostgreSQL's time zone ([#389]). +* Matched PostgreSQL `TimeZone` when pushing down `date_part`, `extract`, + `date_trunc`, `to_char`, `date`, and timestamp arithmetic with intervals, + regardless of ClickHouse column or server time zones ([#389]). +* Preserved microseconds in pushed down `date_part('second')` and + `date_part('epoch')`. PostgreSQL interprets `timestamp` and `date` values + as UTC for epoch extraction ([#389]). +* Fixed pushdown of `date_trunc` to return timestamps for `week`, `month`, + `quarter`, and `year`, allowing comparisons with timestamps. Enabled + `enable_extended_results_for_datetime_functions` to support dates before + 1970 ([#389]). +* Don't push down `timezone()` or `AT TIME ZONE` ([#389]). +* Preserved floating-point parameter values with shortest round-trip + literals, including `NaN` and infinities ([#389]). +* Fixed bare `numeric` casts to use `Nullable(Decimal(76, 38))` ([#389]). * Fixed GCC 15 build failure caused by a `-Wclobbered` error in binary driver connection setup ([#395]). * Added checks to prevent the pushdown of custom functions or @@ -41,6 +64,8 @@ All notable changes to this project will be documented in this file. It uses the [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/doc/pg_clickhouse.md b/doc/pg_clickhouse.md index 33dda066..857e2eb9 100644 --- a/doc/pg_clickhouse.md +++ b/doc/pg_clickhouse.md @@ -1135,6 +1135,27 @@ or `bigint` to read and write counts of their units. For example, an `IntervalNanosecond` to `bigint` preserves nanoseconds, while mapping to `interval` truncates to microseconds. +### Time Zones + +On ClickHouse 23.6 and later, pg_clickhouse sets ClickHouse +[session_timezone] to PostgreSQL [TimeZone] for each query. This overrides +`session_timezone` in [`pg_clickhouse.session_settings`]. ClickHouse uses the +setting to parse and format `DateTime` and `DateTime64` values without an +explicit time zone, including timestamp literals and parameters. Older +ClickHouse versions use the server time zone. + +ClickHouse date and time functions use each column's time zone, or the server +time zone when a column has none. They do not use `session_timezone`. To match +PostgreSQL, pg_clickhouse converts timestamp arguments to `DateTime64` in +PostgreSQL's `TimeZone` when it pushes down `date_part`, `extract`, +`date_trunc`, `to_char`, and `date`. A `Date` column mapped to `timestamp` is +treated as midnight. Timestamp arithmetic with intervals also uses +PostgreSQL's `TimeZone`, so month and day calculations follow daylight savings. + +When PostgreSQL's `TimeZone` is a fixed UTC offset, ClickHouse supports +offsets in 15-minute increments from −14:00 through +14:00. Other fixed +offsets raise an error. + ### BYTEA ClickHouse does not provide the equivalent of the PostgreSQL [BYTEA] type, but @@ -1603,11 +1624,15 @@ equivalents as follows: * `date_part('month')`: [toMonth](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toMonth) * `date_part('hour')`: [toHour](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toHour) * `date_part('minute')`: [toMinute](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toMinute) - * `date_part('second')`: [toSecond](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toSecond) + * `date_part('second')`: [toSecond](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toSecond), + with fractional seconds preserved for timestamps * `date_part('quarter')`: [toQuarter](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toQuarter) * `date_part('isoyear')`: [toISOYear](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toISOYear) * `date_part('week')`: [toISOYear](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toISOWeek) - * `date_part('epoch')`: [toISOYear](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toUnixTimestamp) + * `date_part('epoch')`: cast [toDateTime64](https://clickhouse.com/docs/sql-reference/functions/type-conversion-functions#todatetime64) + to `Decimal64(6)` to preserve microseconds; for `timestamp`, adjust + with [timeZoneOffset](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#timeZoneOffset) + so PostgreSQL interprets the wall-clock value as UTC * `date_trunc`: * `date_trunc('week')`: [toMonday](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toMonday) * `date_trunc('second')`: [toStartOfSecond](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toStartOfSecond) @@ -1619,7 +1644,6 @@ equivalents as follows: * `date_trunc('year')`: [toStartOfYear](https://clickhouse.com/docs/sql-reference/functions/date-time-functions#toStartOfYear) * `extract(field FROM source)`: same mappings as `date_part` * `date(timestamp)` & `date(timestamptz)`: [toDate](https://clickhouse.com/docs/sql-reference/functions/type-conversion-functions#toDate) - (deparsed as CH alias `date`) * `array_position`: [indexOf](https://clickhouse.com/docs/sql-reference/functions/array-functions#indexOf) with [nullIf](https://clickhouse.com/docs/reference/functions/regular-functions/functions-for-nulls#nullif) to convert `0` to `NULL` and @@ -2075,6 +2099,13 @@ other backslash sequences are treated as literal text. Copyright (c) 2025-2026, ClickHouse. + [session_timezone]: https://clickhouse.com/docs/operations/settings/settings#session_timezone + "ClickHouse Docs: session_timezone" + [enable_extended_results_for_datetime_functions]: https://clickhouse.com/docs/reference/settings/session-settings/enable#enable_extended_results_for_datetime_functions + "ClickHouse Docs: enable_extended_results_for_datetime_functions" + [TimeZone]: https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-TIMEZONE + "PostgreSQL Docs: TimeZone" + [`pg_clickhouse.session_settings`]: #pg_clickhousesession_settings [foreign data wrapper]: https://www.postgresql.org/docs/current/fdwhandler.html "PostgreSQL Docs: Writing a Foreign Data Wrapper" [Docker image]: https://github.com/ClickHouse/pg_clickhouse/pkgs/container/pg_clickhouse diff --git a/src/binary/binary.c b/src/binary/binary.c index f764e988..49af03cb 100644 --- a/src/binary/binary.c +++ b/src/binary/binary.c @@ -31,27 +31,6 @@ #include "binary_internal.h" #include "kv_list.h" -/* - * output_format_native_write_json_as_string exists on the server from - * 24.10 onwards. Sending it as `important` against an older server would - * fail the query, so gate. - */ -bool -server_supports_json_as_string(const chc_client* c) { - const chc_server_info* info = chc_client_server_info(c); - - if (!info) { - return false; - } - if (info->version_major > 24) { - return true; - } - if (info->version_major == 24 && info->version_minor >= 10) { - return true; - } - return false; -} - const char* ch_binary_exception_message(const chc_exception* ex) { if (ex) { @@ -111,18 +90,18 @@ ch_binary_drain(ch_binary_connection_t* conn, char** out_msg) { */ chc_query_setting* ch_binary_query_settings( - const chc_client* c, + const ch_binary_connection_t* conn, const ch_query* query, size_t* n_settings ) { - bool json_as_string = server_supports_json_as_string(c); - size_t n = (query->settings ? (size_t)query->settings->length : 0) + - (json_as_string ? 1 : 0); + /* Unknown important settings cause query errors on older servers. */ + ch_server_version version = ch_binary_server_version(conn); + bool json_as_string = chfdw_version_ge(version, 24, 10); + bool timezone = chfdw_version_ge(version, 23, 6); + size_t n = (query->settings ? (size_t)query->settings->length : 0) + 1 + + (json_as_string ? 1 : 0) + (timezone ? 1 : 0); *n_settings = n; - if (!n) { - return NULL; - } chc_query_setting* settings = palloc0(n * sizeof(*settings)); size_t i = 0; @@ -134,10 +113,22 @@ ch_binary_query_settings( settings[i].important = true; i++; } + /* Preserve dates before 1970 in ClickHouse datetime functions. */ + settings[i].name = "enable_extended_results_for_datetime_functions"; + settings[i].value = "1"; + settings[i].important = true; + i++; if (json_as_string) { settings[i].name = "output_format_native_write_json_as_string"; settings[i].value = "1"; settings[i].important = true; + i++; + } + if (timezone) { + /* Interpret unzoned DateTime64 values in PostgreSQL TimeZone. */ + settings[i].name = "session_timezone"; + settings[i].value = pgch_session_timezone(); + settings[i].important = true; } return settings; } diff --git a/src/binary/binary_internal.h b/src/binary/binary_internal.h index c68d6b29..22d0e93b 100644 --- a/src/binary/binary_internal.h +++ b/src/binary/binary_internal.h @@ -80,17 +80,13 @@ struct ch_binary_connection_t { extern void ch_binary_set_deadline(ch_binary_connection_t* conn, int64_t deadline_us); -/* True if server advertises output_format_native_write_json_as_string. */ -extern bool -server_supports_json_as_string(const chc_client* c); - /* - * Collect settings for query, adding session settings before driver settings. - * Store number of settings in *n_settings and return NULL when list is empty. + * Collect query settings, adding session settings before driver settings. + * Store number of settings in *n_settings. */ extern chc_query_setting* ch_binary_query_settings( - const chc_client* c, + const ch_binary_connection_t* conn, const ch_query* query, size_t* n_settings ); diff --git a/src/binary/connection.c b/src/binary/connection.c index 552e05d5..ba9766b5 100644 --- a/src/binary/connection.c +++ b/src/binary/connection.c @@ -359,29 +359,19 @@ ch_binary_is_broken(const ch_binary_connection_t* conn) { } /* - * Reports the ClickHouse server version (major.minor.patch) for a binary - * connection. The native protocol reports the server version during the - * handshake, so it reads the cached handshake info rather than issuing a - * query. Writes 0 to all out-params when the version is unavailable. + * Read ClickHouse server version from cached native protocol handshake. + * Return 0.0.0 when version is unavailable. */ -void -ch_binary_server_version( - const ch_binary_connection_t* conn, - int* major, - int* minor, - int* patch -) { - *major = *minor = *patch = 0; - if (!conn || !conn->client) { - return; - } +ch_server_version +ch_binary_server_version(const ch_binary_connection_t* conn) { + const chc_server_info* info = chc_client_server_info(conn ? conn->client : NULL); - const chc_server_info* info = chc_client_server_info(conn->client); - if (info) { - *major = (int)info->version_major; - *minor = (int)info->version_minor; - *patch = (int)info->version_patch; + if (!info) { + return (ch_server_version){ 0, 0, 0 }; } + return (ch_server_version){ (int)info->version_major, + (int)info->version_minor, + (int)info->version_patch }; } void diff --git a/src/binary/insert.c b/src/binary/insert.c index efc90f00..8daae56d 100644 --- a/src/binary/insert.c +++ b/src/binary/insert.c @@ -104,7 +104,7 @@ ch_binary_begin_insert(ch_binary_connection_t* conn, const ch_query* query) { size_t n_settings; chc_query_setting* settings = - ch_binary_query_settings(conn->client, query, &n_settings); + ch_binary_query_settings(conn, query, &n_settings); chc_query_opts insert_opts = { .settings = settings, .n_settings = n_settings, diff --git a/src/binary/select.c b/src/binary/select.c index ff5439db..8ede4146 100644 --- a/src/binary/select.c +++ b/src/binary/select.c @@ -182,8 +182,7 @@ ch_binary_simple_query( size_t n_params = (size_t)(query->num_params > 0 ? query->num_params : 0); chc_query_param* params = NULL; size_t n_settings; - chc_query_setting* settings = - ch_binary_query_settings(conn->client, query, &n_settings); + chc_query_setting* settings = ch_binary_query_settings(conn, query, &n_settings); if (n_params) { params = palloc0(n_params * sizeof(*params)); diff --git a/src/custom_types.c b/src/custom_types.c index b39ff9a1..deb05550 100644 --- a/src/custom_types.c +++ b/src/custom_types.c @@ -258,11 +258,6 @@ lookup_builtin_func(Oid funcid, builtin_func_def* def) { def->cf_type = CF_DATE_PART; def->ch_name = "\1"; return true; - case F_TIMEZONE_TEXT_TIMESTAMP: - case F_TIMEZONE_TEXT_TIMESTAMPTZ: - def->cf_type = CF_TIMEZONE; - def->ch_name = "toTimeZone"; - return true; case F_ARRAY_POSITION_ANYCOMPATIBLEARRAY_ANYCOMPATIBLE: case F_ARRAY_POSITION_ANYCOMPATIBLEARRAY_ANYCOMPATIBLE_INT4: def->cf_type = CF_ARRAY_POSITION; @@ -406,6 +401,11 @@ lookup_builtin_func(Oid funcid, builtin_func_def* def) { def->cf_type = CF_TO_TIMESTAMP; def->ch_name = "\1"; return true; + case F_DATE_TIMESTAMP: + case F_DATE_TIMESTAMPTZ: + def->cf_type = CF_DATE; + def->ch_name = "\1"; + return true; case F_TO_CHAR_TIMESTAMP_TEXT: case F_TO_CHAR_TIMESTAMPTZ_TEXT: def->cf_type = CF_TO_CHAR; @@ -650,9 +650,6 @@ lookup_builtin_func(Oid funcid, builtin_func_def* def) { case F_RTRIM_TEXT_TEXT: case F_CONCAT_WS: case F_LENGTH_BYTEA: - /* date(ts), date(tstz) deparse as CH date() (alias toDate) */ - case F_DATE_TIMESTAMP: - case F_DATE_TIMESTAMPTZ: /* window functions: lead/lag share PG and CH names */ case F_LEAD_ANYELEMENT: case F_LEAD_ANYELEMENT_INT4: diff --git a/src/deparse.c b/src/deparse.c index c99ca3b2..b6e7b638 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" @@ -42,18 +43,22 @@ #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" #include "utils/typcache.h" #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 -/* Oft-used syntax to quote quote the session time zone literal string. */ -#define QUOTED_TZ ch_quote_literal(pg_get_timezone_name(session_timezone)) +/* Quote session time zone for ClickHouse SQL. */ +#define QUOTED_TZ ch_quote_literal(pgch_session_timezone()) /* variable counter */ static uint32 var_counter = 0; @@ -874,6 +879,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. * @@ -890,6 +909,34 @@ classify_notin_subplan(SubPlan* subplan, PlannerInfo* root, Relids relids) { * 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; @@ -926,6 +973,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: @@ -949,6 +999,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; @@ -958,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; } @@ -1060,6 +1115,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. */ @@ -1311,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; } @@ -1853,31 +1924,30 @@ 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; case INTERVALOID: - if (with_typemod) { - buf = printTypmod("UInt64", typemod, typeform->typmodout); - } else { - buf = pstrdup("UInt64"); - } + buf = pstrdup("UInt64"); break; + case TIMEOID: case TIMESTAMPTZOID: case TIMESTAMPOID: - buf = pstrdup("DateTime"); - break; case DATEOID: - buf = pstrdup("Date"); + 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; case VARCHAROID: @@ -1890,6 +1960,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) { @@ -3175,6 +3251,38 @@ 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); + } +} + +/* 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, @@ -3411,12 +3519,22 @@ 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; + } + + /* 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("); } - getTypeOutputInfo(node->consttype, &typoutput, &typIsVarlena); - if (typoutput == F_TIMESTAMPTZ_OUT || typoutput == F_TIMESTAMP_OUT) { char ts[MAXDATELEN + 1]; @@ -3452,6 +3570,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 { @@ -3515,31 +3636,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) { @@ -3565,6 +3697,15 @@ deparseParam(Param* node, deparse_expr_cxt* context) { } } +/* PostgreSQL intervals retain months, days, microseconds; CH intervals use one unit */ +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. @@ -3577,7 +3718,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); } @@ -3598,7 +3739,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); } @@ -3895,7 +4036,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) { /* @@ -4323,6 +4472,69 @@ chfdw_translate_to_char_format(const char* pgfmt, StringInfo out) { return true; } +static bool +isTimestamp(Expr* arg) { + Oid type = exprType((Node*)arg); + + return type == TIMESTAMPOID || type == TIMESTAMPTZOID; +} + +/* + * ClickHouse datetime functions use column or server time zones, ignoring + * session_timezone. Convert to PostgreSQL TimeZone and interpret Date values + * mapped or implicitly cast to timestamp as midnight. + */ +static void +deparseZonedExpr(Expr* arg, deparse_expr_cxt* context) { + if (!isTimestamp(arg)) { + deparseExpr(arg, context); + return; + } + appendStringInfoString(context->buf, "toDateTime64("); + deparseExpr(arg, context); + appendStringInfo(context->buf, ", 6, %s)", QUOTED_TZ); +} + +/* + * PostgreSQL epoch extraction interprets timestamp and date as UTC and + * preserves microseconds. ClickHouse toUnixTimestamp uses instants and + * truncates fractional seconds. + */ +static void +deparseEpoch(Expr* arg, deparse_expr_cxt* context) { + StringInfo buf = context->buf; + + appendStringInfoString(buf, "(toDecimal64("); + if (isTimestamp(arg)) { + deparseZonedExpr(arg, context); + } else { + appendStringInfoString(buf, "toDateTime64("); + deparseExpr(arg, context); + appendStringInfoString(buf, ", 6, 'UTC')"); + } + appendStringInfoString(buf, ", 6)"); + if (exprType((Node*)arg) == TIMESTAMPOID) { + appendStringInfoString(buf, " + timeZoneOffset("); + deparseZonedExpr(arg, context); + appendStringInfoChar(buf, ')'); + } + appendStringInfoChar(buf, ')'); +} + +/* Preserve fractional seconds that ClickHouse toSecond truncates. */ +static void +deparseSecond(Expr* arg, deparse_expr_cxt* context) { + StringInfo buf = context->buf; + + appendStringInfoString(buf, "(toSecond("); + deparseZonedExpr(arg, context); + appendStringInfoString(buf, ") + (toDecimal64("); + deparseZonedExpr(arg, context); + appendStringInfoString(buf, ", 6) - floor(toDecimal64("); + deparseZonedExpr(arg, context); + appendStringInfoString(buf, ", 6))))"); +} + /* * Deparse a function call. */ @@ -4348,16 +4560,21 @@ 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); - appendStringInfo( - buf, ", 'Nullable(%s)')", deparse_type_name(rettype, coercedTypmod) + appendStringInfoString(buf, widen ? "cast(toFloat64(" : "cast("); + deparseExpr(arg, context); + appendStringInfoString(buf, widen ? "), " : ", "); + deparseStringLiteral( + buf, psprintf("Nullable(%s)", deparse_type_name(rettype, coercedTypmod)) ); + appendStringInfoChar(buf, ')'); return; } @@ -4401,30 +4618,41 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { appendStringInfoString(buf, ", 6, 'UTC')"); return; } + case CF_DATE: { + appendStringInfoString(buf, "toDate("); + deparseZonedExpr((Expr*)linitial(node->args), context); + appendStringInfoChar(buf, ')'); + return; + } case CF_DATE_TRUNC: { Const* arg = (Const*)linitial(node->args); char* trunctype = TextDatumGetCString(arg->constvalue); + const char* fn; + /* Match PostgreSQL timestamp results for ClickHouse date functions. */ + bool date = false; CSTRING_TOLOWER(trunctype); - int cast_to_datetime64 = 0; if (strcmp(trunctype, "week") == 0) { - appendStringInfoString(buf, "toMonday"); + fn = "toMonday"; + date = true; } else if (strcmp(trunctype, "second") == 0) { - cast_to_datetime64 = 1; - appendStringInfoString(buf, "toStartOfSecond"); + fn = "toStartOfSecond"; } else if (strcmp(trunctype, "minute") == 0) { - appendStringInfoString(buf, "toStartOfMinute"); + fn = "toStartOfMinute"; } else if (strcmp(trunctype, "hour") == 0) { - appendStringInfoString(buf, "toStartOfHour"); + fn = "toStartOfHour"; } else if (strcmp(trunctype, "day") == 0) { - appendStringInfoString(buf, "toStartOfDay"); + fn = "toStartOfDay"; } else if (strcmp(trunctype, "month") == 0) { - appendStringInfoString(buf, "toStartOfMonth"); + fn = "toStartOfMonth"; + date = true; } else if (strcmp(trunctype, "quarter") == 0) { - appendStringInfoString(buf, "toStartOfQuarter"); + fn = "toStartOfQuarter"; + date = true; } else if (strcmp(trunctype, "year") == 0) { - appendStringInfoString(buf, "toStartOfYear"); + fn = "toStartOfYear"; + date = true; } else { ereport( ERROR, @@ -4434,14 +4662,14 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { } pfree(trunctype); - if (cast_to_datetime64) { - appendStringInfoString(buf, "(toDateTime64("); - deparseExpr(list_nth(node->args, 1), context); - appendStringInfoString(buf, ", 1))"); - } else { - appendStringInfoChar(buf, '('); - deparseExpr(list_nth(node->args, 1), context); - appendStringInfoChar(buf, ')'); + if (date) { + appendStringInfoString(buf, "toDateTime64("); + } + appendStringInfo(buf, "%s(", fn); + deparseZonedExpr(list_nth(node->args, 1), context); + appendStringInfoChar(buf, ')'); + if (date) { + appendStringInfo(buf, ", 6, %s)", QUOTED_TZ); } return; } @@ -4452,6 +4680,17 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { CSTRING_TOLOWER(parttype); + if (strcmp(parttype, "epoch") == 0) { + pfree(parttype); + deparseEpoch(list_nth(node->args, 1), context); + return; + } + if (strcmp(parttype, "second") == 0 && + isTimestamp(list_nth(node->args, 1))) { + pfree(parttype); + deparseSecond(list_nth(node->args, 1), context); + return; + } if (strcmp(parttype, "day") == 0) { appendStringInfoString(buf, "toDayOfMonth"); } else if (strcmp(parttype, "doy") == 0) { @@ -4475,8 +4714,6 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { appendStringInfoString(buf, "toISOYear"); } else if (strcmp(parttype, "week") == 0) { appendStringInfoString(buf, "toISOWeek"); - } else if (strcmp(parttype, "epoch") == 0) { - appendStringInfoString(buf, "toUnixTimestamp"); } else { ereport( ERROR, @@ -4487,7 +4724,7 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { pfree(parttype); appendStringInfoChar(buf, '('); - deparseExpr(list_nth(node->args, 1), context); + deparseZonedExpr(list_nth(node->args, 1), context); if (postgres_dow) { /* Mode 2 aligns with Postgres behavior (Sunday = 0). */ appendStringInfoString(buf, ", 2"); @@ -4495,7 +4732,6 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { appendStringInfoChar(buf, ')'); return; } - case CF_TIMEZONE: case CF_ARRAY_PREPEND: case CF_STRING_TO_ARRAY: case CF_STRING_TO_ARRAY_PART: { @@ -4665,7 +4901,7 @@ deparseFuncExpr(FuncExpr* node, deparse_expr_cxt* context) { } appendStringInfoChar(buf, '('); - deparseExpr((Expr*)linitial(node->args), context); + deparseZonedExpr((Expr*)linitial(node->args), context); appendStringInfoString(buf, ", "); deparseStringLiteral(buf, chfmt.data); appendStringInfoChar(buf, ')'); @@ -4861,6 +5097,21 @@ appendIntervalTerm(StringInfo buf, bool plus, int64 amount, const char* unit) { ); } +/* + * PostgreSQL adds months and days in TimeZone; ClickHouse uses column time + * zone. Convert timestamps to PostgreSQL TimeZone before interval arithmetic. + */ +static void +deparseWideExpr(Expr* first, bool widen, deparse_expr_cxt* context) { + if (!widen || isTimestamp(first)) { + deparseZonedExpr(first, context); + return; + } + appendStringInfoString(context->buf, "toDateTime64("); + deparseExpr(first, context); + appendStringInfoString(context->buf, ", 6)"); +} + static void deparseIntervalOp(Node* first, Node* second, deparse_expr_cxt* context, bool plus) { StringInfo buf = context->buf; @@ -4872,12 +5123,25 @@ deparseIntervalOp(Node* first, Node* second, deparse_expr_cxt* context, bool plu */ bool widen = span && span->time % USECS_PER_SEC != 0; - appendStringInfoString(buf, widen ? "(toDateTime64(" : "("); - deparseExpr((Expr*)first, context); - if (widen) { - appendStringInfoString(buf, ", 6)"); + if (IsA(second, Param) && !correlation_arg((Param*)second, context)) { + static const char* const units[] = { "Month", "Day", "Microsecond" }; + + appendStringInfoChar(buf, '('); + deparseWideExpr((Expr*)first, true, context); + 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; } + appendStringInfoChar(buf, '('); + deparseWideExpr((Expr*)first, widen, context); + if (!span) { bool old_op = context->interval_op; @@ -5617,7 +5881,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/include/binary.h b/src/include/binary.h index d4e7b798..e74d9b65 100644 --- a/src/include/binary.h +++ b/src/include/binary.h @@ -21,6 +21,7 @@ #include "engine.h" #include "pg-clickhouse-decode.h" #include "pg-clickhouse-encode.h" +#include "server_version.h" typedef struct ch_binary_connection_t ch_binary_connection_t; typedef struct ch_binary_response_t ch_binary_response_t; @@ -41,16 +42,11 @@ extern bool ch_binary_is_broken(const ch_binary_connection_t* conn); /* - * Read the server version captured during the native-protocol handshake. - * Writes 0 to all out-params when the version is unavailable. + * Read server version captured during native protocol handshake. + * Return 0.0.0 when version is unavailable. */ -extern void -ch_binary_server_version( - const ch_binary_connection_t* conn, - int* major, - int* minor, - int* patch -); +extern ch_server_version +ch_binary_server_version(const ch_binary_connection_t* conn); /* SELECT. */ extern ch_binary_response_t* diff --git a/src/include/fdw.h b/src/include/fdw.h index d26da879..ee7739fb 100644 --- a/src/include/fdw.h +++ b/src/include/fdw.h @@ -331,6 +331,10 @@ 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); +void +chfdw_append_point_literal(StringInfo buf, Datum val); /* chfdw_is_equal_op's classification of a comparison operator's name. */ typedef enum CHEqualOp { @@ -345,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 @@ -373,7 +379,6 @@ typedef enum { CF_DATE_PART, /* date_part function */ CF_DATETIME_PL_INTERVAL, /* date/timestamp/timestamptz + interval */ CF_DATETIME_MI_INTERVAL, /* date/timestamp/timestamptz - interval */ - CF_TIMEZONE, /* timezone */ CF_HSTORE_FETCHVAL, /* -> operation on hstore */ CF_RE2_MATCH, /* @~ re operation */ CF_INTARRAY_IDX, @@ -398,6 +403,7 @@ typedef enum { CF_CURRENT_SCHEMA, /* CF_CURRENT_SCHEMA → string literal */ CF_CLOCK_TIMESTAMP, /* clock_timestamp → nowInBlock64(6, $TZ) */ CF_TO_TIMESTAMP, /* to_timestamp → toDateTime64($arg, 6, 'UTC') */ + CF_DATE, /* date → toDate($arg, $TZ) */ CF_ARRAY_LENGTH, /* array_length(array, 1) → nullIf(length(), 0) */ CF_ARRAY_POSITION, /* array_position → nullIf(indexOf(), 0) */ CF_ARRAY_PREPEND, /* array_prepend → arrayPushFront, swap args */ diff --git a/src/pglink.c b/src/pglink.c index b187ea59..ffa62121 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -328,13 +328,11 @@ native_chunks_cancelled(void* ud pg_attribute_unused()) { } /* Room for every setting native_overrides writes. */ -#define NATIVE_OVERRIDES_MAX 3 +#define NATIVE_OVERRIDES_MAX 5 /* - * Settings the shared decoder needs from a Native response: the pair - * PGCH_NATIVE_SETTINGS joins, plus the format itself. Listed one by one - * because each needs its own server version gate; an unknown HTTP setting - * fails the query. + * Configure Native decoding and PostgreSQL datetime semantics. Unknown HTTP + * settings cause query errors, so check server versions before sending them. */ static int native_overrides(void* conn, ch_setting out[NATIVE_OVERRIDES_MAX]) { @@ -344,6 +342,8 @@ native_overrides(void* conn, ch_setting out[NATIVE_OVERRIDES_MAX]) { /* Format as a setting keeps SQL unchanged, so query parameters work. */ out[n++] = (ch_setting){ "default_format", "Native" }; + /* Preserve dates before 1970 in ClickHouse datetime functions. */ + out[n++] = (ch_setting){ "enable_extended_results_for_datetime_functions", "1" }; if (chfdw_version_ge(version, 24, 7)) { out[n++] = (ch_setting){ "output_format_native_encode_types_in_binary_format", "0" }; @@ -351,6 +351,10 @@ native_overrides(void* conn, ch_setting out[NATIVE_OVERRIDES_MAX]) { if (chfdw_version_ge(version, 24, 10)) { out[n++] = (ch_setting){ "output_format_native_write_json_as_string", "1" }; } + /* Interpret unzoned DateTime64 values in PostgreSQL TimeZone. */ + if (chfdw_version_ge(version, 23, 6)) { + out[n++] = (ch_setting){ "session_timezone", pgch_session_timezone() }; + } return n; } @@ -425,11 +429,17 @@ 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 POINTOID: + chfdw_append_point_literal(&buf, value); + return buf.data; case BOOLOID: case INT2OID: case INT4OID: @@ -437,9 +447,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: @@ -482,11 +494,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: { @@ -496,6 +507,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, @@ -667,12 +683,7 @@ binary_is_broken(const void* conn) { static ch_server_version binary_server_version(void* conn) { - ch_server_version v = { 0, 0, 0 }; - - ch_binary_server_version( - (ch_binary_connection_t*)conn, &v.major, &v.minor, &v.patch - ); - return v; + return ch_binary_server_version((ch_binary_connection_t*)conn); } static void 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/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 099f37b4..b6f7e808 100644 --- a/test/expected/functions.out +++ b/test/expected/functions.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -989,126 +1038,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1124,435 +1173,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1573,11 +1622,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 +1636,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 +1650,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 +1664,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); @@ -1645,8 +1694,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1660,8 +1709,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); SELECT * FROM t1 WHERE c < statement_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); @@ -1675,8 +1724,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); SELECT * FROM t1 WHERE c < transaction_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); SELECT * FROM t1 WHERE c < clock_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- Check SQL Value functions. @@ -1706,8 +1755,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1721,8 +1770,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1736,8 +1785,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1751,8 +1800,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1766,69 +1815,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1838,11 +1887,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; @@ -1946,7 +1995,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -2001,52 +2050,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2219,11 +2268,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 +2380,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 +2427,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 +2442,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; @@ -2780,11 +2829,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2797,11 +2846,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_0.out b/test/expected/functions_0.out index 76282643..a413bd9d 100644 --- a/test/expected/functions_0.out +++ b/test/expected/functions_0.out @@ -509,18 +509,19 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont ----------------- - 1546426260 + 1546397460 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FILTER (WHERE b = 1) FROM t1; @@ -566,18 +567,19 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont ------------------------------------ - {1546425720,1546426260,1546426692} + {1546396920,1546397460,1546397892} (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FILTER (WHERE b = 1) FROM t1; @@ -617,18 +619,19 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc ----------------- - 1546426800 + 1546398000 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FILTER (WHERE b = 1) FROM t1; @@ -674,18 +677,19 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc ------------------------------------ - {1546426800,1546426800,1546426800} + {1546398000,1546398000,1546398000} (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FILTER (WHERE b = 1) FROM t1; @@ -739,61 +743,81 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2018-12-31 00:00:00-08 + 2019-01-01 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ---- 1 - 2 + 31 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,30 +889,40 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2019-01-01 02:00:00-08 - 2019-01-02 02:00:00-08 - 2019-01-02 03:00:00-08 + 2018-12-31 18:00:00-08 + 2019-01-01 18:00:00-08 + 2019-01-01 19:00:00-08 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -985,11 +1034,11 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; @@ -999,11 +1048,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; @@ -1013,39 +1062,39 @@ SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- 2028-01-18 15:15:28 -(1 row) + 2029-02-18 17:16:29 +(2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - ts ---------------------- - 2025-10-15 13:12:25 -(1 row) + ts +---- +(0 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; @@ -1056,11 +1105,11 @@ SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; @@ -1070,11 +1119,11 @@ SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; @@ -1084,11 +1133,11 @@ SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; @@ -1096,15 +1145,16 @@ SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; --------------------- 2026-11-17 00:13:26 2028-01-18 15:15:28 -(2 rows) + 2030-03-19 19:16:30 +(3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,11 +1170,11 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; @@ -1136,11 +1186,11 @@ SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; @@ -1150,11 +1200,11 @@ SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; @@ -1164,27 +1214,26 @@ SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 2030-03-19 19:16:30 -(2 rows) +(1 row) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; @@ -1194,11 +1243,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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; @@ -1208,26 +1257,26 @@ 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2029-02-18 17:16:29 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; @@ -1237,11 +1286,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; @@ -1251,39 +1300,39 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- 2028-01-18 15:15:28 -(1 row) + 2029-02-18 17:16:29 +(2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - ts ---------------------- - 2025-10-15 13:12:25 -(1 row) + ts +---- +(0 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; @@ -1294,11 +1343,11 @@ SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; @@ -1308,11 +1357,11 @@ SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; @@ -1322,11 +1371,11 @@ SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; @@ -1334,14 +1383,15 @@ SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; --------------------- 2026-11-17 00:13:26 2028-01-18 15:15:28 -(2 rows) + 2030-03-19 19:16:30 +(3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; @@ -1353,11 +1403,11 @@ SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; @@ -1367,11 +1417,11 @@ SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; @@ -1381,27 +1431,26 @@ SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 2030-03-19 19:16:30 -(2 rows) +(1 row) -- 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 +1460,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 +1474,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; @@ -1440,11 +1489,11 @@ SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18; -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; @@ -1454,11 +1503,11 @@ SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; @@ -1468,11 +1517,11 @@ SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; @@ -1482,53 +1531,50 @@ SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - ts ---------------------- - 2029-02-18 17:16:29 -(1 row) + ts +---- +(0 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - ts ---------------------- - 2025-10-15 13:12:25 -(1 row) + ts +---- +(0 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - ts ---------------------- - 2027-12-17 14:14:27 -(1 row) + ts +---- +(0 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; @@ -1538,11 +1584,11 @@ SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; @@ -1569,11 +1615,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 +1629,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 +1643,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 +1657,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 +1802,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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); @@ -1773,11 +1819,11 @@ SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; @@ -1791,28 +1837,28 @@ SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAM -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1822,11 +1868,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; @@ -1974,11 +2020,11 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; @@ -1994,11 +2040,11 @@ SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; @@ -2015,11 +2061,11 @@ SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2189,16 +2235,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 +2342,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 +2389,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; @@ -2737,11 +2791,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2754,11 +2808,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_1.out b/test/expected/functions_1.out index 61ce3eff..51131563 100644 --- a/test/expected/functions_1.out +++ b/test/expected/functions_1.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -989,126 +1038,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1124,435 +1173,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1573,11 +1622,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 +1636,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 +1650,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 +1664,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); @@ -1645,8 +1694,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1660,8 +1709,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); SELECT * FROM t1 WHERE c < statement_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); @@ -1675,8 +1724,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); SELECT * FROM t1 WHERE c < transaction_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); SELECT * FROM t1 WHERE c < clock_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- Check SQL Value functions. @@ -1706,8 +1755,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1721,8 +1770,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1736,8 +1785,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1751,8 +1800,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1766,69 +1815,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1838,11 +1887,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; @@ -1946,7 +1995,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -2001,52 +2050,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2219,11 +2268,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 +2380,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 +2427,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 +2442,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; @@ -2780,11 +2829,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2797,11 +2846,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_2.out b/test/expected/functions_2.out index bb1e1674..9556da98 100644 --- a/test/expected/functions_2.out +++ b/test/expected/functions_2.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -989,126 +1038,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1124,435 +1173,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1573,11 +1622,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 +1636,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 +1650,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 +1664,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); @@ -1645,8 +1694,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1660,8 +1709,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); SELECT * FROM t1 WHERE c < statement_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); @@ -1675,8 +1724,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); SELECT * FROM t1 WHERE c < transaction_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); SELECT * FROM t1 WHERE c < clock_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- Check SQL Value functions. @@ -1706,8 +1755,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1721,8 +1770,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1736,8 +1785,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1751,8 +1800,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1766,69 +1815,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1838,11 +1887,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; @@ -1946,7 +1995,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -2001,52 +2050,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2219,11 +2268,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 +2380,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 +2427,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 +2442,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; @@ -2768,11 +2817,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2785,11 +2834,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_3.out b/test/expected/functions_3.out index 1657e75e..faad1d6d 100644 --- a/test/expected/functions_3.out +++ b/test/expected/functions_3.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -989,126 +1038,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1124,435 +1173,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1573,11 +1622,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 +1636,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 +1650,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 +1664,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); @@ -1645,8 +1694,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1660,8 +1709,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); SELECT * FROM t1 WHERE c < statement_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); @@ -1675,8 +1724,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); SELECT * FROM t1 WHERE c < transaction_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); SELECT * FROM t1 WHERE c < clock_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- Check SQL Value functions. @@ -1706,8 +1755,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1721,8 +1770,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1736,8 +1785,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1751,8 +1800,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1766,69 +1815,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1838,11 +1887,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; @@ -1946,7 +1995,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -2001,52 +2050,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2219,11 +2268,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 +2380,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 +2427,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 +2442,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; @@ -2768,11 +2817,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2785,11 +2834,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_5.out b/test/expected/functions_5.out index 1f3f692d..2d46ee9e 100644 --- a/test/expected/functions_5.out +++ b/test/expected/functions_5.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -985,126 +1034,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,435 +1169,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1569,11 +1618,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 +1632,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 +1646,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 +1660,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); @@ -1641,8 +1690,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1656,8 +1705,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); SELECT * FROM t1 WHERE c < statement_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); @@ -1671,8 +1720,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < transaction_timestamp(); SELECT * FROM t1 WHERE c < transaction_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); @@ -1686,8 +1735,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < clock_timestamp(); SELECT * FROM t1 WHERE c < clock_timestamp() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- Check SQL Value functions. @@ -1702,8 +1751,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1717,8 +1766,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1732,8 +1781,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1747,8 +1796,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1762,69 +1811,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1834,11 +1883,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; @@ -1942,7 +1991,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -1997,52 +2046,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2215,11 +2264,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 +2376,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 +2423,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 +2438,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; @@ -2776,11 +2825,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2793,11 +2842,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_6.out b/test/expected/functions_6.out index 44d5cdc2..f19c7282 100644 --- a/test/expected/functions_6.out +++ b/test/expected/functions_6.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -985,126 +1034,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,435 +1169,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1569,11 +1618,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 +1632,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 +1646,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 +1660,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); @@ -1641,8 +1690,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1705,8 +1754,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1720,8 +1769,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1735,8 +1784,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1750,69 +1799,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1822,11 +1871,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; @@ -1930,7 +1979,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -1985,52 +2034,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2203,11 +2252,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 +2364,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 +2411,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 +2426,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; @@ -2764,11 +2813,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2781,11 +2830,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_7.out b/test/expected/functions_7.out index c3de7d84..ea2b14cb 100644 --- a/test/expected/functions_7.out +++ b/test/expected/functions_7.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -985,126 +1034,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,435 +1169,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1569,11 +1618,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 +1632,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 +1646,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 +1660,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); @@ -1641,8 +1690,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1705,8 +1754,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1720,8 +1769,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1735,8 +1784,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1750,69 +1799,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1822,11 +1871,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; @@ -1930,7 +1979,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -1985,52 +2034,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2203,11 +2252,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 +2364,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 +2411,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 +2426,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; @@ -2764,11 +2813,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2781,11 +2830,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_8.out b/test/expected/functions_8.out index 0109be39..05df7996 100644 --- a/test/expected/functions_8.out +++ b/test/expected/functions_8.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -985,126 +1034,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,435 +1169,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1569,11 +1618,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 +1632,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 +1646,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 +1660,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); @@ -1641,8 +1690,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1705,8 +1754,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1720,8 +1769,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1735,8 +1784,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1750,69 +1799,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1822,11 +1871,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; @@ -1930,7 +1979,7 @@ SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:0 SELECT * FROM t1 WHERE concat_ws(',', a, b, 'foo', c) = '2,3,foo,2019-01-02 10:00:00'; a | b | c ---+---+--------------------- - 2 | 3 | 2019-01-02 02:00:00 + 2 | 3 | 2019-01-02 10:00:00 (1 row) -- Test fuzzystrmatch pushdown. @@ -1981,52 +2030,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2199,11 +2248,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 +2360,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 +2407,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 +2422,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; @@ -2760,11 +2809,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2777,11 +2826,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; diff --git a/test/expected/functions_9.out b/test/expected/functions_9.out index 467d1f2a..51d92c88 100644 --- a/test/expected/functions_9.out +++ b/test/expected/functions_9.out @@ -124,9 +124,9 @@ SELECT coalesce(a::text, b::text, c::text) FROM t1 GROUP BY a, b, c; coalesce ---------- 2 - 1 2 2 + 1 (4 rows) -- check IN functions @@ -509,13 +509,14 @@ SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantile(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -566,13 +567,14 @@ SELECT percentile_cont(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantiles(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_cont('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_cont(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_cont @@ -617,13 +619,14 @@ SELECT percentile_disc(0.25) WITHIN GROUP (ORDER BY a) FROM t1; (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantileExactLow(0.95)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('0.95'::double precision) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(0.95) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -674,13 +677,14 @@ SELECT percentile_disc(ARRAY[0.25, 0.5, 0.75]) WITHIN GROUP (ORDER BY a) FROM t1 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c))))) - Relations: Aggregate on (t1) - Remote SQL: SELECT quantilesExactLow(0.9,0.95,0.99)(toUnixTimestamp(toTimeZone(c, 'UTC'))) FROM functions_test.t1 -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------- + Aggregate + Output: percentile_disc('{0.9,0.95,0.99}'::double precision[]) WITHIN GROUP (ORDER BY (date_part('epoch'::text, timezone('UTC'::text, c)))) + -> Foreign Scan on public.t1 + Output: a, b, c + Remote SQL: SELECT c FROM functions_test.t1 +(5 rows) SELECT percentile_disc(ARRAY[0.9, 0.95, 0.99]) WITHIN GROUP (ORDER BY date_part('epoch', timezone('UTC', c))) FROM t1; percentile_disc @@ -739,45 +743,60 @@ SELECT local_ordered_count() WITHIN GROUP (ORDER BY a) FROM t1; DROP AGGREGATE local_ordered_count(integer); DROP FUNCTION local_ordered_sfunc(integer, integer); EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('dAy', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('dAy'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('dAy'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 ------------------------ - 2018-12-31 16:00:00-08 - 2019-01-01 16:00:00-08 + 2019-01-01 00:00:00-08 + 2019-01-02 00:00:00-08 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +----------------------------------------------------------------------------- + Sort Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toStartOfDay(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toStartOfDay(toTimeZone(c, 'UTC'))) ORDER BY toStartOfDay(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('day'::text, (t2.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t2 + Output: date_trunc('day'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('day', c at time zone 'UTC') as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 --------------------- - 2018-12-31 16:00:00 - 2019-01-01 16:00:00 + 2019-01-01 00:00:00 + 2019-01-02 00:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t1.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t1.c)) + -> Foreign Scan on public.t1 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -787,13 +806,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t1 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('day'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfMonth(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfMonth(toTimeZone(c, 'UTC'))) ORDER BY toDayOfMonth(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('day'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('day'::text, timezone('UTC'::text, c))) + Group Key: date_part('day'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('day'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -803,13 +827,18 @@ SELECT date_part('day'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('doy'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfYear(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toDayOfYear(toTimeZone(c, 'UTC'))) ORDER BY toDayOfYear(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('doy'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('doy'::text, timezone('UTC'::text, c))) + Group Key: date_part('doy'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('doy'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -819,13 +848,18 @@ SELECT date_part('doy'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +------------------------------------------------------------------------ + Sort Output: (date_part('dow'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toDayOfWeek(toTimeZone(c, 'UTC'), 2) FROM functions_test.t1 GROUP BY (toDayOfWeek(toTimeZone(c, 'UTC'), 2)) ORDER BY toDayOfWeek(toTimeZone(c, 'UTC'), 2) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('dow'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('dow'::text, timezone('UTC'::text, c))) + Group Key: date_part('dow'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('dow'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -835,13 +869,18 @@ SELECT date_part('dow'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +--------------------------------------------------------------------------- + Sort Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toMinute(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toMinute(toTimeZone(c, 'UTC'))) ORDER BY toMinute(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('minuTe'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('minuTe'::text, timezone('UTC'::text, c))) + Group Key: date_part('minuTe'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('minuTe'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 @@ -850,13 +889,18 @@ SELECT date_part('minuTe'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP B (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------------- + Sort Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) - Relations: Aggregate on (t1) - Remote SQL: SELECT toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) FROM functions_test.t1 GROUP BY (toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1))) ORDER BY toStartOfSecond(toDateTime64(toTimeZone(c, 'UTC'), 1)) ASC NULLS LAST -(4 rows) + Sort Key: (date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text))) + -> HashAggregate + Output: (date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text))) + Group Key: date_trunc('SeCond'::text, (t1.c AT TIME ZONE 'UTC'::text)) + -> Foreign Scan on public.t1 + Output: date_trunc('SeCond'::text, (c AT TIME ZONE 'UTC'::text)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDER BY d1; d1 @@ -867,20 +911,25 @@ SELECT date_trunc('SeCond', c at time zone 'UTC') as d1 FROM t1 GROUP BY d1 ORDE (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan + QUERY PLAN +-------------------------------------------------------------------------- + Sort Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) - Relations: Aggregate on (t2) - Remote SQL: SELECT toUnixTimestamp(toTimeZone(c, 'UTC')) FROM functions_test.t1 GROUP BY (toUnixTimestamp(toTimeZone(c, 'UTC'))) ORDER BY toUnixTimestamp(toTimeZone(c, 'UTC')) ASC NULLS LAST -(4 rows) + Sort Key: (date_part('ePoch'::text, timezone('UTC'::text, t2.c))) + -> HashAggregate + Output: (date_part('ePoch'::text, timezone('UTC'::text, c))) + Group Key: date_part('ePoch'::text, timezone('UTC'::text, t2.c)) + -> Foreign Scan on public.t2 + Output: date_part('ePoch'::text, timezone('UTC'::text, c)) + Remote SQL: SELECT c FROM functions_test.t1 +(9 rows) SELECT date_part('ePoch'::text, timezone('UTC'::text, c)) as d1 FROM t2 GROUP BY d1 ORDER BY d1; d1 ------------ - 1546336800 - 1546423200 - 1546426800 + 1546365600 + 1546452000 + 1546455600 (3 rows) -- Dynamic unit argument cannot push down, stays local. @@ -985,126 +1034,126 @@ SELECT a, dictGet('functions_test.t3_dict', 'val', (1, 'key' || a::text)) as val -- Check date_part mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts) = '2027'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts) = '11'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts) = '18'; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE date_part('hour', ts) = '20'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE date_part('minute', ts) = '16'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE date_part('second', ts) = '26'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE date_part('doy', ts) = '351'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE date_part('dow', ts) = '2'; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan Output: (date_part('dow'::text, ts)) Relations: Aggregate on (t8) - Remote SQL: SELECT toDayOfWeek(ts, 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(ts, 2)) ORDER BY toDayOfWeek(ts, 2) ASC NULLS LAST + Remote SQL: SELECT toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) FROM functions_test.t8 GROUP BY (toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2)) ORDER BY toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) ASC NULLS LAST (4 rows) SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; @@ -1120,435 +1169,435 @@ SELECT date_part('dow', ts) AS dow FROM t8 GROUP BY dow ORDER BY dow; (7 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE date_part('quarter', ts) = '1'; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE date_part('isoyear', ts) = '2025'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE date_part('week', ts) = '47'; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180'; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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(toDateTime64(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check EXTRACT mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(ts) = 2027)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2027)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts) = 2027; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; - QUERY PLAN ---------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(ts) = 11)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 11)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts) = 11; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(ts) = 18)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')) = 18)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts) = 18; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(ts) = 20)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 20)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(hour FROM ts) = 20; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(ts) = 16)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = 16)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(minute FROM ts) = 16; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toSecond(ts) = 26)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) = 26)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(second FROM ts) = 26; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(ts) = 351)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 351)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(doy FROM ts) = 351; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; - QUERY PLAN ---------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(ts, 2) = 2)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfWeek(toDateTime64(ts, 6, 'America/Los_Angeles'), 2) = 2)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(dow FROM ts) = 2; ts --------------------- - 2026-11-17 00:13:26 - 2028-01-18 15:15:28 + 2026-11-17 08:13:26 + 2028-01-18 23:15:28 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; - QUERY PLAN ----------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(ts) = 1)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')) = 1)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(quarter FROM ts) = 1; ts --------------------- - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(ts) = 2025)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOYear(toDateTime64(ts, 6, 'America/Los_Angeles')) = 2025)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(isoyear FROM ts) = 2025; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(ts) = 47)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toISOWeek(toDateTime64(ts, 6, 'America/Los_Angeles')) = 47)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(week FROM ts) = 47; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toUnixTimestamp(ts) > 1866158180)) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) > 1866158180)) (3 rows) SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180; ts --------------------- - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (2 rows) -- 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; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (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; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (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; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) -- Check date_trunc mappings. EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; - QUERY PLAN -------------------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfYear(ts) = '2026-01-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfYear(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2026-01-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('year', ts) = '2026-01-01'::date; ts --------------------- - 2026-11-17 00:13:26 + 2026-11-17 08:13:26 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; - QUERY PLAN --------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMonth(ts) = '2027-12-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-12-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('month', ts) = '2027-12-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; - QUERY PLAN ------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(ts) = '2028-01-18')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2028-01-18')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('day', ts) = '2028-01-18'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(ts) = '2029-02-19 01:00:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2029-02-19 01:00:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('hour', ts) = '2029-02-19T01:00:00'; ts --------------------- - 2029-02-18 17:16:29 + 2029-02-19 01:16:29 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; - QUERY PLAN ------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(ts) = '2025-10-15 20:12:00')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfMinute(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2025-10-15 20:12:00')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('minute', ts) = '2025-10-15T20:12:00'; ts --------------------- - 2025-10-15 13:12:25 + 2025-10-15 20:12:25 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 1)) = '2027-12-17 22:14:27')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) = '2027-12-17 22:14:27')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('second', ts) = '2027-12-17T22:14:27'; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; - QUERY PLAN --------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonday(ts) = '2028-01-17')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toMonday(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2028-01-17')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('week', ts) = '2028-01-17'::date; ts --------------------- - 2028-01-18 15:15:28 + 2028-01-18 23:15:28 (1 row) EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t5 Output: ts - Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toStartOfQuarter(ts) = '2027-10-01')) + Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDateTime64(toStartOfQuarter(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2027-10-01')) (3 rows) SELECT ts FROM t5 WHERE date_trunc('quarter', ts) = '2027-10-01'::date; ts --------------------- - 2027-12-17 14:14:27 + 2027-12-17 22:14:27 (1 row) -- Check hashing functions. @@ -1569,11 +1618,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 +1632,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 +1646,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 +1660,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); @@ -1641,8 +1690,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < NOW(); SELECT * FROM t1 WHERE c < NOW() ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < statement_timestamp(); @@ -1690,8 +1739,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_DATE; SELECT * FROM t1 WHERE c < CURRENT_DATE ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; @@ -1705,8 +1754,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP; SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); @@ -1720,8 +1769,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3); SELECT * FROM t1 WHERE c < CURRENT_TIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; @@ -1735,8 +1784,8 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP; SELECT * FROM t1 WHERE c < LOCALTIMESTAMP ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); @@ -1750,69 +1799,69 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3); SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 (2 rows) -- 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(toDateTime64(c, 6, 'America/Los_Angeles')) < toYear(toDateTime64(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'), 6, 'America/Los_Angeles')))) (3 rows) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE); a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a LIMIT 2; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 1 DAY))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '1 day' ORDER BY a; a | b | c ---+---+--------------------- - 1 | 1 | 2019-01-01 02:00:00 - 2 | 2 | 2019-01-02 02:00:00 - 2 | 2 | 2019-01-02 03:00:00 - 2 | 3 | 2019-01-02 02:00:00 + 1 | 1 | 2019-01-01 10:00:00 + 2 | 2 | 2019-01-02 10:00:00 + 2 | 2 | 2019-01-02 11:00:00 + 2 | 3 | 2019-01-02 10:00:00 (4 rows) -- Month and compound intervals push down as INTERVAL chains (issue #61). EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) < date_trunc('day', CURRENT_TIMESTAMP) - INTERVAL '6 months' ORDER BY a LIMIT 2; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) < (toStartOfDay(now64(6, 'America/Los_Angeles')) - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) < (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') - INTERVAL 6 MONTH))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_trunc('day', c) > date_trunc('day', CURRENT_TIMESTAMP) + INTERVAL '1 month 2 days 3 hours' ORDER BY a LIMIT 2; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b, c - Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(c) > (toStartOfDay(now64(6, 'America/Los_Angeles')) + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 + Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toStartOfDay(toDateTime64(c, 6, 'America/Los_Angeles')) > (toDateTime64(toStartOfDay(toDateTime64(now64(6, 'America/Los_Angeles'), 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') + INTERVAL 1 MONTH + INTERVAL 2 DAY + INTERVAL 10800 SECOND))) ORDER BY a ASC NULLS LAST LIMIT 2 (3 rows) -- Sub-second intervals keep microseconds, widening to DateTime64. EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a - Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6) + INTERVAL 500000 MICROSECOND) > c)) + Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(c, 6, 'America/Los_Angeles') + INTERVAL 500000 MICROSECOND) > c)) (3 rows) SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c; @@ -1822,11 +1871,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; @@ -1978,52 +2027,52 @@ DROP EXTENSION fuzzystrmatch; -- formatDateTime equivalent. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YYYY-MM-DD HH24:MI:SS'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%Y-%m-%d %H:%i:%S') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%Y-%m-%d %H:%i:%S') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YYYY-MM-DD HH24:MI:SS') FROM t5 ORDER BY 1; to_char --------------------- - 2025-10-15 13:12:25 - 2026-11-17 00:13:26 - 2027-12-17 14:14:27 - 2028-01-18 15:15:28 - 2029-02-18 17:16:29 - 2030-03-19 19:16:30 + 2025-10-15 20:12:25 + 2026-11-17 08:13:26 + 2027-12-17 22:14:27 + 2028-01-18 23:15:28 + 2029-02-19 01:16:29 + 2030-03-20 02:16:30 (6 rows) EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%y/%m/%d %I:%i %p %Q %j %b %a') ASC NULLS LAST (3 rows) SELECT to_char(ts, 'YY/MM/DD HH12:MI AM Q DDD Mon Dy') FROM t5 ORDER BY 1; to_char --------------------------------- - 25/10/15 01:12 PM 4 288 Oct Wed - 26/11/17 12:13 AM 4 321 Nov Tue - 27/12/17 02:14 PM 4 351 Dec Fri - 28/01/18 03:15 PM 1 018 Jan Tue - 29/02/18 05:16 PM 1 049 Feb Sun - 30/03/19 07:16 PM 1 078 Mar Tue + 25/10/15 08:12 PM 4 288 Oct Wed + 26/11/17 08:13 AM 4 321 Nov Tue + 27/12/17 10:14 PM 4 351 Dec Fri + 28/01/18 11:15 PM 1 018 Jan Tue + 29/02/19 01:16 AM 1 050 Feb Mon + 30/03/20 02:16 AM 1 079 Mar Wed (6 rows) -- Quoted literal text and a literal % round-trip via formatDateTime escaping. EXPLAIN (VERBOSE, COSTS OFF) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; - QUERY PLAN ----------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t5 Output: to_char(ts, '"Year=" YYYY "%"'::text) - Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(ts, 'Year= %Y %%') ASC NULLS LAST + Remote SQL: SELECT ts FROM functions_test.t5 ORDER BY formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), 'Year= %Y %%') ASC NULLS LAST (3 rows) SELECT to_char(ts, '"Year=" YYYY "%"') FROM t5 ORDER BY 1; @@ -2196,16 +2245,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 +2357,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 +2404,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; @@ -2744,11 +2806,11 @@ SELECT val FROM t4 WHERE reverse(val::bytea) = 'olleh'::bytea; -- date(timestamp) and date(timestamptz) push down as CH date (alias for toDate). EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t1 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'America/Los_Angeles')) = '2019-01-01')) (3 rows) SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; @@ -2761,11 +2823,11 @@ SELECT a, b FROM t1 WHERE date(c) = '2019-01-01'::date; SET timezone = 'UTC'; EXPLAIN (VERBOSE, COSTS OFF) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; - QUERY PLAN ------------------------------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------------------------------------------------------------- Foreign Scan on public.t2 Output: a, b - Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((date(c) = '2019-01-01')) + Remote SQL: SELECT a, b FROM functions_test.t1 WHERE ((toDate(toDateTime64(c, 6, 'UTC')) = '2019-01-01')) (3 rows) SELECT a, b FROM t2 WHERE date(c) = '2019-01-01'::date; 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/expected/import_schema.out b/test/expected/import_schema.out index 90cb2947..ab6de763 100644 --- a/test/expected/import_schema.out +++ b/test/expected/import_schema.out @@ -275,8 +275,8 @@ SELECT * FROM clickhouse.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; @@ -447,8 +447,8 @@ SELECT * FROM clickhouse_bin.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse_bin.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; diff --git a/test/expected/import_schema_1.out b/test/expected/import_schema_1.out index 622e1619..9121e70b 100644 --- a/test/expected/import_schema_1.out +++ b/test/expected/import_schema_1.out @@ -239,8 +239,8 @@ SELECT * FROM clickhouse.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; @@ -375,8 +375,8 @@ SELECT * FROM clickhouse_bin.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse_bin.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; diff --git a/test/expected/import_schema_2.out b/test/expected/import_schema_2.out index dd1528d1..1e8fb3b2 100644 --- a/test/expected/import_schema_2.out +++ b/test/expected/import_schema_2.out @@ -275,8 +275,8 @@ SELECT * FROM clickhouse.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; @@ -447,8 +447,8 @@ SELECT * FROM clickhouse_bin.tuples ORDER BY c1 LIMIT 2; SELECT * FROM clickhouse_bin.timezones ORDER BY t1 LIMIT 2; t1 | t2 | t4 | t5 ------------------------+------------------------+------------------------+------------------------ - 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 - 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 11:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 12:00:00-08 (2 rows) SELECT * FROM clickhouse.ip ORDER BY c1; diff --git a/test/expected/import_schema_3.out b/test/expected/import_schema_3.out new file mode 100644 index 00000000..dd1528d1 --- /dev/null +++ b/test/expected/import_schema_3.out @@ -0,0 +1,673 @@ +SET datestyle = 'ISO'; +CREATE SERVER import_loopback FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(dbname 'import_test', driver 'http'); +CREATE SERVER import_loopback_bin FOREIGN DATA WRAPPER clickhouse_fdw + OPTIONS(dbname 'import_test', driver 'binary'); +CREATE SCHEMA clickhouse; +CREATE SCHEMA clickhouse_bin; +CREATE SCHEMA clickhouse_limit; +CREATE SCHEMA clickhouse_except; +CREATE USER MAPPING FOR CURRENT_USER SERVER import_loopback; +CREATE USER MAPPING FOR CURRENT_USER SERVER import_loopback_bin; +CREATE SERVER import_admin FOREIGN DATA WRAPPER clickhouse_fdw; +CREATE USER MAPPING FOR CURRENT_USER SERVER import_admin; +CALL clickhouse_perform('import_admin', 'DROP DATABASE IF EXISTS import_test'); +CALL clickhouse_perform('import_admin', 'CREATE DATABASE import_test'); +CALL clickhouse_perform('import_admin', 'DROP DATABASE IF EXISTS import_test_2'); +CALL clickhouse_perform('import_admin', 'CREATE DATABASE import_test_2'); +-- numeric types +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.ints ( + c1 Int8, c2 Int16, c3 Int32, c4 Int64, + c5 UInt8, c6 UInt16, c7 UInt32, c8 UInt64, + c9 Float32, c10 Nullable(Float64) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.ints SELECT + number, number + 1, number + 2, number + 3, number + 4, number + 5, + number + 6, number + 7, number + 8.1, number + 9.2 FROM numbers(10);'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.ints SELECT + number, number + 1, number + 2, number + 3, number + 4, number + 5, + number + 6, number + 7, number + 8.1, NULL FROM numbers(10, 2);'); +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.types ( + c1 Date, c2 DateTime, c3 String, c4 FixedString(5), c5 UUID, + c6 Enum8(''one'' = 1, ''two'' = 2), + c7 Enum16(''one'' = 1, ''two'' = 2, ''three'' = 3), + c9 Nullable(FixedString(50)), + c8 LowCardinality(String) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.types SELECT + addDays(toDate(''1990-01-01''), number), + addMinutes(addSeconds(addDays(toDateTime(''1990-01-01 10:00:00'', ''UTC''), number), number), number), + format(''number {0}'', toString(number)), + format(''num {0}'', toString(number)), + format(''f4bf890f-f9dc-4332-ad5c-0c18e73f28e{0}'', toString(number)), + ''two'', + ''three'', + toString(number), + format(''cardinal {0}'', toString(number)) + FROM numbers(10);'); +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.types2 ( + c1 LowCardinality(Nullable(String)) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1) SETTINGS allow_nullable_key = 1; +'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.types2 SELECT + format(''cardinal {0}'', toString(number + 1)) + FROM numbers(10);'); +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.ip ( + c1 IPv4, + c2 IPv6 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); +CALL clickhouse_perform('import_admin', $$ + INSERT INTO import_test.ip VALUES + ('116.106.34.242', '2001:44c8:129:2632:33:0:252:2'), + ('116.106.34.243', '2a02:e980:1e::1'), + ('116.106.34.244', '::1'); +$$); +-- array types +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.arrays ( + c1 Array(Int), c2 Array(String) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.arrays SELECT + [number, number + 1], + [format(''num{0}'', toString(number)), format(''num{0}'', toString(number + 1))] + FROM numbers(10);'); +-- tuple +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.tuples ( + c1 Int8, + c2 Tuple(Int, String, Float32), + c3 Nested(a Int, b Int), + c4 Int16 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.tuples SELECT + number, + (number, toString(number), number + 1.0), + [toInt32(number),1,1], + [toInt32(number),2,2], + toInt16(number) + FROM numbers(10);'); +-- datetime with timezones +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test.timezones ( + t1 DateTime64(6,''UTC''), + t2 DateTime64(6,''Europe/Berlin''), + t4 DateTime(''Europe/Berlin''), + t5 DateTime64(6)) + ENGINE = MergeTree ORDER BY (t1) SETTINGS index_granularity=8192;'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.timezones VALUES ( + ''2020-01-01 11:00:00'', + ''2020-01-01 11:00:00'', + ''2020-01-01 11:00:00'', + ''2020-01-01 11:00:00'')'); +CALL clickhouse_perform('import_admin', 'INSERT INTO import_test.timezones VALUES ( + ''2020-01-01 12:00:00'', + ''2020-01-01 12:00:00'', + ''2020-01-01 12:00:00'', + ''2020-01-01 12:00:00'')'); +-- Injection attempt should import nothing. +IMPORT FOREIGN SCHEMA "import_test' OR database = 'public" FROM SERVER import_loopback INTO clickhouse; +\det clickhouse.* + List of foreign tables + Schema | Table | Server +--------+-------+-------- +(0 rows) + +-- Should succeed. +IMPORT FOREIGN SCHEMA import_test FROM SERVER import_loopback INTO clickhouse; +NOTICE: pg_clickhouse: ClickHouse type was translated to type for column "c2"; please create composite type and alter the column if needed +\d+ clickhouse.ints; + Foreign table "clickhouse.ints" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------------------+-----------+----------+---------+-------------+---------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | smallint | | not null | | | plain | | + c3 | integer | | not null | | | plain | | + c4 | bigint | | not null | | | plain | | + c5 | smallint | | not null | | | plain | | + c6 | integer | | not null | | | plain | | + c7 | bigint | | not null | | | plain | | + c8 | numeric(20,0) | | not null | | | main | | + c9 | real | | not null | | | plain | | + c10 | double precision | | | | | plain | | +Not-null constraints: + "ints_c1_not_null" NOT NULL "c1" + "ints_c2_not_null" NOT NULL "c2" + "ints_c3_not_null" NOT NULL "c3" + "ints_c4_not_null" NOT NULL "c4" + "ints_c5_not_null" NOT NULL "c5" + "ints_c6_not_null" NOT NULL "c6" + "ints_c7_not_null" NOT NULL "c7" + "ints_c8_not_null" NOT NULL "c8" + "ints_c9_not_null" NOT NULL "c9" +Server: import_loopback +FDW options: (database 'import_test', table_name 'ints', engine 'MergeTree') + +\d+ clickhouse.types; + Foreign table "clickhouse.types" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+--------------------------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | date | | not null | | | plain | | + c2 | timestamp with time zone | | not null | | | plain | | + c3 | text | | not null | | | extended | | + c4 | text | | not null | | | extended | | + c5 | uuid | | not null | | | plain | | + c6 | text | | not null | | | extended | | + c7 | text | | not null | | | extended | | + c9 | text | | | | | extended | | + c8 | text | | not null | | | extended | | +Not-null constraints: + "types_c1_not_null" NOT NULL "c1" + "types_c2_not_null" NOT NULL "c2" + "types_c3_not_null" NOT NULL "c3" + "types_c4_not_null" NOT NULL "c4" + "types_c5_not_null" NOT NULL "c5" + "types_c6_not_null" NOT NULL "c6" + "types_c7_not_null" NOT NULL "c7" + "types_c8_not_null" NOT NULL "c8" +Server: import_loopback +FDW options: (database 'import_test', table_name 'types', engine 'MergeTree') + +\d+ clickhouse.types2; + Foreign table "clickhouse.types2" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | text | | | | | extended | | +Server: import_loopback +FDW options: (database 'import_test', table_name 'types2', engine 'MergeTree') + +\d+ clickhouse.arrays; + Foreign table "clickhouse.arrays" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer[] | | not null | | | extended | | + c2 | text[] | | not null | | | extended | | +Not-null constraints: + "arrays_c1_not_null" NOT NULL "c1" + "arrays_c2_not_null" NOT NULL "c2" +Server: import_loopback +FDW options: (database 'import_test', table_name 'arrays', engine 'MergeTree') + +\d+ clickhouse.tuples; + Foreign table "clickhouse.tuples" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | text[] | | not null | | | extended | | + c3.a | integer[] | | not null | | | extended | | + c3.b | integer[] | | not null | | | extended | | + c4 | smallint | | not null | | | plain | | +Not-null constraints: + "tuples_c1_not_null" NOT NULL "c1" + "tuples_c2_not_null" NOT NULL "c2" + "tuples_c3.a_not_null" NOT NULL "c3.a" + "tuples_c3.b_not_null" NOT NULL "c3.b" + "tuples_c4_not_null" NOT NULL "c4" +Server: import_loopback +FDW options: (database 'import_test', table_name 'tuples', engine 'MergeTree') + +\d+ clickhouse.timezones; + Foreign table "clickhouse.timezones" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------------------------+-----------+----------+---------+-------------+---------+--------------+------------- + t1 | timestamp(6) with time zone | | not null | | | plain | | + t2 | timestamp(6) with time zone | | not null | | | plain | | + t4 | timestamp with time zone | | not null | | | plain | | + t5 | timestamp(6) with time zone | | not null | | | plain | | +Not-null constraints: + "timezones_t1_not_null" NOT NULL "t1" + "timezones_t2_not_null" NOT NULL "t2" + "timezones_t4_not_null" NOT NULL "t4" + "timezones_t5_not_null" NOT NULL "t5" +Server: import_loopback +FDW options: (database 'import_test', table_name 'timezones', engine 'MergeTree') + +\d+ clickhouse.ip; + Foreign table "clickhouse.ip" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------+-----------+----------+---------+-------------+---------+--------------+------------- + c1 | inet | | not null | | | main | | + c2 | inet | | not null | | | main | | +Not-null constraints: + "ip_c1_not_null" NOT NULL "c1" + "ip_c2_not_null" NOT NULL "c2" +Server: import_loopback +FDW options: (database 'import_test', table_name 'ip', engine 'MergeTree') + +SELECT * FROM clickhouse.ints ORDER BY c1 DESC LIMIT 4; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+------+------ + 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19.1 | + 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18.1 | + 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17.1 | 18.2 + 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16.1 | 17.2 +(4 rows) + +SELECT * FROM clickhouse.types ORDER BY c1 LIMIT 2; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c9 | c8 +------------+------------------------+----------+-------+--------------------------------------+-----+-------+----+------------ + 1990-01-01 | 1990-01-01 02:00:00-08 | number 0 | num 0 | f4bf890f-f9dc-4332-ad5c-0c18e73f28e0 | two | three | 0 | cardinal 0 + 1990-01-02 | 1990-01-02 02:01:01-08 | number 1 | num 1 | f4bf890f-f9dc-4332-ad5c-0c18e73f28e1 | two | three | 1 | cardinal 1 +(2 rows) + +SELECT * FROM clickhouse.types2 ORDER BY c1 LIMIT 2; + c1 +------------- + cardinal 1 + cardinal 10 +(2 rows) + +SELECT * FROM clickhouse.arrays ORDER BY c1 LIMIT 2; + c1 | c2 +-------+------------- + {0,1} | {num0,num1} + {1,2} | {num1,num2} +(2 rows) + +SELECT * FROM clickhouse.tuples ORDER BY c1 LIMIT 2; + c1 | c2 | c3.a | c3.b | c4 +----+---------+---------+---------+---- + 0 | {0,0,1} | {0,1,1} | {0,2,2} | 0 + 1 | {1,1,2} | {1,1,1} | {1,2,2} | 1 +(2 rows) + +SELECT * FROM clickhouse.timezones ORDER BY t1 LIMIT 2; + t1 | t2 | t4 | t5 +------------------------+------------------------+------------------------+------------------------ + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 +(2 rows) + +SELECT * FROM clickhouse.ip ORDER BY c1; + c1 | c2 +----------------+------------------------------- + 116.106.34.242 | 2001:44c8:129:2632:33:0:252:2 + 116.106.34.243 | 2a02:e980:1e::1 + 116.106.34.244 | ::1 +(3 rows) + +IMPORT FOREIGN SCHEMA "import_test" FROM SERVER import_loopback_bin INTO clickhouse_bin; +NOTICE: pg_clickhouse: ClickHouse type was translated to type for column "c2"; please create composite type and alter the column if needed +\d+ clickhouse_bin.ints; + Foreign table "clickhouse_bin.ints" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------------------+-----------+----------+---------+-------------+---------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | smallint | | not null | | | plain | | + c3 | integer | | not null | | | plain | | + c4 | bigint | | not null | | | plain | | + c5 | smallint | | not null | | | plain | | + c6 | integer | | not null | | | plain | | + c7 | bigint | | not null | | | plain | | + c8 | numeric(20,0) | | not null | | | main | | + c9 | real | | not null | | | plain | | + c10 | double precision | | | | | plain | | +Not-null constraints: + "ints_c1_not_null" NOT NULL "c1" + "ints_c2_not_null" NOT NULL "c2" + "ints_c3_not_null" NOT NULL "c3" + "ints_c4_not_null" NOT NULL "c4" + "ints_c5_not_null" NOT NULL "c5" + "ints_c6_not_null" NOT NULL "c6" + "ints_c7_not_null" NOT NULL "c7" + "ints_c8_not_null" NOT NULL "c8" + "ints_c9_not_null" NOT NULL "c9" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'ints', engine 'MergeTree') + +\d+ clickhouse_bin.types; + Foreign table "clickhouse_bin.types" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+--------------------------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | date | | not null | | | plain | | + c2 | timestamp with time zone | | not null | | | plain | | + c3 | text | | not null | | | extended | | + c4 | text | | not null | | | extended | | + c5 | uuid | | not null | | | plain | | + c6 | text | | not null | | | extended | | + c7 | text | | not null | | | extended | | + c9 | text | | | | | extended | | + c8 | text | | not null | | | extended | | +Not-null constraints: + "types_c1_not_null" NOT NULL "c1" + "types_c2_not_null" NOT NULL "c2" + "types_c3_not_null" NOT NULL "c3" + "types_c4_not_null" NOT NULL "c4" + "types_c5_not_null" NOT NULL "c5" + "types_c6_not_null" NOT NULL "c6" + "types_c7_not_null" NOT NULL "c7" + "types_c8_not_null" NOT NULL "c8" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'types', engine 'MergeTree') + +\d+ clickhouse_bin.types2; + Foreign table "clickhouse_bin.types2" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | text | | | | | extended | | +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'types2', engine 'MergeTree') + +\d+ clickhouse_bin.arrays; + Foreign table "clickhouse_bin.arrays" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer[] | | not null | | | extended | | + c2 | text[] | | not null | | | extended | | +Not-null constraints: + "arrays_c1_not_null" NOT NULL "c1" + "arrays_c2_not_null" NOT NULL "c2" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'arrays', engine 'MergeTree') + +\d+ clickhouse_bin.tuples; + Foreign table "clickhouse_bin.tuples" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | text[] | | not null | | | extended | | + c3.a | integer[] | | not null | | | extended | | + c3.b | integer[] | | not null | | | extended | | + c4 | smallint | | not null | | | plain | | +Not-null constraints: + "tuples_c1_not_null" NOT NULL "c1" + "tuples_c2_not_null" NOT NULL "c2" + "tuples_c3.a_not_null" NOT NULL "c3.a" + "tuples_c3.b_not_null" NOT NULL "c3.b" + "tuples_c4_not_null" NOT NULL "c4" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'tuples', engine 'MergeTree') + +\d+ clickhouse_bin.timezones; + Foreign table "clickhouse_bin.timezones" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------------------------+-----------+----------+---------+-------------+---------+--------------+------------- + t1 | timestamp(6) with time zone | | not null | | | plain | | + t2 | timestamp(6) with time zone | | not null | | | plain | | + t4 | timestamp with time zone | | not null | | | plain | | + t5 | timestamp(6) with time zone | | not null | | | plain | | +Not-null constraints: + "timezones_t1_not_null" NOT NULL "t1" + "timezones_t2_not_null" NOT NULL "t2" + "timezones_t4_not_null" NOT NULL "t4" + "timezones_t5_not_null" NOT NULL "t5" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'timezones', engine 'MergeTree') + +\d+ clickhouse_bin.ip; + Foreign table "clickhouse_bin.ip" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------+-----------+----------+---------+-------------+---------+--------------+------------- + c1 | inet | | not null | | | main | | + c2 | inet | | not null | | | main | | +Not-null constraints: + "ip_c1_not_null" NOT NULL "c1" + "ip_c2_not_null" NOT NULL "c2" +Server: import_loopback_bin +FDW options: (database 'import_test', table_name 'ip', engine 'MergeTree') + +SELECT * FROM clickhouse_bin.ints ORDER BY c1 DESC LIMIT 4; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+------+------ + 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19.1 | + 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18.1 | + 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17.1 | 18.2 + 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16.1 | 17.2 +(4 rows) + +SELECT * FROM clickhouse_bin.types ORDER BY c1 LIMIT 2; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c9 | c8 +------------+------------------------+----------+-------+--------------------------------------+-----+-------+----+------------ + 1990-01-01 | 1990-01-01 02:00:00-08 | number 0 | num 0 | f4bf890f-f9dc-4332-ad5c-0c18e73f28e0 | two | three | 0 | cardinal 0 + 1990-01-02 | 1990-01-02 02:01:01-08 | number 1 | num 1 | f4bf890f-f9dc-4332-ad5c-0c18e73f28e1 | two | three | 1 | cardinal 1 +(2 rows) + +SELECT * FROM clickhouse_bin.types2 ORDER BY c1 LIMIT 2; + c1 +------------- + cardinal 1 + cardinal 10 +(2 rows) + +SELECT * FROM clickhouse_bin.arrays ORDER BY c1 LIMIT 2; + c1 | c2 +-------+------------- + {0,1} | {num0,num1} + {1,2} | {num1,num2} +(2 rows) + +SELECT * FROM clickhouse_bin.tuples ORDER BY c1 LIMIT 2; + c1 | c2 | c3.a | c3.b | c4 +----+---------+---------+---------+---- + 0 | {0,0,1} | {0,1,1} | {0,2,2} | 0 + 1 | {1,1,2} | {1,1,1} | {1,2,2} | 1 +(2 rows) + +SELECT * FROM clickhouse_bin.timezones ORDER BY t1 LIMIT 2; + t1 | t2 | t4 | t5 +------------------------+------------------------+------------------------+------------------------ + 2020-01-01 03:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 02:00:00-08 | 2020-01-01 03:00:00-08 + 2020-01-01 04:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 03:00:00-08 | 2020-01-01 04:00:00-08 +(2 rows) + +SELECT * FROM clickhouse.ip ORDER BY c1; + c1 | c2 +----------------+------------------------------- + 116.106.34.242 | 2001:44c8:129:2632:33:0:252:2 + 116.106.34.243 | 2a02:e980:1e::1 + 116.106.34.244 | ::1 +(3 rows) + +IMPORT FOREIGN SCHEMA "import_test" LIMIT TO (ints, types) FROM SERVER import_loopback INTO clickhouse_limit; +\d+ clickhouse_limit.ints; + Foreign table "clickhouse_limit.ints" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+------------------+-----------+----------+---------+-------------+---------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | smallint | | not null | | | plain | | + c3 | integer | | not null | | | plain | | + c4 | bigint | | not null | | | plain | | + c5 | smallint | | not null | | | plain | | + c6 | integer | | not null | | | plain | | + c7 | bigint | | not null | | | plain | | + c8 | numeric(20,0) | | not null | | | main | | + c9 | real | | not null | | | plain | | + c10 | double precision | | | | | plain | | +Not-null constraints: + "ints_c1_not_null" NOT NULL "c1" + "ints_c2_not_null" NOT NULL "c2" + "ints_c3_not_null" NOT NULL "c3" + "ints_c4_not_null" NOT NULL "c4" + "ints_c5_not_null" NOT NULL "c5" + "ints_c6_not_null" NOT NULL "c6" + "ints_c7_not_null" NOT NULL "c7" + "ints_c8_not_null" NOT NULL "c8" + "ints_c9_not_null" NOT NULL "c9" +Server: import_loopback +FDW options: (database 'import_test', table_name 'ints', engine 'MergeTree') + +\d+ clickhouse_limit.types; + Foreign table "clickhouse_limit.types" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+--------------------------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | date | | not null | | | plain | | + c2 | timestamp with time zone | | not null | | | plain | | + c3 | text | | not null | | | extended | | + c4 | text | | not null | | | extended | | + c5 | uuid | | not null | | | plain | | + c6 | text | | not null | | | extended | | + c7 | text | | not null | | | extended | | + c9 | text | | | | | extended | | + c8 | text | | not null | | | extended | | +Not-null constraints: + "types_c1_not_null" NOT NULL "c1" + "types_c2_not_null" NOT NULL "c2" + "types_c3_not_null" NOT NULL "c3" + "types_c4_not_null" NOT NULL "c4" + "types_c5_not_null" NOT NULL "c5" + "types_c6_not_null" NOT NULL "c6" + "types_c7_not_null" NOT NULL "c7" + "types_c8_not_null" NOT NULL "c8" +Server: import_loopback +FDW options: (database 'import_test', table_name 'types', engine 'MergeTree') + +\d+ clickhouse_limit.arrays; +\d+ clickhouse_limit.tuples; +IMPORT FOREIGN SCHEMA "import_test" EXCEPT (ints, types) FROM SERVER import_loopback INTO clickhouse_except; +NOTICE: pg_clickhouse: ClickHouse type was translated to type for column "c2"; please create composite type and alter the column if needed +\d+ clickhouse_except.ints; +\d+ clickhouse_except.types; +\d+ clickhouse_except.arrays; + Foreign table "clickhouse_except.arrays" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer[] | | not null | | | extended | | + c2 | text[] | | not null | | | extended | | +Not-null constraints: + "arrays_c1_not_null" NOT NULL "c1" + "arrays_c2_not_null" NOT NULL "c2" +Server: import_loopback +FDW options: (database 'import_test', table_name 'arrays', engine 'MergeTree') + +\d+ clickhouse_except.tuples; + Foreign table "clickhouse_except.tuples" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+-----------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | smallint | | not null | | | plain | | + c2 | text[] | | not null | | | extended | | + c3.a | integer[] | | not null | | | extended | | + c3.b | integer[] | | not null | | | extended | | + c4 | smallint | | not null | | | plain | | +Not-null constraints: + "tuples_c1_not_null" NOT NULL "c1" + "tuples_c2_not_null" NOT NULL "c2" + "tuples_c3.a_not_null" NOT NULL "c3.a" + "tuples_c3.b_not_null" NOT NULL "c3.b" + "tuples_c4_not_null" NOT NULL "c4" +Server: import_loopback +FDW options: (database 'import_test', table_name 'tuples', engine 'MergeTree') + +-- check custom database +CALL clickhouse_perform('import_admin', 'CREATE TABLE import_test_2.custom_option (a Int64) ENGINE = MergeTree ORDER BY (a)'); +IMPORT FOREIGN SCHEMA "import_test_2" FROM SERVER import_loopback INTO clickhouse; +EXPLAIN VERBOSE SELECT * FROM clickhouse.custom_option; + QUERY PLAN +--------------------------------------------------------------------------------- + Foreign Scan on clickhouse.custom_option (cost=10.00..20.00 rows=1000 width=8) + Output: a + Remote SQL: SELECT a FROM import_test_2.custom_option +(3 rows) + +ALTER FOREIGN TABLE clickhouse.custom_option OPTIONS (DROP database); +EXPLAIN VERBOSE SELECT * FROM clickhouse.custom_option; + QUERY PLAN +--------------------------------------------------------------------------------- + Foreign Scan on clickhouse.custom_option (cost=10.00..20.00 rows=1000 width=8) + Output: a + Remote SQL: SELECT a FROM import_test.custom_option +(3 rows) + +-- check overflows. +CALL clickhouse_perform('import_admin', $$ + INSERT INTO import_test.ints (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) VALUES + ( + -- Min values + -128, -32768, -2147483648, -9223372036854775808, + 0, 0, 0, 0, + 1.175494351e-38, 2.2250738585072014e-308 + ), + ( + -- Max values + 127, 32767, 2147483647, 9223372036854775807, + 255, 65535, 4294967295, 18446744073709551615, + 3.402823466e+38, 1.7976931348623158e+308 + ) +$$); +SELECT * FROM clickhouse_query('import_admin', $$ + SELECT c1, c2, c3, c4, c5, c6, c7, c9, c10 + FROM import_test.ints + WHERE c1 IN (127, -128) + ORDER BY c1; +$$) AS t(c1 text, c2 text, c3 text, c4 text, c5 text, + c6 text, c7 text, c9 text, c10 text); + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c9 | c10 +------+--------+-------------+----------------------+-----+-------+------------+---------------+------------------------- + -128 | -32768 | -2147483648 | -9223372036854775808 | 0 | 0 | 0 | 1.1754942e-38 | 2.2250738585072014e-308 + 127 | 32767 | 2147483647 | 9223372036854775807 | 255 | 65535 | 4294967295 | 3.4028233e+38 | 1.7976931348623157e+308 +(2 rows) + +-- Read 18446744073709551615. +SELECT * FROM clickhouse_bin.ints +WHERE c1 IN (127, -128) +ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +------+--------+-------------+----------------------+-----+-------+------------+----------------------+---------------+------------------------- + -128 | -32768 | -2147483648 | -9223372036854775808 | 0 | 0 | 0 | 0 | 1.1754942e-38 | 2.2250738585072014e-308 + 127 | 32767 | 2147483647 | 9223372036854775807 | 255 | 65535 | 4294967295 | 18446744073709551615 | 3.4028233e+38 | 1.7976931348623157e+308 +(2 rows) + +SELECT * FROM clickhouse.ints +WHERE c1 IN (127, -128) +ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +------+--------+-------------+----------------------+-----+-------+------------+----------------------+---------------+------------------------- + -128 | -32768 | -2147483648 | -9223372036854775808 | 0 | 0 | 0 | 0 | 1.1754942e-38 | 2.2250738585072014e-308 + 127 | 32767 | 2147483647 | 9223372036854775807 | 255 | 65535 | 4294967295 | 18446744073709551615 | 3.4028233e+38 | 1.7976931348623157e+308 +(2 rows) + +-- Ignore 18446744073709551615 +SELECT * FROM clickhouse_bin.ints WHERE c1 = -128 +UNION +SELECT c1, c2, c3, c4, c5, c6, c7, NULL, c9, c10 +FROM clickhouse_bin.ints +WHERE c1 = 127 +ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +------+--------+-------------+----------------------+-----+-------+------------+----+---------------+------------------------- + -128 | -32768 | -2147483648 | -9223372036854775808 | 0 | 0 | 0 | 0 | 1.1754942e-38 | 2.2250738585072014e-308 + 127 | 32767 | 2147483647 | 9223372036854775807 | 255 | 65535 | 4294967295 | | 3.4028233e+38 | 1.7976931348623157e+308 +(2 rows) + +SELECT * FROM clickhouse.ints WHERE c1 = -128 +UNION +SELECT c1, c2, c3, c4, c5, c6, c7, NULL, c9, c10 +FROM clickhouse.ints +WHERE c1 = 127 +ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +------+--------+-------------+----------------------+-----+-------+------------+----+---------------+------------------------- + -128 | -32768 | -2147483648 | -9223372036854775808 | 0 | 0 | 0 | 0 | 1.1754942e-38 | 2.2250738585072014e-308 + 127 | 32767 | 2147483647 | 9223372036854775807 | 255 | 65535 | 4294967295 | | 3.4028233e+38 | 1.7976931348623157e+308 +(2 rows) + +DROP USER MAPPING FOR CURRENT_USER SERVER import_loopback; +DROP USER MAPPING FOR CURRENT_USER SERVER import_loopback_bin; +CALL clickhouse_perform('import_admin', 'DROP DATABASE import_test'); +CALL clickhouse_perform('import_admin', 'DROP DATABASE import_test_2'); +DROP SERVER import_loopback_bin CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to foreign table clickhouse_bin.arrays +drop cascades to foreign table clickhouse_bin.ints +drop cascades to foreign table clickhouse_bin.ip +drop cascades to foreign table clickhouse_bin.timezones +drop cascades to foreign table clickhouse_bin.tuples +drop cascades to foreign table clickhouse_bin.types +drop cascades to foreign table clickhouse_bin.types2 +DROP SERVER import_loopback CASCADE; +NOTICE: drop cascades to 15 other objects +DETAIL: drop cascades to foreign table clickhouse.arrays +drop cascades to foreign table clickhouse.ints +drop cascades to foreign table clickhouse.ip +drop cascades to foreign table clickhouse.timezones +drop cascades to foreign table clickhouse.tuples +drop cascades to foreign table clickhouse.types +drop cascades to foreign table clickhouse.types2 +drop cascades to foreign table clickhouse_limit.ints +drop cascades to foreign table clickhouse_limit.types +drop cascades to foreign table clickhouse_except.arrays +drop cascades to foreign table clickhouse_except.ip +drop cascades to foreign table clickhouse_except.timezones +drop cascades to foreign table clickhouse_except.tuples +drop cascades to foreign table clickhouse_except.types2 +drop cascades to foreign table clickhouse.custom_option diff --git a/test/expected/interval.out b/test/expected/interval.out index 478e7b4a..c4fade9e 100644 --- a/test/expected/interval.out +++ b/test/expected/interval.out @@ -108,11 +108,11 @@ SELECT id, base + nanos FROM ival_bin.intervals WHERE base + nanos > base ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on ival_bin.intervals Output: id, (base + nanos) - Remote SQL: SELECT id, base, nanos FROM interval_test.intervals WHERE (((base + nanos) > base)) ORDER BY id ASC NULLS LAST + Remote SQL: SELECT id, base, nanos FROM interval_test.intervals WHERE (((toDateTime64(base, 6, 'America/Los_Angeles') + nanos) > base)) ORDER BY id ASC NULLS LAST (3 rows) SELECT id, base + nanos @@ -132,11 +132,11 @@ EXPLAIN (verbose, COSTS OFF) FROM ival_bin.intervals WHERE base - nanos < base ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Foreign Scan on ival_bin.intervals Output: id, (base - nanos) - Remote SQL: SELECT id, base, nanos FROM interval_test.intervals WHERE (((base - nanos) < base)) ORDER BY id ASC NULLS LAST + Remote SQL: SELECT id, base, nanos FROM interval_test.intervals WHERE (((toDateTime64(base, 6, 'America/Los_Angeles') - nanos) < base)) ORDER BY id ASC NULLS LAST (3 rows) SELECT id, base - nanos diff --git a/test/expected/param.out b/test/expected/param.out index 72439efc..9ecc9927 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 -- =================================================================== @@ -97,12 +112,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) 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,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -326,6 +513,14 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -387,12 +582,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -411,12 +606,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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +803,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -616,14 +983,24 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +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; -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..34bed5be 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 -- =================================================================== @@ -97,12 +112,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) 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,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -326,6 +513,14 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -387,12 +582,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -411,12 +606,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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +803,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -616,14 +983,24 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +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; -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..1d5773ff 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 -- =================================================================== @@ -97,12 +112,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) 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,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -326,6 +513,14 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables -- =================================================================== @@ -387,12 +582,12 @@ SET enable_sort TO off; -- subquery using stable function (can't be sent to remote, but is?) PREPARE st2(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(c4) = date('1970-01-17')) ORDER BY c1; EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(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.c4) = '1970-01-17')) 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 ((toDate(toDateTime64(r3.c4, 6, 'America/Los_Angeles')) = '1970-01-17')) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st2(10, 20); @@ -411,12 +606,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 ((toDate(toDateTime64(r3.c5, 6, 'America/Los_Angeles')) = toDate(toDateTime64(cast('1970-01-17 08:00:00' as DateTime64(6, 'UTC')), 6, 'America/Los_Angeles')))) AND ((r1.c3 = r3.c3))) WHERE ((r1.c1 < 20)) ORDER BY r1.c1 ASC NULLS LAST (4 rows) EXECUTE st3(10, 20); @@ -608,6 +803,178 @@ 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) + +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, 'America/Los_Angeles') + 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) + +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; DEALLOCATE st2; @@ -616,14 +983,24 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +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; -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/result_map.txt b/test/expected/result_map.txt index 8f4e2e5b..1a496ec3 100644 --- a/test/expected/result_map.txt +++ b/test/expected/result_map.txt @@ -206,7 +206,8 @@ import_schema.sql ClickHouse | File ------------|--------------------- 26.7+ | import_schema.out - 23.3-26.6 | import_schema_2.out + 23.6-26.6 | import_schema_2.out + 23.3-23.5 | import_schema_3.out interval.sql ------------ @@ -286,6 +287,15 @@ regex.sql 25+ | regex.out 23-24 | regex_1.out +session_timezone.sql +-------------------- + + ClickHouse | File +------------|-------------------------- + 26.3+ | session_timezone.out + 23.6-26.2 | session_timezone_1.out + 23.3-23.5 | session_timezone_2.out + subplan_pushdown.sql -------------------- diff --git a/test/expected/session_timezone.out b/test/expected/session_timezone.out new file mode 100644 index 00000000..cdd5df5f --- /dev/null +++ b/test/expected/session_timezone.out @@ -0,0 +1,517 @@ +SET datestyle = 'ISO'; +CREATE SERVER stz_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'binary'); +CREATE SERVER stz_http_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +CREATE SERVER stz_admin FOREIGN DATA WRAPPER clickhouse_fdw; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_admin; +\set ECHO errors +CALL clickhouse_perform('stz_admin', 'DROP DATABASE IF EXISTS stz_test'); +CALL clickhouse_perform('stz_admin', 'CREATE DATABASE stz_test'); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.wall (id Int, ts DateTime64(6)) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.utc (id Int, ts DateTime('UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.day (id Int, d Date, ts DateTime64(6, 'UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.day VALUES + (1, '2020-03-07', '2020-03-07 10:00:05.25'), + (2, '2020-07-01', '1969-12-31 23:59:58.75') +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.utc + SELECT number, addMonths(toDateTime('2020-01-01 10:00:00', 'UTC'), number * 3) + FROM numbers(4) +$$); +CREATE FOREIGN TABLE stz_bin_wall (id int, ts timestamp) + SERVER stz_bin_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_http_wall (id int, ts timestamp) + SERVER stz_http_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_bin_utc (id int, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_http_utc (id int, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_bin_day (id int, d timestamp, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'day'); +CREATE FOREIGN TABLE stz_http_day (id int, d timestamp, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'day'); +-- Verify unzoned DateTime64 literals use PostgreSQL TimeZone. +SET timezone = 'America/Los_Angeles'; +INSERT INTO stz_bin_wall VALUES (1, '2024-07-01 12:00'); +INSERT INTO stz_http_wall VALUES (2, '2024-07-01 12:00'); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.wall VALUES (3, '2024-07-01 12:00:00') +$$); +SELECT * FROM clickhouse_query('stz_admin', $$ + SELECT id FROM stz_test.wall WHERE ts = '2024-07-01 12:00:00' ORDER BY id +$$) AS t(id int); + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT * FROM stz_bin_wall ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 12:00:00 + 2 | 2024-07-01 12:00:00 + 3 | 2024-07-01 12:00:00 +(3 rows) + +SELECT * FROM stz_http_wall ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 12:00:00 + 2 | 2024-07-01 12:00:00 + 3 | 2024-07-01 12:00:00 +(3 rows) + +-- Verify pushed down literals and functions match local evaluation. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_wall + Output: id + Remote SQL: SELECT id FROM stz_test.wall WHERE ((ts = '2024-07-01 12:00:00')) AND ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 12)) +(3 rows) + +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_http_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +-- Execute six times to test parameters with generic plans. +PREPARE prep_bin(timestamp) AS SELECT id FROM stz_bin_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +DEALLOCATE prep_bin; +PREPARE prep_http(timestamp) AS SELECT id FROM stz_http_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +DEALLOCATE prep_http; +-- Read same instants as Tokyo wall clock times. Before ClickHouse 26.3, +-- literals use time zone unzoned columns had when table loaded +\if :ch263 +SET timezone = 'Asia/Tokyo'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-02 04:00:00 + 2 | 2024-07-02 04:00:00 + 3 | 2024-07-02 04:00:00 +(3 rows) + +SELECT * FROM stz_http_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-02 04:00:00 + 2 | 2024-07-02 04:00:00 + 3 | 2024-07-02 04:00:00 +(3 rows) + +-- Verify fixed offsets map to ClickHouse Fixed/UTC zones. +SET timezone = '+05:30'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 13:30:00 + 2 | 2024-07-01 13:30:00 + 3 | 2024-07-01 13:30:00 +(3 rows) + +SELECT * FROM stz_http_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 13:30:00 + 2 | 2024-07-01 13:30:00 + 3 | 2024-07-01 13:30:00 +(3 rows) + +\endif +-- Verify explicit UTC columns use PostgreSQL TimeZone across DST. +SET timezone = 'America/Los_Angeles'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (date_trunc('day'::text, ts)), (to_char(ts, 'HH24'::text)), (count(*)) + Relations: Aggregate on (stz_bin_utc) + Remote SQL: SELECT toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')), formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%H'), count(*) FROM stz_test.utc WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 3)) GROUP BY (toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles'))), (formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%H')) ORDER BY toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) ASC NULLS LAST +(4 rows) + +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + d | h | count +------------------------+----+------- + 2020-04-01 00:00:00-07 | 03 | 1 + 2020-07-01 00:00:00-07 | 03 | 1 + 2020-10-01 00:00:00-07 | 03 | 1 +(3 rows) + +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_http_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + d | h | count +------------------------+----+------- + 2020-04-01 00:00:00-07 | 03 | 1 + 2020-07-01 00:00:00-07 | 03 | 1 + 2020-10-01 00:00:00-07 | 03 | 1 +(3 rows) + +SELECT id, ts, date_part('hour', ts) FROM stz_bin_utc ORDER BY id; + id | ts | date_part +----+------------------------+----------- + 0 | 2020-01-01 02:00:00-08 | 2 + 1 | 2020-04-01 03:00:00-07 | 3 + 2 | 2020-07-01 03:00:00-07 | 3 + 3 | 2020-10-01 03:00:00-07 | 3 +(4 rows) + +-- Verify interval arithmetic preserves 02:00 across PST and PDT. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id + Remote SQL: SELECT id FROM stz_test.utc WHERE (((toDateTime64(ts, 6, 'America/Los_Angeles') + INTERVAL 3 MONTH) = cast('2020-04-01 09:00:00' as DateTime64(6, 'UTC')))) +(3 rows) + +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + id +---- + 0 +(1 row) + +SELECT id FROM stz_http_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + id +---- + 0 +(1 row) + +PREPARE prep_iv(interval) AS SELECT id FROM stz_bin_utc WHERE ts + $1 = '2020-04-01 02:00'; +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +DEALLOCATE prep_iv; +-- Verify epoch extraction interprets timestamp wall clock times as UTC. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_wall + Output: id + Remote SQL: SELECT id FROM stz_test.wall WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) = 1719835200)) +(3 rows) + +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_http_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_bin_utc WHERE extract(epoch FROM ts) = 1577872800; + id +---- + 0 +(1 row) + +-- Verify timezone() evaluates locally. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10; + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id + Filter: (date_part('hour'::text, (stz_bin_utc.ts AT TIME ZONE 'UTC'::text)) = '10'::double precision) + Remote SQL: SELECT id, ts FROM stz_test.utc +(4 rows) + +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10 ORDER BY id; + id +---- + 0 + 1 + 2 + 3 +(4 rows) + +-- Verify second and epoch extraction preserve microseconds before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id, date_part('second'::text, ts), EXTRACT(epoch FROM ts) + Remote SQL: SELECT id, ts FROM stz_test.day WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) > 5)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; + id | date_part | extract +----+-----------+------------------- + 1 | 5.25 | 1583575205.250000 + 2 | 58.75 | -1.250000 +(2 rows) + +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_http_day + WHERE date_part('second', ts) > 5 ORDER BY id; + id | date_part | extract +----+-----------+------------------- + 1 | 5.25 | 1583575205.250000 + 2 | 58.75 | -1.250000 +(2 rows) + +-- Verify date_trunc supports dates before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id + Remote SQL: SELECT id FROM stz_test.day WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = cast('1969-12-01 08:00:00' as DateTime64(6, 'UTC')))) AND ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = cast('1969-12-31 23:00:00' as DateTime64(6, 'UTC')))) +(3 rows) + +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + id +---- + 2 +(1 row) + +SELECT id FROM stz_http_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + id +---- + 2 +(1 row) + +-- Verify Date mapped to timestamp uses midnight and supports day arithmetic. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id, d + Remote SQL: SELECT id, d FROM stz_test.day WHERE ((toDateTime64(toStartOfMonth(toDateTime64(d, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2020-03-01 00:00:00')) AND (((toDateTime64(d, 6, 'America/Los_Angeles') + INTERVAL 1 DAY) = '2020-03-08 00:00:00')) AND (((toDecimal64(toDateTime64(d, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(d, 6, 'America/Los_Angeles'))) = 1583539200)) +(3 rows) + +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + id | d +----+--------------------- + 1 | 2020-03-07 00:00:00 +(1 row) + +SELECT id, d FROM stz_http_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + id | d +----+--------------------- + 1 | 2020-03-07 00:00:00 +(1 row) + +-- Verify date() uses TimeZone: 10:00 UTC falls on next day at UTC+14. +SET timezone = 'Pacific/Kiritimati'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id, date(ts) + Remote SQL: SELECT id, ts FROM stz_test.utc WHERE ((toDate(toDateTime64(ts, 6, 'Pacific/Kiritimati')) = '2020-01-02')) +(3 rows) + +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; + id | date +----+------------ + 0 | 2020-01-02 +(1 row) + +SELECT id, date(ts) FROM stz_http_utc WHERE date(ts) = '2020-01-02'; + id | date +----+------------ + 0 | 2020-01-02 +(1 row) + +RESET timezone; +CALL clickhouse_perform('stz_admin', 'DROP DATABASE stz_test'); +DROP USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +DROP SERVER stz_bin_svr CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to foreign table stz_bin_wall +drop cascades to foreign table stz_bin_utc +drop cascades to foreign table stz_bin_day +DROP USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +DROP SERVER stz_http_svr CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to foreign table stz_http_wall +drop cascades to foreign table stz_http_utc +drop cascades to foreign table stz_http_day +DROP USER MAPPING FOR CURRENT_USER SERVER stz_admin; +DROP SERVER stz_admin; diff --git a/test/expected/session_timezone_1.out b/test/expected/session_timezone_1.out new file mode 100644 index 00000000..d3b5df90 --- /dev/null +++ b/test/expected/session_timezone_1.out @@ -0,0 +1,489 @@ +SET datestyle = 'ISO'; +CREATE SERVER stz_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'binary'); +CREATE SERVER stz_http_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +CREATE SERVER stz_admin FOREIGN DATA WRAPPER clickhouse_fdw; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_admin; +\set ECHO errors +CALL clickhouse_perform('stz_admin', 'DROP DATABASE IF EXISTS stz_test'); +CALL clickhouse_perform('stz_admin', 'CREATE DATABASE stz_test'); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.wall (id Int, ts DateTime64(6)) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.utc (id Int, ts DateTime('UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.day (id Int, d Date, ts DateTime64(6, 'UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.day VALUES + (1, '2020-03-07', '2020-03-07 10:00:05.25'), + (2, '2020-07-01', '1969-12-31 23:59:58.75') +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.utc + SELECT number, addMonths(toDateTime('2020-01-01 10:00:00', 'UTC'), number * 3) + FROM numbers(4) +$$); +CREATE FOREIGN TABLE stz_bin_wall (id int, ts timestamp) + SERVER stz_bin_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_http_wall (id int, ts timestamp) + SERVER stz_http_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_bin_utc (id int, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_http_utc (id int, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_bin_day (id int, d timestamp, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'day'); +CREATE FOREIGN TABLE stz_http_day (id int, d timestamp, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'day'); +-- Verify unzoned DateTime64 literals use PostgreSQL TimeZone. +SET timezone = 'America/Los_Angeles'; +INSERT INTO stz_bin_wall VALUES (1, '2024-07-01 12:00'); +INSERT INTO stz_http_wall VALUES (2, '2024-07-01 12:00'); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.wall VALUES (3, '2024-07-01 12:00:00') +$$); +SELECT * FROM clickhouse_query('stz_admin', $$ + SELECT id FROM stz_test.wall WHERE ts = '2024-07-01 12:00:00' ORDER BY id +$$) AS t(id int); + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT * FROM stz_bin_wall ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 12:00:00 + 2 | 2024-07-01 12:00:00 + 3 | 2024-07-01 12:00:00 +(3 rows) + +SELECT * FROM stz_http_wall ORDER BY id; + id | ts +----+--------------------- + 1 | 2024-07-01 12:00:00 + 2 | 2024-07-01 12:00:00 + 3 | 2024-07-01 12:00:00 +(3 rows) + +-- Verify pushed down literals and functions match local evaluation. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_wall + Output: id + Remote SQL: SELECT id FROM stz_test.wall WHERE ((ts = '2024-07-01 12:00:00')) AND ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 12)) +(3 rows) + +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_http_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +-- Execute six times to test parameters with generic plans. +PREPARE prep_bin(timestamp) AS SELECT id FROM stz_bin_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_bin('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +DEALLOCATE prep_bin; +PREPARE prep_http(timestamp) AS SELECT id FROM stz_http_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +EXECUTE prep_http('2024-07-01 12:00'); + id +---- + 1 + 2 + 3 +(3 rows) + +DEALLOCATE prep_http; +-- Read same instants as Tokyo wall clock times. Before ClickHouse 26.3, +-- literals use time zone unzoned columns had when table loaded +\if :ch263 +SET timezone = 'Asia/Tokyo'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; +SELECT * FROM stz_http_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; +-- Verify fixed offsets map to ClickHouse Fixed/UTC zones. +SET timezone = '+05:30'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; +SELECT * FROM stz_http_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; +\endif +-- Verify explicit UTC columns use PostgreSQL TimeZone across DST. +SET timezone = 'America/Los_Angeles'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (date_trunc('day'::text, ts)), (to_char(ts, 'HH24'::text)), (count(*)) + Relations: Aggregate on (stz_bin_utc) + Remote SQL: SELECT toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')), formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%H'), count(*) FROM stz_test.utc WHERE ((toHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = 3)) GROUP BY (toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles'))), (formatDateTime(toDateTime64(ts, 6, 'America/Los_Angeles'), '%H')) ORDER BY toStartOfDay(toDateTime64(ts, 6, 'America/Los_Angeles')) ASC NULLS LAST +(4 rows) + +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + d | h | count +------------------------+----+------- + 2020-04-01 00:00:00-07 | 03 | 1 + 2020-07-01 00:00:00-07 | 03 | 1 + 2020-10-01 00:00:00-07 | 03 | 1 +(3 rows) + +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_http_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; + d | h | count +------------------------+----+------- + 2020-04-01 00:00:00-07 | 03 | 1 + 2020-07-01 00:00:00-07 | 03 | 1 + 2020-10-01 00:00:00-07 | 03 | 1 +(3 rows) + +SELECT id, ts, date_part('hour', ts) FROM stz_bin_utc ORDER BY id; + id | ts | date_part +----+------------------------+----------- + 0 | 2020-01-01 02:00:00-08 | 2 + 1 | 2020-04-01 03:00:00-07 | 3 + 2 | 2020-07-01 03:00:00-07 | 3 + 3 | 2020-10-01 03:00:00-07 | 3 +(4 rows) + +-- Verify interval arithmetic preserves 02:00 across PST and PDT. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id + Remote SQL: SELECT id FROM stz_test.utc WHERE (((toDateTime64(ts, 6, 'America/Los_Angeles') + INTERVAL 3 MONTH) = cast('2020-04-01 09:00:00' as DateTime64(6, 'UTC')))) +(3 rows) + +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + id +---- + 0 +(1 row) + +SELECT id FROM stz_http_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; + id +---- + 0 +(1 row) + +PREPARE prep_iv(interval) AS SELECT id FROM stz_bin_utc WHERE ts + $1 = '2020-04-01 02:00'; +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +EXECUTE prep_iv('3 months'); + id +---- + 0 +(1 row) + +DEALLOCATE prep_iv; +-- Verify epoch extraction interprets timestamp wall clock times as UTC. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_wall + Output: id + Remote SQL: SELECT id FROM stz_test.wall WHERE (((toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(ts, 6, 'America/Los_Angeles'))) = 1719835200)) +(3 rows) + +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_http_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; + id +---- + 1 + 2 + 3 +(3 rows) + +SELECT id FROM stz_bin_utc WHERE extract(epoch FROM ts) = 1577872800; + id +---- + 0 +(1 row) + +-- Verify timezone() evaluates locally. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10; + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id + Filter: (date_part('hour'::text, (stz_bin_utc.ts AT TIME ZONE 'UTC'::text)) = '10'::double precision) + Remote SQL: SELECT id, ts FROM stz_test.utc +(4 rows) + +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10 ORDER BY id; + id +---- + 0 + 1 + 2 + 3 +(4 rows) + +-- Verify second and epoch extraction preserve microseconds before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id, date_part('second'::text, ts), EXTRACT(epoch FROM ts) + Remote SQL: SELECT id, ts FROM stz_test.day WHERE (((toSecond(toDateTime64(ts, 6, 'America/Los_Angeles')) + (toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6) - floor(toDecimal64(toDateTime64(ts, 6, 'America/Los_Angeles'), 6)))) > 5)) ORDER BY id ASC NULLS LAST +(3 rows) + +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; + id | date_part | extract +----+-----------+------------------- + 1 | 5.25 | 1583575205.250000 + 2 | 58.75 | -1.250000 +(2 rows) + +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_http_day + WHERE date_part('second', ts) > 5 ORDER BY id; + id | date_part | extract +----+-----------+------------------- + 1 | 5.25 | 1583575205.250000 + 2 | 58.75 | -1.250000 +(2 rows) + +-- Verify date_trunc supports dates before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id + Remote SQL: SELECT id FROM stz_test.day WHERE ((toDateTime64(toStartOfMonth(toDateTime64(ts, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = cast('1969-12-01 08:00:00' as DateTime64(6, 'UTC')))) AND ((toStartOfHour(toDateTime64(ts, 6, 'America/Los_Angeles')) = cast('1969-12-31 23:00:00' as DateTime64(6, 'UTC')))) +(3 rows) + +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + id +---- + 2 +(1 row) + +SELECT id FROM stz_http_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + id +---- + 2 +(1 row) + +-- Verify Date mapped to timestamp uses midnight and supports day arithmetic. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_day + Output: id, d + Remote SQL: SELECT id, d FROM stz_test.day WHERE ((toDateTime64(toStartOfMonth(toDateTime64(d, 6, 'America/Los_Angeles')), 6, 'America/Los_Angeles') = '2020-03-01 00:00:00')) AND (((toDateTime64(d, 6, 'America/Los_Angeles') + INTERVAL 1 DAY) = '2020-03-08 00:00:00')) AND (((toDecimal64(toDateTime64(d, 6, 'America/Los_Angeles'), 6) + timeZoneOffset(toDateTime64(d, 6, 'America/Los_Angeles'))) = 1583539200)) +(3 rows) + +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + id | d +----+--------------------- + 1 | 2020-03-07 00:00:00 +(1 row) + +SELECT id, d FROM stz_http_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + id | d +----+--------------------- + 1 | 2020-03-07 00:00:00 +(1 row) + +-- Verify date() uses TimeZone: 10:00 UTC falls on next day at UTC+14. +SET timezone = 'Pacific/Kiritimati'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public.stz_bin_utc + Output: id, date(ts) + Remote SQL: SELECT id, ts FROM stz_test.utc WHERE ((toDate(toDateTime64(ts, 6, 'Pacific/Kiritimati')) = '2020-01-02')) +(3 rows) + +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; + id | date +----+------------ + 0 | 2020-01-02 +(1 row) + +SELECT id, date(ts) FROM stz_http_utc WHERE date(ts) = '2020-01-02'; + id | date +----+------------ + 0 | 2020-01-02 +(1 row) + +RESET timezone; +CALL clickhouse_perform('stz_admin', 'DROP DATABASE stz_test'); +DROP USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +DROP SERVER stz_bin_svr CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to foreign table stz_bin_wall +drop cascades to foreign table stz_bin_utc +drop cascades to foreign table stz_bin_day +DROP USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +DROP SERVER stz_http_svr CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to foreign table stz_http_wall +drop cascades to foreign table stz_http_utc +drop cascades to foreign table stz_http_day +DROP USER MAPPING FOR CURRENT_USER SERVER stz_admin; +DROP SERVER stz_admin; diff --git a/test/expected/session_timezone_2.out b/test/expected/session_timezone_2.out new file mode 100644 index 00000000..b79f6fd3 --- /dev/null +++ b/test/expected/session_timezone_2.out @@ -0,0 +1,9 @@ +SET datestyle = 'ISO'; +CREATE SERVER stz_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'binary'); +CREATE SERVER stz_http_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +CREATE SERVER stz_admin FOREIGN DATA WRAPPER clickhouse_fdw; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_admin; +\set ECHO errors +SKIP: session_timezone unsupported prior to ClickHouse 23.6 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)) 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; diff --git a/test/sql/param.sql b/test/sql/param.sql index 454455b9..5b9798e6 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,52 @@ 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'); +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'); +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 DEALLOCATE st1; DEALLOCATE st2; @@ -143,6 +206,14 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- =================================================================== -- http foreign tables @@ -238,6 +309,52 @@ 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'); +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'); +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 DEALLOCATE st1; DEALLOCATE st2; @@ -246,6 +363,14 @@ DEALLOCATE st4; DEALLOCATE st5; DEALLOCATE st6; DEALLOCATE st7; +DEALLOCATE st8; +DEALLOCATE st9; +DEALLOCATE st10; +DEALLOCATE st11; +DEALLOCATE st12; +DEALLOCATE st13; +DEALLOCATE st14; +DEALLOCATE st15; -- Clean up. DROP USER MAPPING FOR CURRENT_USER SERVER param_bin_svr; diff --git a/test/sql/session_timezone.sql b/test/sql/session_timezone.sql new file mode 100644 index 00000000..d180d485 --- /dev/null +++ b/test/sql/session_timezone.sql @@ -0,0 +1,194 @@ +SET datestyle = 'ISO'; +CREATE SERVER stz_bin_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'binary'); +CREATE SERVER stz_http_svr FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'stz_test', driver 'http'); +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; + +CREATE SERVER stz_admin FOREIGN DATA WRAPPER clickhouse_fdw; +CREATE USER MAPPING FOR CURRENT_USER SERVER stz_admin; + +\set ECHO errors +SELECT clickhouse_server_version('stz_admin') AS ch_version \gset +SELECT (split_part(:'ch_version', '.', 1)::int, + split_part(:'ch_version', '.', 2)::int) < (23, 6) AS no_ch236 \gset +\if :no_ch236 +\echo 'SKIP: session_timezone unsupported prior to ClickHouse 23.6' +\quit +\endif +SELECT (split_part(:'ch_version', '.', 1)::int, + split_part(:'ch_version', '.', 2)::int) >= (26, 3) AS ch263 \gset +\set ECHO all + +CALL clickhouse_perform('stz_admin', 'DROP DATABASE IF EXISTS stz_test'); +CALL clickhouse_perform('stz_admin', 'CREATE DATABASE stz_test'); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.wall (id Int, ts DateTime64(6)) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.utc (id Int, ts DateTime('UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + CREATE TABLE stz_test.day (id Int, d Date, ts DateTime64(6, 'UTC')) + ENGINE = MergeTree ORDER BY id +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.day VALUES + (1, '2020-03-07', '2020-03-07 10:00:05.25'), + (2, '2020-07-01', '1969-12-31 23:59:58.75') +$$); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.utc + SELECT number, addMonths(toDateTime('2020-01-01 10:00:00', 'UTC'), number * 3) + FROM numbers(4) +$$); + +CREATE FOREIGN TABLE stz_bin_wall (id int, ts timestamp) + SERVER stz_bin_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_http_wall (id int, ts timestamp) + SERVER stz_http_svr OPTIONS (table_name 'wall'); +CREATE FOREIGN TABLE stz_bin_utc (id int, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_http_utc (id int, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'utc'); +CREATE FOREIGN TABLE stz_bin_day (id int, d timestamp, ts timestamptz) + SERVER stz_bin_svr OPTIONS (table_name 'day'); +CREATE FOREIGN TABLE stz_http_day (id int, d timestamp, ts timestamptz) + SERVER stz_http_svr OPTIONS (table_name 'day'); + +-- Verify unzoned DateTime64 literals use PostgreSQL TimeZone. +SET timezone = 'America/Los_Angeles'; +INSERT INTO stz_bin_wall VALUES (1, '2024-07-01 12:00'); +INSERT INTO stz_http_wall VALUES (2, '2024-07-01 12:00'); +CALL clickhouse_perform('stz_admin', $$ + INSERT INTO stz_test.wall VALUES (3, '2024-07-01 12:00:00') +$$); +SELECT * FROM clickhouse_query('stz_admin', $$ + SELECT id FROM stz_test.wall WHERE ts = '2024-07-01 12:00:00' ORDER BY id +$$) AS t(id int); +SELECT * FROM stz_bin_wall ORDER BY id; +SELECT * FROM stz_http_wall ORDER BY id; + +-- Verify pushed down literals and functions match local evaluation. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12; +SELECT id FROM stz_bin_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; +SELECT id FROM stz_http_wall + WHERE ts = '2024-07-01 12:00' AND date_part('hour', ts) = 12 ORDER BY id; + +-- Execute six times to test parameters with generic plans. +PREPARE prep_bin(timestamp) AS SELECT id FROM stz_bin_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_bin('2024-07-01 12:00'); +EXECUTE prep_bin('2024-07-01 12:00'); +EXECUTE prep_bin('2024-07-01 12:00'); +EXECUTE prep_bin('2024-07-01 12:00'); +EXECUTE prep_bin('2024-07-01 12:00'); +EXECUTE prep_bin('2024-07-01 12:00'); +DEALLOCATE prep_bin; +PREPARE prep_http(timestamp) AS SELECT id FROM stz_http_wall WHERE ts = $1 ORDER BY id; +EXECUTE prep_http('2024-07-01 12:00'); +EXECUTE prep_http('2024-07-01 12:00'); +EXECUTE prep_http('2024-07-01 12:00'); +EXECUTE prep_http('2024-07-01 12:00'); +EXECUTE prep_http('2024-07-01 12:00'); +EXECUTE prep_http('2024-07-01 12:00'); +DEALLOCATE prep_http; + +-- Read same instants as Tokyo wall clock times. Before ClickHouse 26.3, +-- literals use time zone unzoned columns had when table loaded +\if :ch263 +SET timezone = 'Asia/Tokyo'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; +SELECT * FROM stz_http_wall WHERE ts = '2024-07-02 04:00' ORDER BY id; + +-- Verify fixed offsets map to ClickHouse Fixed/UTC zones. +SET timezone = '+05:30'; +SELECT * FROM stz_bin_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; +SELECT * FROM stz_http_wall WHERE ts = '2024-07-01 13:30' ORDER BY id; +\endif + +-- Verify explicit UTC columns use PostgreSQL TimeZone across DST. +SET timezone = 'America/Los_Angeles'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_bin_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; +SELECT date_trunc('day', ts) AS d, to_char(ts, 'HH24') AS h, count(*) + FROM stz_http_utc WHERE extract(hour FROM ts) = 3 GROUP BY d, h ORDER BY d; +SELECT id, ts, date_part('hour', ts) FROM stz_bin_utc ORDER BY id; + +-- Verify interval arithmetic preserves 02:00 across PST and PDT. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; +SELECT id FROM stz_bin_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; +SELECT id FROM stz_http_utc WHERE ts + interval '3 months' = '2020-04-01 02:00'; +PREPARE prep_iv(interval) AS SELECT id FROM stz_bin_utc WHERE ts + $1 = '2020-04-01 02:00'; +EXECUTE prep_iv('3 months'); +EXECUTE prep_iv('3 months'); +EXECUTE prep_iv('3 months'); +EXECUTE prep_iv('3 months'); +EXECUTE prep_iv('3 months'); +EXECUTE prep_iv('3 months'); +DEALLOCATE prep_iv; + +-- Verify epoch extraction interprets timestamp wall clock times as UTC. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200; +SELECT id FROM stz_bin_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; +SELECT id FROM stz_http_wall WHERE date_part('epoch', ts) = 1719835200 ORDER BY id; +SELECT id FROM stz_bin_utc WHERE extract(epoch FROM ts) = 1577872800; + +-- Verify timezone() evaluates locally. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10; +SELECT id FROM stz_bin_utc WHERE date_part('hour', ts AT TIME ZONE 'UTC') = 10 ORDER BY id; + +-- Verify second and epoch extraction preserve microseconds before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_bin_day + WHERE date_part('second', ts) > 5 ORDER BY id; +SELECT id, date_part('second', ts), extract(epoch FROM ts) FROM stz_http_day + WHERE date_part('second', ts) > 5 ORDER BY id; + +-- Verify date_trunc supports dates before 1970. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; +SELECT id FROM stz_bin_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; +SELECT id FROM stz_http_day + WHERE date_trunc('month', ts) = '1969-12-01' AND date_trunc('hour', ts) = '1969-12-31 15:00'; + +-- Verify Date mapped to timestamp uses midnight and supports day arithmetic. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; +SELECT id, d FROM stz_bin_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; +SELECT id, d FROM stz_http_day + WHERE date_trunc('month', d) = '2020-03-01' AND d + interval '1 day' = '2020-03-08' + AND date_part('epoch', d) = 1583539200; + +-- Verify date() uses TimeZone: 10:00 UTC falls on next day at UTC+14. +SET timezone = 'Pacific/Kiritimati'; +EXPLAIN (VERBOSE, COSTS OFF) +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; +SELECT id, date(ts) FROM stz_bin_utc WHERE date(ts) = '2020-01-02'; +SELECT id, date(ts) FROM stz_http_utc WHERE date(ts) = '2020-01-02'; +RESET timezone; + +CALL clickhouse_perform('stz_admin', 'DROP DATABASE stz_test'); +DROP USER MAPPING FOR CURRENT_USER SERVER stz_bin_svr; +DROP SERVER stz_bin_svr CASCADE; +DROP USER MAPPING FOR CURRENT_USER SERVER stz_http_svr; +DROP SERVER stz_http_svr CASCADE; +DROP USER MAPPING FOR CURRENT_USER SERVER stz_admin; +DROP SERVER stz_admin; 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