Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax CAggs JOIN restrictions #7111

Merged
Merged
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
170 changes: 45 additions & 125 deletions tsl/src/continuous_aggs/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,17 +667,12 @@ cagg_validate_query(const Query *query, const bool finalized, const char *cagg_s
CAggTimebucketInfo bucket_info = { 0 };
CAggTimebucketInfo bucket_info_parent = { 0 };
Hypertable *ht = NULL, *ht_parent = NULL;
RangeTblRef *rtref = NULL, *rtref_other = NULL;
RangeTblEntry *rte = NULL, *rte_other = NULL;
JoinType jointype = JOIN_FULL;
OpExpr *op = NULL;
List *fromList = NIL;
RangeTblEntry *rte = NULL;
StringInfo hint = makeStringInfo();
StringInfo detail = makeStringInfo();
bool is_hierarchical = false;
Query *prev_query = NULL;
ContinuousAgg *cagg_parent = NULL;
Oid normal_table_id = InvalidOid;

if (!cagg_query_supported(query, hint, detail, finalized))
{
Expand All @@ -688,146 +683,71 @@ cagg_validate_query(const Query *query, const bool finalized, const char *cagg_s
detail->len > 0 ? errdetail("%s", detail->data) : 0));
}

/* Check if there are only two tables in the from list. */
fromList = query->jointree->fromlist;
if (list_length(fromList) > CONTINUOUS_AGG_MAX_JOIN_RELATIONS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only two tables with one hypertable and one normal table "
"are allowed in continuous aggregate view")));
}
/* Extra checks for joins in Caggs. */
if (list_length(fromList) == CONTINUOUS_AGG_MAX_JOIN_RELATIONS ||
!IsA(linitial(query->jointree->fromlist), RangeTblRef))
int num_tables = 0, num_hypertables = 0;
ListCell *lc;
foreach (lc, query->rtable)
{
if (list_length(fromList) == CONTINUOUS_AGG_MAX_JOIN_RELATIONS)
RangeTblEntry *inner_rte = lfirst_node(RangeTblEntry, lc);

if (inner_rte->rtekind == RTE_RELATION)
{
if (!IsA(linitial(fromList), RangeTblRef) || !IsA(lsecond(fromList), RangeTblRef))
bool is_hypertable = ts_is_hypertable(inner_rte->relid) ||
ts_continuous_agg_find_by_relid(inner_rte->relid);

if (is_hypertable)
{
num_hypertables++;
if (rte == NULL)
rte = copyObject(inner_rte);
}
else
{
num_tables++;
}

if (is_hypertable && inner_rte->inh == false)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail(
"From clause can only have one hypertable and one normal table.")));

rtref = linitial_node(RangeTblRef, query->jointree->fromlist);
rte = list_nth(query->rtable, rtref->rtindex - 1);
rtref_other = lsecond_node(RangeTblRef, query->jointree->fromlist);
rte_other = list_nth(query->rtable, rtref_other->rtindex - 1);
jointype = rte->jointype || rte_other->jointype;

if (query->jointree->quals != NULL && IsA(query->jointree->quals, OpExpr))
op = (OpExpr *) query->jointree->quals;
}
else
{
ListCell *l;
foreach (l, query->jointree->fromlist)
{
Node *jtnode = (Node *) lfirst(l);
JoinExpr *join = NULL;
if (IsA(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);
if (rte->subquery != NULL || rte_other->subquery != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Sub-queries are not supported in FROM clause.")));
RangeTblEntry *jrte = rt_fetch(join->rtindex, query->rtable);
if (jrte->joinaliasvars == NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view")));
}
}
"FROM ONLY on hypertables is not allowed in continuous aggregate.")));
}

/*
* Error out if there is aynthing else than one normal table and one hypertable
* in the from clause, e.g. sub-query, lateral, two hypertables, etc.
*/
if (rte->lateral || rte_other->lateral)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Lateral joins are not supported in FROM clause.")));
if ((rte->relkind == RELKIND_VIEW && ts_is_hypertable(rte_other->relid)) ||
(rte_other->relkind == RELKIND_VIEW && ts_is_hypertable(rte->relid)))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Views are not supported in FROM clause.")));
if (rte->relkind != RELKIND_VIEW && rte_other->relkind != RELKIND_VIEW &&
(ts_is_hypertable(rte->relid) == ts_is_hypertable(rte_other->relid)))
/* Only inner joins are allowed. */
if (inner_rte->jointype != JOIN_INNER && inner_rte->jointype != JOIN_LEFT)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Multiple hypertables or normal tables are not supported in FROM "
"clause.")));
errmsg("only INNER or LEFT joins are supported in continuous aggregates")));

/* Only inner joins are allowed. */
if (jointype != JOIN_INNER)
/* Subquery only using LATERAL */
if (inner_rte->subquery && !inner_rte->lateral)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only inner joins are supported in continuous aggregates")));
errmsg("invalid continuous aggregate view"),
errdetail("Sub-queries are not supported in FROM clause.")));

