Skip to content

Commit

Permalink
Fix segfault creating CAgg with multiple joins
Browse files Browse the repository at this point in the history
When using explicit JOIN clauses in and statement the
`Query->jointree->fromlist` will contain a list of `JoinExpr` elements
and each element have `larg` and `larg` node that can be either
`JoinExpr` or `RangeTableRef`.

Fixing it by checking the type of node before casting it properly in
order to use the `rtindex` to get the properly `RangeTblEntry`.
  • Loading branch information
fabriziomello committed Jun 20, 2024
1 parent e2089f7 commit 79bd882
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
24 changes: 20 additions & 4 deletions tsl/src/continuous_aggs/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,14 +702,30 @@ cagg_validate_query(const Query *query, const bool finalized, const char *cagg_s
foreach (l, query->jointree->fromlist)
{
Node *jtnode = (Node *) lfirst(l);
JoinExpr *join = NULL;
if (IsA(jtnode, JoinExpr))
{
join = castNode(JoinExpr, jtnode);
JoinExpr *join = castNode(JoinExpr, jtnode);
jointype = join->jointype;
op = (OpExpr *) join->quals;
rte = list_nth(query->rtable, ((RangeTblRef *) join->larg)->rtindex - 1);
rte_other = list_nth(query->rtable, ((RangeTblRef *) join->rarg)->rtindex - 1);

int lindex = 0, rindex = 0;

if (IsA(join->larg, RangeTblRef))
lindex = ((RangeTblRef *) join->larg)->rtindex;

if (IsA(join->larg, JoinExpr))
lindex = ((JoinExpr *) join->larg)->rtindex;

if (IsA(join->rarg, RangeTblRef))
rindex = ((RangeTblRef *) join->rarg)->rtindex;

if (IsA(join->rarg, JoinExpr))
rindex = ((JoinExpr *) join->rarg)->rtindex;

Check warning on line 723 in tsl/src/continuous_aggs/common.c

View check run for this annotation

Codecov / codecov/patch

tsl/src/continuous_aggs/common.c#L723

Added line #L723 was not covered by tests

Assert(lindex != 0 && rindex != 0);

rte = list_nth(query->rtable, lindex - 1);
rte_other = list_nth(query->rtable, rindex - 1);
if (rte->subquery != NULL || rte_other->subquery != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
Expand Down
14 changes: 14 additions & 0 deletions tsl/test/expected/cagg_joins.out
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ DETAIL: Migration might take a while depending on the amount of data.

CREATE TABLE devices ( device_id int not null, name text, location text);
INSERT INTO devices values (1, 'thermo_1', 'Moscow'), (2, 'thermo_2', 'Berlin'),(3, 'thermo_3', 'London'),(4, 'thermo_4', 'Stockholm');
CREATE TABLE location (location_id INTEGER, name TEXT);
INSERT INTO location VALUES (1, 'Moscow'), (2, 'Berlin'), (3, 'London'), (4, 'Stockholm');
CREATE TABLE devices_dup AS SELECT * FROM devices;
CREATE VIEW devices_view AS SELECT * FROM devices;
-- Working cases
Expand Down Expand Up @@ -1115,6 +1117,18 @@ WHERE cagg.device_id = conditions.device_id
GROUP BY 1,2,3;
ERROR: invalid continuous aggregate view
DETAIL: Views are not supported in FROM clause.
--Multiple JOINS are not supported
CREATE MATERIALIZED VIEW conditions_by_day WITH (timescaledb.continuous) AS
SELECT time_bucket(INTERVAL '1 day', conditions.day) AS bucket,
AVG(conditions.temperature),
devices.name,
location.name
FROM conditions
JOIN devices ON conditions.device_id = devices.device_id
JOIN location ON location.name = devices.location
GROUP BY bucket, devices.name, location.name;
ERROR: invalid continuous aggregate view
DETAIL: Multiple hypertables or normal tables are not supported in FROM clause.
\set VERBOSITY terse
DROP TABLE conditions CASCADE;
NOTICE: drop cascades to 51 other objects
Expand Down
14 changes: 14 additions & 0 deletions tsl/test/sql/cagg_joins.sql
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ SELECT create_hypertable(
CREATE TABLE devices ( device_id int not null, name text, location text);
INSERT INTO devices values (1, 'thermo_1', 'Moscow'), (2, 'thermo_2', 'Berlin'),(3, 'thermo_3', 'London'),(4, 'thermo_4', 'Stockholm');

CREATE TABLE location (location_id INTEGER, name TEXT);
INSERT INTO location VALUES (1, 'Moscow'), (2, 'Berlin'), (3, 'London'), (4, 'Stockholm');

CREATE TABLE devices_dup AS SELECT * FROM devices;
CREATE VIEW devices_view AS SELECT * FROM devices;

Expand Down Expand Up @@ -547,6 +550,17 @@ FROM cagg_cagg cagg, conditions
WHERE cagg.device_id = conditions.device_id
GROUP BY 1,2,3;

--Multiple JOINS are not supported
CREATE MATERIALIZED VIEW conditions_by_day WITH (timescaledb.continuous) AS
SELECT time_bucket(INTERVAL '1 day', conditions.day) AS bucket,
AVG(conditions.temperature),
devices.name,
location.name
FROM conditions
JOIN devices ON conditions.device_id = devices.device_id
JOIN location ON location.name = devices.location
GROUP BY bucket, devices.name, location.name;

\set VERBOSITY terse
DROP TABLE conditions CASCADE;
DROP TABLE devices CASCADE;
Expand Down

0 comments on commit 79bd882

Please sign in to comment.