diff --git a/src/backend/columnar/cstore_customscan.c b/src/backend/columnar/cstore_customscan.c index 9a014123c..473b6ba36 100644 --- a/src/backend/columnar/cstore_customscan.c +++ b/src/backend/columnar/cstore_customscan.c @@ -53,7 +53,8 @@ typedef struct ColumnarScanState static void ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); -static Path * CreateColumnarScanPath(RelOptInfo *rel, RangeTblEntry *rte); +static Path * CreateColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte); static Cost ColumnarScanCost(RangeTblEntry *rte); static Plan * ColumnarScanPath_PlanCustomPath(PlannerInfo *root, RelOptInfo *rel, @@ -182,7 +183,7 @@ ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti, errmsg("sample scans not supported on columnar tables"))); } - Path *customPath = CreateColumnarScanPath(rel, rte); + Path *customPath = CreateColumnarScanPath(root, rel, rte); ereport(DEBUG1, (errmsg("pathlist hook for columnar table am"))); @@ -195,7 +196,7 @@ ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti, static Path * -CreateColumnarScanPath(RelOptInfo *rel, RangeTblEntry *rte) +CreateColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { ColumnarScanPath *cspath = (ColumnarScanPath *) newNode(sizeof(ColumnarScanPath), T_CustomPath); @@ -214,6 +215,14 @@ CreateColumnarScanPath(RelOptInfo *rel, RangeTblEntry *rte) path->parent = rel; path->pathtarget = rel->reltarget; + /* + * We don't support pushing join clauses into the quals of a seqscan, but + * it could still have required parameterization due to LATERAL refs in + * its tlist. + */ + path->param_info = get_baserel_parampathinfo(root, rel, + rel->lateral_relids); + /* * Add cost estimates for a columnar table scan, row count is the rows estimated by * postgres' planner. diff --git a/src/test/regress/expected/am_query.out b/src/test/regress/expected/am_query.out index a96fd36fd..af59bfb4f 100644 --- a/src/test/regress/expected/am_query.out +++ b/src/test/regress/expected/am_query.out @@ -1,6 +1,8 @@ -- --- Test querying cstore_fdw tables. +-- Test querying columnar tables. -- +CREATE SCHEMA columnar_join; +SET search_path to columnar_join, public; -- Settings to make the result deterministic SET datestyle = "ISO, YMD"; -- Query uncompressed data @@ -119,3 +121,63 @@ INSERT INTO union_second SELECT a, a FROM generate_series(11, 15) a; (10 rows) DROP TABLE union_first, union_second; +-- https://github.com/citusdata/citus/issues/4600 +CREATE TABLE INT8_TBL_columnar(q1 int8, q2 int8) using columnar; +INSERT INTO INT8_TBL_columnar VALUES(' 123 ',' 456'); +INSERT INTO INT8_TBL_columnar VALUES('123 ','4567890123456789'); +INSERT INTO INT8_TBL_columnar VALUES('4567890123456789','123'); +INSERT INTO INT8_TBL_columnar VALUES(+4567890123456789,'4567890123456789'); +INSERT INTO INT8_TBL_columnar VALUES('+4567890123456789','-4567890123456789'); +explain (costs off, summary off) select * from + INT8_TBL_columnar a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_columnar b cross join INT8_TBL_columnar c) ss + on a.q2 = ss.bq1; + QUERY PLAN +--------------------------------------------------------------------- + Nested Loop Left Join + -> Custom Scan (ColumnarScan) on int8_tbl_columnar a + -> Nested Loop + -> Custom Scan (ColumnarScan) on int8_tbl_columnar b + Filter: (a.q2 = q1) + -> Custom Scan (ColumnarScan) on int8_tbl_columnar c +(6 rows) + +explain (costs off, summary off) + SELECT COUNT(*) FROM INT8_TBL_columnar t1 JOIN + LATERAL (SELECT * FROM INT8_TBL_columnar t2 WHERE t1.q1 = t2.q1) + as foo ON (true); + QUERY PLAN +--------------------------------------------------------------------- + Aggregate + -> Hash Join + Hash Cond: (t2.q1 = t1.q1) + -> Custom Scan (ColumnarScan) on int8_tbl_columnar t2 + -> Hash + -> Custom Scan (ColumnarScan) on int8_tbl_columnar t1 +(6 rows) + +CREATE TABLE INT8_TBL_heap (LIKE INT8_TBL_columnar) ; +INSERT INTO INT8_TBL_heap SELECT * FROM INT8_TBL_columnar; +CREATE TABLE result_columnar AS +select * from + INT8_TBL_columnar a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_columnar b cross join INT8_TBL_columnar c) ss + on a.q2 = ss.bq1; +CREATE TABLE result_regular AS +select * from + INT8_TBL_heap a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_heap b cross join INT8_TBL_heap c) ss + on a.q2 = ss.bq1; +-- 2 results should be identical, so the following should be empty +(table result_columnar EXCEPT table result_regular) +UNION +(table result_regular EXCEPT table result_columnar); + q1 | q2 | bq1 | cq1 | least +--------------------------------------------------------------------- +(0 rows) + +SET client_min_messages TO WARNING; +DROP SCHEMA columnar_join CASCADE; diff --git a/src/test/regress/sql/am_query.sql b/src/test/regress/sql/am_query.sql index 12e4ab4e3..a56860956 100644 --- a/src/test/regress/sql/am_query.sql +++ b/src/test/regress/sql/am_query.sql @@ -1,7 +1,10 @@ -- --- Test querying cstore_fdw tables. +-- Test querying columnar tables. -- +CREATE SCHEMA columnar_join; +SET search_path to columnar_join, public; + -- Settings to make the result deterministic SET datestyle = "ISO, YMD"; @@ -43,3 +46,48 @@ INSERT INTO union_second SELECT a, a FROM generate_series(11, 15) a; (SELECT a*1, b FROM union_first) union all (SELECT a*1, b FROM union_second); DROP TABLE union_first, union_second; + +-- https://github.com/citusdata/citus/issues/4600 +CREATE TABLE INT8_TBL_columnar(q1 int8, q2 int8) using columnar; + +INSERT INTO INT8_TBL_columnar VALUES(' 123 ',' 456'); +INSERT INTO INT8_TBL_columnar VALUES('123 ','4567890123456789'); +INSERT INTO INT8_TBL_columnar VALUES('4567890123456789','123'); +INSERT INTO INT8_TBL_columnar VALUES(+4567890123456789,'4567890123456789'); +INSERT INTO INT8_TBL_columnar VALUES('+4567890123456789','-4567890123456789'); + +explain (costs off, summary off) select * from + INT8_TBL_columnar a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_columnar b cross join INT8_TBL_columnar c) ss + on a.q2 = ss.bq1; + +explain (costs off, summary off) + SELECT COUNT(*) FROM INT8_TBL_columnar t1 JOIN + LATERAL (SELECT * FROM INT8_TBL_columnar t2 WHERE t1.q1 = t2.q1) + as foo ON (true); + +CREATE TABLE INT8_TBL_heap (LIKE INT8_TBL_columnar) USING heap; +INSERT INTO INT8_TBL_heap SELECT * FROM INT8_TBL_columnar; + +CREATE TABLE result_columnar AS +select * from + INT8_TBL_columnar a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_columnar b cross join INT8_TBL_columnar c) ss + on a.q2 = ss.bq1; + +CREATE TABLE result_regular AS +select * from + INT8_TBL_heap a left join lateral + (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from + INT8_TBL_heap b cross join INT8_TBL_heap c) ss + on a.q2 = ss.bq1; + +-- 2 results should be identical, so the following should be empty +(table result_columnar EXCEPT table result_regular) +UNION +(table result_regular EXCEPT table result_columnar); + +SET client_min_messages TO WARNING; +DROP SCHEMA columnar_join CASCADE;