/* Only equality conditions are permitted on joins. */
if (op && IsA(op, OpExpr) &&
list_length(castNode(OpExpr, op)->args) == CONTINUOUS_AGG_MAX_JOIN_RELATIONS)
{
Oid left_type = exprType(linitial(op->args));
Oid right_type = exprType(lsecond(op->args));
if (!ts_is_equality_operator(op->opno, left_type, right_type))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail(
"Only equality conditions are supported in continuous aggregates.")));
}
else
/* TABLESAMPLE not allowed */
if (inner_rte->tablesample)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Unsupported expression in join clause."),
errhint("Only equality conditions are supported in continuous aggregates.")));
/*
* Record the table oid of the normal table. This is required so
* that we know which one is hypertable to carry out the related
* processing in later parts of code.
*/
if (rte->relkind == RELKIND_VIEW)
normal_table_id = rte_other->relid;
else if (rte_other->relkind == RELKIND_VIEW)
normal_table_id = rte->relid;
else
normal_table_id = ts_is_hypertable(rte->relid) ? rte_other->relid : rte->relid;
if (normal_table_id == rte->relid)
rte = rte_other;
errdetail("TABLESAMPLE is not supported in continuous aggregate.")));
}
else
{
/* Check if we have a hypertable in the FROM clause. */
rtref = linitial_node(RangeTblRef, query->jointree->fromlist);
rte = list_nth(query->rtable, rtref->rtindex - 1);
}
/* FROM only <tablename> sets rte->inh to false. */
if (rte->rtekind != RTE_JOIN)

if (num_hypertables > 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("Only one hypertable is allowed in continuous aggregate view.")));

if (rte == NULL)
{
if ((rte->relkind != RELKIND_RELATION && rte->relkind != RELKIND_VIEW) ||
rte->tablesample || rte->inh == false)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view")));
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("invalid continuous aggregate view"),
errdetail("At least one hypertable should be used in the view definition.")));
}

Ensure(rte->relkind == RELKIND_RELATION || rte->relkind == RELKIND_VIEW,
"invalid continuous aggregate view");

const Dimension *part_dimension = NULL;
int32 parent_mat_hypertable_id = INVALID_HYPERTABLE_ID;
Cache *hcache = ts_hypertable_cache_pin();
Expand Down
8 changes: 6 additions & 2 deletions tsl/test/expected/cagg_errors.out
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ CREATE MATERIALIZED VIEW mat_m1 WITH (timescaledb.continuous, timescaledb.materi
as
select a, count(*) from mat_t1
group by a WITH NO DATA;
ERROR: table "mat_t1" is not a hypertable
ERROR: invalid continuous aggregate view
DETAIL: At least one hypertable should be used in the view definition.
-- no group by
CREATE MATERIALIZED VIEW mat_m1 WITH (timescaledb.continuous, timescaledb.materialized_only=false)
as
Expand Down Expand Up @@ -119,6 +120,7 @@ from
from conditions ) q
group by time_bucket('1week', timec) , location WITH NO DATA;
ERROR: invalid continuous aggregate view
DETAIL: Sub-queries are not supported in FROM clause.
CREATE MATERIALIZED VIEW mat_m1 WITH (timescaledb.continuous, timescaledb.materialized_only=false)
AS
select * from
Expand Down Expand Up @@ -194,13 +196,15 @@ from conditions tablesample bernoulli(0.2)
group by time_bucket('1week', timec) , location
WITH NO DATA;
ERROR: invalid continuous aggregate view
DETAIL: TABLESAMPLE is not supported in continuous aggregate.
-- ONLY in from clause
CREATE MATERIALIZED VIEW mat_m1 WITH (timescaledb.continuous, timescaledb.materialized_only=false)
AS
Select sum(humidity), avg(temperature::int4)
from ONLY conditions
group by time_bucket('1week', timec) , location WITH NO DATA;
ERROR: invalid continuous aggregate view
DETAIL: FROM ONLY on hypertables is not allowed in continuous aggregate.
--grouping sets and variants
CREATE MATERIALIZED VIEW mat_m1 WITH (timescaledb.continuous, timescaledb.materialized_only=false)
AS
Expand Down Expand Up @@ -645,7 +649,7 @@ ERROR: compression not enabled on "i2980"
-- cagg on normal view should error out
CREATE VIEW v1 AS SELECT now() AS time;
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous, timescaledb.materialized_only=false) AS SELECT time_bucket('1h',time) FROM v1 GROUP BY 1;
ERROR: invalid continuous aggregate query
ERROR: invalid continuous aggregate view
-- cagg on normal view should error out
CREATE MATERIALIZED VIEW matv1 AS SELECT now() AS time;
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous, timescaledb.materialized_only=false) AS SELECT time_bucket('1h',time) FROM matv1 GROUP BY 1;
Expand Down
Loading
Loading