Skip to content
Draft

wip #389

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 213 additions & 39 deletions src/deparse.c

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/include/fdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
20 changes: 16 additions & 4 deletions src/pglink.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,21 +425,29 @@ 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:
return psprintf("%d", DatumGetInt32(value));
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:
Expand Down Expand Up @@ -482,11 +490,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: {
Expand All @@ -496,6 +503,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,
Expand Down
43 changes: 43 additions & 0 deletions src/shipable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -404,6 +437,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;
}
Expand Down
72 changes: 36 additions & 36 deletions test/expected/functions.out
Original file line number Diff line number Diff line change
Expand Up @@ -1184,11 +1184,11 @@ SELECT ts FROM t5 WHERE date_part('epoch', ts) > '1866158180';

-- Check date_part from date.
EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 2027))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 2027))
(3 rows)

SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027;
Expand All @@ -1198,11 +1198,11 @@ SELECT ts FROM t5 WHERE date_part('year', ts::date) = 2027;
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 11))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 11))
(3 rows)

SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11;
Expand All @@ -1212,11 +1212,11 @@ SELECT ts FROM t5 WHERE date_part('month', ts::date) = 11;
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date)'), 'Nullable(DateTime)')) = 18))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(cast(ts, 'Nullable(Date32)'), 'Nullable(DateTime64(6))')) = 18))
(3 rows)

SELECT ts FROM t5 WHERE date_part('day', ts::date) = 18;
Expand Down Expand Up @@ -1401,11 +1401,11 @@ SELECT ts FROM t5 WHERE EXTRACT(epoch FROM ts) > 1866158180;

-- Check extract from date.
EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027;
QUERY PLAN
----------------------------------------------------------------------------------------------------
QUERY PLAN
------------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date)')) = 2027))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toYear(cast(ts, 'Nullable(Date32)')) = 2027))
(3 rows)

SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027;
Expand All @@ -1415,11 +1415,11 @@ SELECT ts FROM t5 WHERE EXTRACT(year FROM ts::date) = 2027;
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11;
QUERY PLAN
---------------------------------------------------------------------------------------------------
QUERY PLAN
-----------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date)')) = 11))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toMonth(cast(ts, 'Nullable(Date32)')) = 11))
(3 rows)

SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11;
Expand All @@ -1429,11 +1429,11 @@ SELECT ts FROM t5 WHERE EXTRACT(month FROM ts::date) = 11;
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Foreign Scan on public.t5
Output: ts
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date)')) = 18))
Remote SQL: SELECT ts FROM functions_test.t5 WHERE ((toDayOfMonth(cast(ts, 'Nullable(Date32)')) = 18))
(3 rows)

SELECT ts FROM t5 WHERE EXTRACT(day FROM ts::date) = 18;
Expand Down Expand Up @@ -1573,11 +1573,11 @@ SELECT key1 FROM t3_map WHERE md5(val) LIKE 'a%' ORDER BY key1;

-- Check to_timestamp(float8).
EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t6
Output: i64, f64
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00'))
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC'))))
(3 rows)

SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0);
Expand All @@ -1587,11 +1587,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0);
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t6
Output: i64, f64
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '1970-01-01 00:00:00'))
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC'))))
(3 rows)

SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0);
Expand All @@ -1601,11 +1601,11 @@ SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(0);
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(0);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t6
Output: i64, f64
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = '1970-01-01 00:00:00'))
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(i64, 6, 'UTC') = cast('1970-01-01 00:00:00' as DateTime64(6, 'UTC'))))
(3 rows)

SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443);
Expand All @@ -1615,11 +1615,11 @@ SELECT * FROM t6 WHERE to_timestamp(i64) = to_timestamp(2042323443);
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t6
Output: i64, f64
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = '2034-09-20 00:04:03'))
Remote SQL: SELECT i64, f64 FROM functions_test.t6 WHERE ((toDateTime64(f64, 6, 'UTC') = cast('2034-09-20 00:04:03' as DateTime64(6, 'UTC'))))
(3 rows)

SELECT * FROM t6 WHERE to_timestamp(f64) = to_timestamp(2042323443);
Expand Down Expand Up @@ -1772,11 +1772,11 @@ SELECT * FROM t1 WHERE c < LOCALTIMESTAMP(3) ORDER BY a LIMIT 2;

-- Use with other functions.
EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t1
Output: a, b, c
Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime)'))))
Remote SQL: SELECT a, b, c FROM functions_test.t1 WHERE ((toYear(c) < toYear(cast(toDate(now('America/Los_Angeles')), 'Nullable(DateTime64(6))'))))
(3 rows)

SELECT * FROM t1 WHERE date_part('year', c) < date_part('year', CURRENT_DATE);
Expand Down Expand Up @@ -1838,11 +1838,11 @@ SELECT a FROM t1 WHERE a = 1 AND c + INTERVAL '0.5 seconds' > c;
(1 row)

EXPLAIN (VERBOSE, COSTS OFF) SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Foreign Scan on public.t1
Output: a
Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date)') - 1)))
Remote SQL: SELECT a FROM functions_test.t1 WHERE ((a = 1)) AND (((toDateTime64(cast(c, 'Nullable(Date32)'), 6) - INTERVAL 1 DAY - INTERVAL 500000 MICROSECOND) < (cast(c, 'Nullable(Date32)') - 1)))
(3 rows)

SELECT a FROM t1 WHERE a = 1 AND c::date - INTERVAL '1 day 0.5 seconds' < c::date - 1;
Expand Down
Loading
Loading