Allow named time_bucket arguments in Cagg definition

Fixes #5450
This commit is contained in:
Konstantina Skovola 2023-03-28 16:27:00 +03:00 committed by Konstantina Skovola
parent 98218c1d07
commit cb81c331ae
5 changed files with 124 additions and 7 deletions

View File

@ -27,6 +27,7 @@ accidentally triggering the load of a previous DB version.**
* #5470 Ensure superuser perms during copy/move chunk * #5470 Ensure superuser perms during copy/move chunk
* #5459 Fix issue creating dimensional constraints * #5459 Fix issue creating dimensional constraints
* #5499 Do not segfault on large histogram() parameters * #5499 Do not segfault on large histogram() parameters
* #5497 Allow named time_bucket arguments in Cagg definition
**Thanks** **Thanks**
* @nikolaps for reporting an issue with the COPY fetcher * @nikolaps for reporting an issue with the COPY fetcher

View File

@ -764,6 +764,7 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
ListCell *l; ListCell *l;
bool found = false; bool found = false;
bool custom_origin = false; bool custom_origin = false;
Const *const_arg;
/* Make sure tbinfo was initialized. This assumption is used below. */ /* Make sure tbinfo was initialized. This assumption is used below. */
Assert(tbinfo->bucket_width == 0); Assert(tbinfo->bucket_width == 0);
@ -804,6 +805,9 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
/* Only column allowed : time_bucket('1day', <column> ) */ /* Only column allowed : time_bucket('1day', <column> ) */
col_arg = lsecond(fe->args); col_arg = lsecond(fe->args);
/* Could be a named argument */
if (IsA(col_arg, NamedArgExpr))
col_arg = (Node *) castNode(NamedArgExpr, col_arg)->arg;
if (!(IsA(col_arg, Var)) || ((Var *) col_arg)->varattno != tbinfo->htpartcolno) if (!(IsA(col_arg, Var)) || ((Var *) col_arg)->varattno != tbinfo->htpartcolno)
ereport(ERROR, ereport(ERROR,
@ -831,6 +835,7 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
if (list_length(fe->args) >= 4) if (list_length(fe->args) >= 4)
{ {
/* origin */
Const *arg = check_time_bucket_argument(lfourth(fe->args), "fourth"); Const *arg = check_time_bucket_argument(lfourth(fe->args), "fourth");
if (exprType((Node *) arg) == TEXTOID) if (exprType((Node *) arg) == TEXTOID)
{ {
@ -854,19 +859,22 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
/* Origin is always 3rd arg for date variants. */ /* Origin is always 3rd arg for date variants. */
if (list_length(fe->args) == 3) if (list_length(fe->args) == 3)
{ {
Node *arg = lthird(fe->args);
custom_origin = true; custom_origin = true;
/* this function also takes care of named arguments */
const_arg = check_time_bucket_argument(arg, "third");
tbinfo->origin = DatumGetTimestamp( tbinfo->origin = DatumGetTimestamp(
DirectFunctionCall1(date_timestamp, DirectFunctionCall1(date_timestamp, const_arg->constvalue));
castNode(Const, lthird(fe->args))->constvalue));
} }
break; break;
case TIMESTAMPOID: case TIMESTAMPOID:
/* Origin is always 3rd arg for timestamp variants. */ /* Origin is always 3rd arg for timestamp variants. */
if (list_length(fe->args) == 3) if (list_length(fe->args) == 3)
{ {
Node *arg = lthird(fe->args);
custom_origin = true; custom_origin = true;
tbinfo->origin = const_arg = check_time_bucket_argument(arg, "third");
DatumGetTimestamp(castNode(Const, lthird(fe->args))->constvalue); tbinfo->origin = DatumGetTimestamp(const_arg->constvalue);
} }
break; break;
case TIMESTAMPTZOID: case TIMESTAMPTZOID:
@ -881,8 +889,20 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
exprType(lfourth(fe->args)) == TIMESTAMPTZOID) exprType(lfourth(fe->args)) == TIMESTAMPTZOID)
{ {
custom_origin = true; custom_origin = true;
tbinfo->origin = if (IsA(lfourth(fe->args), Const))
DatumGetTimestampTz(castNode(Const, lfourth(fe->args))->constvalue); {
tbinfo->origin =
DatumGetTimestampTz(castNode(Const, lfourth(fe->args))->constvalue);
}
/* could happen in a statement like time_bucket('1h', .., 'utc', origin =>
* ...) */
else if (IsA(lfourth(fe->args), NamedArgExpr))
{
Const *constval =
check_time_bucket_argument(lfourth(fe->args), "fourth");
tbinfo->origin = DatumGetTimestampTz(constval->constvalue);
}
} }
} }
if (custom_origin && TIMESTAMP_NOT_FINITE(tbinfo->origin)) if (custom_origin && TIMESTAMP_NOT_FINITE(tbinfo->origin))
@ -898,7 +918,12 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
* partitioning column as int constants default to int4 and so expression would * partitioning column as int constants default to int4 and so expression would
* have a cast and not be a Const. * have a cast and not be a Const.
*/ */
width_arg = eval_const_expressions(NULL, linitial(fe->args)); width_arg = linitial(fe->args);
if (IsA(width_arg, NamedArgExpr))
width_arg = (Node *) castNode(NamedArgExpr, width_arg)->arg;
width_arg = eval_const_expressions(NULL, width_arg);
if (IsA(width_arg, Const)) if (IsA(width_arg, Const))
{ {
Const *width = castNode(Const, width_arg); Const *width = castNode(Const, width_arg);

View File

@ -1939,3 +1939,33 @@ SELECT * FROM cashflows;
Thu Nov 01 17:00:00 2018 PDT | 1 | 10 | 11 Thu Nov 01 17:00:00 2018 PDT | 1 | 10 | 11
(6 rows) (6 rows)
-- test cagg creation with named arguments in time_bucket
-- note that positional arguments cannot follow named arguments
-- 1. test named origin
-- 2. test named timezone
-- 3. test named ts
-- 4. test named bucket width
-- named origin
CREATE MATERIALIZED VIEW cagg_named_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named timezone
CREATE MATERIALIZED VIEW cagg_named_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named ts
CREATE MATERIALIZED VIEW cagg_named_ts_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named bucket width
CREATE MATERIALIZED VIEW cagg_named_all WITH
(timescaledb.continuous) AS
SELECT time_bucket(bucket_width => '1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;

View File

@ -1982,6 +1982,36 @@ SELECT * FROM cashflows;
Thu Nov 01 17:00:00 2018 PDT | 1 | 10 | 11 Thu Nov 01 17:00:00 2018 PDT | 1 | 10 | 11
(6 rows) (6 rows)
-- test cagg creation with named arguments in time_bucket
-- note that positional arguments cannot follow named arguments
-- 1. test named origin
-- 2. test named timezone
-- 3. test named ts
-- 4. test named bucket width
-- named origin
CREATE MATERIALIZED VIEW cagg_named_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named timezone
CREATE MATERIALIZED VIEW cagg_named_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named ts
CREATE MATERIALIZED VIEW cagg_named_ts_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named bucket width
CREATE MATERIALIZED VIEW cagg_named_all WITH
(timescaledb.continuous) AS
SELECT time_bucket(bucket_width => '1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- cleanup -- cleanup
\c :TEST_DBNAME :ROLE_CLUSTER_SUPERUSER; \c :TEST_DBNAME :ROLE_CLUSTER_SUPERUSER;
DROP DATABASE :DATA_NODE_1; DROP DATABASE :DATA_NODE_1;

View File

@ -1282,3 +1282,34 @@ WHERE user_view_name = 'cashflows'
\d+ 'cashflows' \d+ 'cashflows'
SELECT * FROM cashflows; SELECT * FROM cashflows;
-- test cagg creation with named arguments in time_bucket
-- note that positional arguments cannot follow named arguments
-- 1. test named origin
-- 2. test named timezone
-- 3. test named ts
-- 4. test named bucket width
-- named origin
CREATE MATERIALIZED VIEW cagg_named_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named timezone
CREATE MATERIALIZED VIEW cagg_named_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named ts
CREATE MATERIALIZED VIEW cagg_named_ts_tz_origin WITH
(timescaledb.continuous) AS
SELECT time_bucket('1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;
-- named bucket width
CREATE MATERIALIZED VIEW cagg_named_all WITH
(timescaledb.continuous) AS
SELECT time_bucket(bucket_width => '1h', ts => time, timezone => 'UTC', origin => '2001-01-03 01:23:45') AS bucket,
avg(amount) as avg_amount
FROM transactions GROUP BY 1 WITH NO DATA;