mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-18 03:23:37 +08:00
Add timezone support to time_bucket
This patch adds a new function time_bucket(period,timestamp,timezone) which supports bucketing for arbitrary timezones.
This commit is contained in:
parent
dc145b7485
commit
5d934baf1d
@ -11,6 +11,7 @@ accidentally triggering the load of a previous DB version.**
|
|||||||
* #4393 Support intervals with day component when constifying now()
|
* #4393 Support intervals with day component when constifying now()
|
||||||
* #4397 Support intervals with month component when constifying now()
|
* #4397 Support intervals with month component when constifying now()
|
||||||
* #4641 Allow bucketing by month in time_bucket
|
* #4641 Allow bucketing by month in time_bucket
|
||||||
|
* #4642 Add timezone support to time_bucket
|
||||||
|
|
||||||
**Bugfixes**
|
**Bugfixes**
|
||||||
* #4416 Handle TRUNCATE TABLE on chunks
|
* #4416 Handle TRUNCATE TABLE on chunks
|
||||||
|
@ -23,6 +23,10 @@ CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width INTERVAL, ts TIM
|
|||||||
CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width INTERVAL, ts DATE, origin DATE) RETURNS DATE
|
CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width INTERVAL, ts DATE, origin DATE) RETURNS DATE
|
||||||
AS '@MODULE_PATHNAME@', 'ts_date_bucket' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
AS '@MODULE_PATHNAME@', 'ts_date_bucket' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||||
|
|
||||||
|
-- bucketing with timezone
|
||||||
|
CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width INTERVAL, ts TIMESTAMPTZ, timezone TEXT, origin TIMESTAMPTZ DEFAULT NULL, "offset" INTERVAL DEFAULT NULL) RETURNS TIMESTAMPTZ
|
||||||
|
AS '@MODULE_PATHNAME@', 'ts_timestamptz_timezone_bucket' LANGUAGE C IMMUTABLE PARALLEL SAFE;
|
||||||
|
|
||||||
-- bucketing of int
|
-- bucketing of int
|
||||||
CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width SMALLINT, ts SMALLINT) RETURNS SMALLINT
|
CREATE OR REPLACE FUNCTION @extschema@.time_bucket(bucket_width SMALLINT, ts SMALLINT) RETURNS SMALLINT
|
||||||
AS '@MODULE_PATHNAME@', 'ts_int16_bucket' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
AS '@MODULE_PATHNAME@', 'ts_int16_bucket' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||||
|
@ -154,7 +154,6 @@ GRANT SELECT ON _timescaledb_catalog.chunk TO PUBLIC;
|
|||||||
|
|
||||||
-- end recreate _timescaledb_catalog.chunk table --
|
-- end recreate _timescaledb_catalog.chunk table --
|
||||||
|
|
||||||
|
|
||||||
ALTER TABLE _timescaledb_internal.bgw_job_stat
|
ALTER TABLE _timescaledb_internal.bgw_job_stat
|
||||||
DROP CONSTRAINT bgw_job_stat_job_id_fkey;
|
DROP CONSTRAINT bgw_job_stat_job_id_fkey;
|
||||||
ALTER TABLE _timescaledb_internal.bgw_policy_chunk_stats
|
ALTER TABLE _timescaledb_internal.bgw_policy_chunk_stats
|
||||||
@ -246,3 +245,6 @@ CREATE FUNCTION @extschema@.alter_job(
|
|||||||
RETURNS TABLE (job_id INTEGER, schedule_interval INTERVAL, max_runtime INTERVAL, max_retries INTEGER, retry_period INTERVAL, scheduled BOOL, config JSONB, next_start TIMESTAMPTZ)
|
RETURNS TABLE (job_id INTEGER, schedule_interval INTERVAL, max_runtime INTERVAL, max_retries INTEGER, retry_period INTERVAL, scheduled BOOL, config JSONB, next_start TIMESTAMPTZ)
|
||||||
AS '@MODULE_PATHNAME@', 'ts_job_alter'
|
AS '@MODULE_PATHNAME@', 'ts_job_alter'
|
||||||
LANGUAGE C VOLATILE;
|
LANGUAGE C VOLATILE;
|
||||||
|
|
||||||
|
DROP FUNCTION @extschema@.time_bucket(INTERVAL, TIMESTAMPTZ, TEXT, TIMESTAMPTZ, INTERVAL);
|
||||||
|
|
||||||
|
@ -355,6 +355,11 @@ get_reindex_options(ReindexStmt *stmt)
|
|||||||
#define list_make5_int(x1, x2, x3, x4, x5) lappend_int(list_make4_int(x1, x2, x3, x4), x5)
|
#define list_make5_int(x1, x2, x3, x4, x5) lappend_int(list_make4_int(x1, x2, x3, x4), x5)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* define lfifth macro for convenience
|
||||||
|
*/
|
||||||
|
#define lfifth(l) lfirst(list_nth_cell(l, 4))
|
||||||
|
|
||||||
/* PG13 removes the natts parameter from map_variable_attnos */
|
/* PG13 removes the natts parameter from map_variable_attnos */
|
||||||
#if PG13_LT
|
#if PG13_LT
|
||||||
#define map_variable_attnos_compat(node, varno, sublevels_up, map, natts, rowtype, found_wholerow) \
|
#define map_variable_attnos_compat(node, varno, sublevels_up, map, natts, rowtype, found_wholerow) \
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <utils/selfuncs.h>
|
#include <utils/selfuncs.h>
|
||||||
#include <utils/syscache.h>
|
#include <utils/syscache.h>
|
||||||
|
|
||||||
|
#include "compat/compat.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "func_cache.h"
|
#include "func_cache.h"
|
||||||
@ -108,6 +109,22 @@ time_bucket_sort_transform(FuncExpr *func)
|
|||||||
return do_sort_transform(func);
|
return do_sort_transform(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* time_bucket with timezone will always have 5 args. For the sort
|
||||||
|
* optimization to apply all args need to be Const except timestamp.
|
||||||
|
*/
|
||||||
|
static Expr *
|
||||||
|
time_bucket_tz_sort_transform(FuncExpr *func)
|
||||||
|
{
|
||||||
|
Assert(list_length(func->args) == 5);
|
||||||
|
|
||||||
|
if (!IsA(linitial((func)->args), Const) || !IsA(lthird(func->args), Const) ||
|
||||||
|
!IsA(lfourth(func->args), Const) || !IsA(lfifth(func->args), Const))
|
||||||
|
return (Expr *) func;
|
||||||
|
|
||||||
|
return do_sort_transform(func);
|
||||||
|
}
|
||||||
|
|
||||||
/* For time_bucket this estimate currently works by seeing how many possible
|
/* For time_bucket this estimate currently works by seeing how many possible
|
||||||
* buckets there will be if the data spans the entire hypertable. Note that
|
* buckets there will be if the data spans the entire hypertable. Note that
|
||||||
* this is an overestimate.
|
* this is an overestimate.
|
||||||
@ -295,6 +312,16 @@ static FuncInfo funcinfo[] = {
|
|||||||
.group_estimate = time_bucket_group_estimate,
|
.group_estimate = time_bucket_group_estimate,
|
||||||
.sort_transform = time_bucket_sort_transform,
|
.sort_transform = time_bucket_sort_transform,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.origin = ORIGIN_TIMESCALE,
|
||||||
|
.is_bucketing_func = true,
|
||||||
|
.allowed_in_cagg_definition = true,
|
||||||
|
.funcname = "time_bucket",
|
||||||
|
.nargs = 5,
|
||||||
|
.arg_types = { INTERVALOID, TIMESTAMPTZOID, TEXTOID, TIMESTAMPTZOID, INTERVALOID },
|
||||||
|
.group_estimate = time_bucket_group_estimate,
|
||||||
|
.sort_transform = time_bucket_tz_sort_transform,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.origin = ORIGIN_TIMESCALE_EXPERIMENTAL,
|
.origin = ORIGIN_TIMESCALE_EXPERIMENTAL,
|
||||||
.is_bucketing_func = true,
|
.is_bucketing_func = true,
|
||||||
|
@ -434,6 +434,9 @@ transform_time_bucket_comparison(PlannerInfo *root, OpExpr *op)
|
|||||||
{
|
{
|
||||||
Interval *interval = DatumGetIntervalP(width->constvalue);
|
Interval *interval = DatumGetIntervalP(width->constvalue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optimization can't be applied when interval has month component.
|
||||||
|
*/
|
||||||
if (interval->month != 0)
|
if (interval->month != 0)
|
||||||
return op;
|
return op;
|
||||||
|
|
||||||
@ -466,7 +469,7 @@ transform_time_bucket_comparison(PlannerInfo *root, OpExpr *op)
|
|||||||
Assert(width->consttype == INTERVALOID);
|
Assert(width->consttype == INTERVALOID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* intervals with month component are not supported by time_bucket
|
* Optimization can't be applied when interval has month component.
|
||||||
*/
|
*/
|
||||||
if (interval->month != 0)
|
if (interval->month != 0)
|
||||||
return op;
|
return op;
|
||||||
@ -513,7 +516,7 @@ transform_time_bucket_comparison(PlannerInfo *root, OpExpr *op)
|
|||||||
Assert(width->consttype == INTERVALOID);
|
Assert(width->consttype == INTERVALOID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* intervals with month component are not supported by time_bucket
|
* Optimization can't be applied when interval has month component.
|
||||||
*/
|
*/
|
||||||
if (interval->month != 0)
|
if (interval->month != 0)
|
||||||
return op;
|
return op;
|
||||||
|
@ -281,6 +281,64 @@ ts_timestamptz_bucket(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TS_FUNCTION_INFO_V1(ts_timestamptz_timezone_bucket);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* time_bucket(bucket_width INTERVAL, ts TIMESTAMPTZ, timezone TEXT, origin TIMESTAMPTZ DEFAULT
|
||||||
|
* NULL, "offset" INTERVAL DEFAULT NULL) RETURNS TIMESTAMPTZ
|
||||||
|
*/
|
||||||
|
TSDLLEXPORT Datum
|
||||||
|
ts_timestamptz_timezone_bucket(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Datum period = PG_GETARG_DATUM(0);
|
||||||
|
Datum timestamp = PG_GETARG_DATUM(1);
|
||||||
|
Datum tzname = PG_GETARG_DATUM(2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When called from SQL we will always have 5 args because default values
|
||||||
|
* will be filled in for missing arguments. When called from C with
|
||||||
|
* DirectFunctionCall number of arguments might be less than 5.
|
||||||
|
*/
|
||||||
|
bool have_origin = PG_NARGS() > 3 && !PG_ARGISNULL(3);
|
||||||
|
bool have_offset = PG_NARGS() > 4 && !PG_ARGISNULL(4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to check for NULL arguments here because the function cannot be
|
||||||
|
* defined STRICT due to the optional arguments.
|
||||||
|
*/
|
||||||
|
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
|
/* Convert to local timestamp according to timezone */
|
||||||
|
timestamp = DirectFunctionCall2(timestamptz_zone, tzname, timestamp);
|
||||||
|
if (have_offset)
|
||||||
|
{
|
||||||
|
/* Apply offset. */
|
||||||
|
timestamp = DirectFunctionCall2(timestamp_mi_interval, timestamp, PG_GETARG_DATUM(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_origin)
|
||||||
|
{
|
||||||
|
Datum origin = DirectFunctionCall2(timestamptz_zone, tzname, PG_GETARG_DATUM(3));
|
||||||
|
timestamp = DirectFunctionCall3(ts_timestamp_bucket, period, timestamp, origin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timestamp = DirectFunctionCall2(ts_timestamp_bucket, period, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_offset)
|
||||||
|
{
|
||||||
|
/* Remove offset. */
|
||||||
|
timestamp = DirectFunctionCall2(timestamp_pl_interval, timestamp, PG_GETARG_DATUM(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert back to timezone */
|
||||||
|
timestamp = DirectFunctionCall2(timestamp_zone, tzname, timestamp);
|
||||||
|
|
||||||
|
PG_RETURN_DATUM(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
check_period_is_daily(int64 period)
|
check_period_is_daily(int64 period)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@ extern TSDLLEXPORT Datum ts_int64_bucket(PG_FUNCTION_ARGS);
|
|||||||
extern TSDLLEXPORT Datum ts_date_bucket(PG_FUNCTION_ARGS);
|
extern TSDLLEXPORT Datum ts_date_bucket(PG_FUNCTION_ARGS);
|
||||||
extern TSDLLEXPORT Datum ts_timestamp_bucket(PG_FUNCTION_ARGS);
|
extern TSDLLEXPORT Datum ts_timestamp_bucket(PG_FUNCTION_ARGS);
|
||||||
extern TSDLLEXPORT Datum ts_timestamptz_bucket(PG_FUNCTION_ARGS);
|
extern TSDLLEXPORT Datum ts_timestamptz_bucket(PG_FUNCTION_ARGS);
|
||||||
|
extern TSDLLEXPORT Datum ts_timestamptz_timezone_bucket(PG_FUNCTION_ARGS);
|
||||||
extern TSDLLEXPORT int64 ts_time_bucket_by_type(int64 interval, int64 timestamp, Oid type);
|
extern TSDLLEXPORT int64 ts_time_bucket_by_type(int64 interval, int64 timestamp, Oid type);
|
||||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_date(PG_FUNCTION_ARGS);
|
extern TSDLLEXPORT Datum ts_time_bucket_ng_date(PG_FUNCTION_ARGS);
|
||||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS);
|
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS);
|
||||||
|
@ -1541,11 +1541,52 @@ ts_continuous_agg_bucket_width(const ContinuousAgg *agg)
|
|||||||
* a common procedure used by ts_compute_* below.
|
* a common procedure used by ts_compute_* below.
|
||||||
*/
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
generic_time_bucket_ng(const ContinuousAggsBucketFunction *bf, Datum timestamp)
|
generic_time_bucket(const ContinuousAggsBucketFunction *bf, Datum timestamp)
|
||||||
{
|
{
|
||||||
/* bf->timezone can't be NULL. If timezone is not specified, "" is stored */
|
/* bf->timezone can't be NULL. If timezone is not specified, "" is stored */
|
||||||
Assert(bf->timezone != NULL);
|
Assert(bf->timezone != NULL);
|
||||||
|
|
||||||
|
if (!bf->experimental)
|
||||||
|
{
|
||||||
|
if (strlen(bf->timezone) > 0)
|
||||||
|
{
|
||||||
|
if (TIMESTAMP_NOT_FINITE(bf->origin))
|
||||||
|
{
|
||||||
|
/* using default origin */
|
||||||
|
return DirectFunctionCall3(ts_timestamptz_timezone_bucket,
|
||||||
|
IntervalPGetDatum(bf->bucket_width),
|
||||||
|
timestamp,
|
||||||
|
CStringGetTextDatum(bf->timezone));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* custom origin specified */
|
||||||
|
return DirectFunctionCall4(ts_timestamptz_timezone_bucket,
|
||||||
|
IntervalPGetDatum(bf->bucket_width),
|
||||||
|
timestamp,
|
||||||
|
CStringGetTextDatum(bf->timezone),
|
||||||
|
TimestampTzGetDatum((TimestampTz) bf->origin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIMESTAMP_NOT_FINITE(bf->origin))
|
||||||
|
{
|
||||||
|
/* using default origin */
|
||||||
|
return DirectFunctionCall2(ts_timestamp_bucket,
|
||||||
|
IntervalPGetDatum(bf->bucket_width),
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* custom origin specified */
|
||||||
|
return DirectFunctionCall3(ts_timestamp_bucket,
|
||||||
|
IntervalPGetDatum(bf->bucket_width),
|
||||||
|
timestamp,
|
||||||
|
TimestampGetDatum(bf->origin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (strlen(bf->timezone) > 0)
|
if (strlen(bf->timezone) > 0)
|
||||||
{
|
{
|
||||||
if (TIMESTAMP_NOT_FINITE(bf->origin))
|
if (TIMESTAMP_NOT_FINITE(bf->origin))
|
||||||
@ -1583,6 +1624,7 @@ generic_time_bucket_ng(const ContinuousAggsBucketFunction *bf, Datum timestamp)
|
|||||||
TimestampGetDatum(bf->origin));
|
TimestampGetDatum(bf->origin));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds one bf->bucket_size interval to the timestamp. This is a common
|
* Adds one bf->bucket_size interval to the timestamp. This is a common
|
||||||
@ -1650,8 +1692,8 @@ ts_compute_inscribed_bucketed_refresh_window_variable(int64 *start, int64 *end,
|
|||||||
start_old = ts_internal_to_time_value(*start, TIMESTAMPOID);
|
start_old = ts_internal_to_time_value(*start, TIMESTAMPOID);
|
||||||
end_old = ts_internal_to_time_value(*end, TIMESTAMPOID);
|
end_old = ts_internal_to_time_value(*end, TIMESTAMPOID);
|
||||||
|
|
||||||
start_new = generic_time_bucket_ng(bf, start_old);
|
start_new = generic_time_bucket(bf, start_old);
|
||||||
end_new = generic_time_bucket_ng(bf, end_old);
|
end_new = generic_time_bucket(bf, end_old);
|
||||||
|
|
||||||
if (DatumGetTimestamp(start_new) != DatumGetTimestamp(start_old))
|
if (DatumGetTimestamp(start_new) != DatumGetTimestamp(start_old))
|
||||||
{
|
{
|
||||||
@ -1684,8 +1726,8 @@ ts_compute_circumscribed_bucketed_refresh_window_variable(int64 *start, int64 *e
|
|||||||
*/
|
*/
|
||||||
start_old = ts_internal_to_time_value(*start, TIMESTAMPOID);
|
start_old = ts_internal_to_time_value(*start, TIMESTAMPOID);
|
||||||
end_old = ts_internal_to_time_value(*end, TIMESTAMPOID);
|
end_old = ts_internal_to_time_value(*end, TIMESTAMPOID);
|
||||||
start_new = generic_time_bucket_ng(bf, start_old);
|
start_new = generic_time_bucket(bf, start_old);
|
||||||
end_new = generic_time_bucket_ng(bf, end_old);
|
end_new = generic_time_bucket(bf, end_old);
|
||||||
|
|
||||||
if (DatumGetTimestamp(end_new) != DatumGetTimestamp(end_old))
|
if (DatumGetTimestamp(end_new) != DatumGetTimestamp(end_old))
|
||||||
{
|
{
|
||||||
@ -1716,7 +1758,7 @@ ts_compute_beginning_of_the_next_bucket_variable(int64 timeval,
|
|||||||
*/
|
*/
|
||||||
val_old = ts_internal_to_time_value(timeval, TIMESTAMPOID);
|
val_old = ts_internal_to_time_value(timeval, TIMESTAMPOID);
|
||||||
|
|
||||||
val_new = generic_time_bucket_ng(bf, val_old);
|
val_new = generic_time_bucket(bf, val_old);
|
||||||
val_new = generic_add_interval(bf, val_new);
|
val_new = generic_add_interval(bf, val_new);
|
||||||
return ts_time_value_to_internal(val_new, TIMESTAMPOID);
|
return ts_time_value_to_internal(val_new, TIMESTAMPOID);
|
||||||
}
|
}
|
||||||
|
@ -1284,6 +1284,117 @@ FROM generate_series('1990-01-03'::timestamptz,'1990-06-03'::timestamptz,'1month
|
|||||||
1990-06-03 00:00:00-04 | 1990-05-31 20:00:00-04 | 1990-04-30 20:00:00-04 | 1990-03-31 19:00:00-05 | 1990-05-31 20:00:00-04 | 1990-05-31 20:00:00-04 | 1990-04-30 20:00:00-04
|
1990-06-03 00:00:00-04 | 1990-05-31 20:00:00-04 | 1990-04-30 20:00:00-04 | 1990-03-31 19:00:00-05 | 1990-05-31 20:00:00-04 | 1990-05-31 20:00:00-04 | 1990-04-30 20:00:00-04
|
||||||
(6 rows)
|
(6 rows)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
--- Test time_bucket with timezones ---
|
||||||
|
---------------------------------------
|
||||||
|
-- test NULL args
|
||||||
|
SELECT
|
||||||
|
time_bucket(NULL::interval,now(),'Europe/Berlin'),
|
||||||
|
time_bucket('1day',NULL::timestamptz,'Europe/Berlin'),
|
||||||
|
time_bucket('1day',now(),NULL::text),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin','2020-04-01',NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',NULL,NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',"offset":=NULL::interval),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',origin:=NULL::timestamptz);
|
||||||
|
time_bucket | time_bucket | time_bucket | time_bucket | time_bucket | time_bucket | time_bucket | time_bucket
|
||||||
|
-------------+-------------+-------------+------------------------+------------------------+------------------------+------------------------+------------------------
|
||||||
|
| | | 2020-02-02 18:00:00-05 | 2020-02-03 00:00:00-05 | 2020-02-02 18:00:00-05 | 2020-02-02 18:00:00-05 | 2020-02-02 18:00:00-05
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET datestyle TO ISO;
|
||||||
|
SELECT
|
||||||
|
time_bucket('1day', ts) AS "UTC",
|
||||||
|
time_bucket('1day', ts, 'Europe/Berlin') AS "Berlin",
|
||||||
|
time_bucket('1day', ts, 'Europe/London') AS "London",
|
||||||
|
time_bucket('1day', ts, 'America/New_York') AS "New York",
|
||||||
|
time_bucket('1day', ts, 'PST') AS "PST",
|
||||||
|
time_bucket('1day', ts, current_setting('timezone')) AS "current"
|
||||||
|
FROM generate_series('1999-12-31 17:00'::timestamptz,'2000-01-02 3:00'::timestamptz, '1hour'::interval) ts;
|
||||||
|
UTC | Berlin | London | New York | PST | current
|
||||||
|
------------------------+------------------------+------------------------+------------------------+------------------------+------------------------
|
||||||
|
1999-12-30 19:00:00-05 | 1999-12-30 18:00:00-05 | 1999-12-30 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-30 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-30 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 1999-12-31 00:00:00-05 | 1999-12-31 03:00:00-05 | 1999-12-31 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-31 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-31 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-31 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 2000-01-01 18:00:00-05 | 1999-12-31 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-01 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-02 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-02 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-02 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-02 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-02 00:00:00-05 | 2000-01-01 03:00:00-05 | 2000-01-02 00:00:00-05
|
||||||
|
2000-01-01 19:00:00-05 | 2000-01-01 18:00:00-05 | 2000-01-01 19:00:00-05 | 2000-01-02 00:00:00-05 | 2000-01-02 03:00:00-05 | 2000-01-02 00:00:00-05
|
||||||
|
(35 rows)
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
time_bucket('1month', ts) AS "UTC",
|
||||||
|
time_bucket('1month', ts, 'Europe/Berlin') AS "Berlin",
|
||||||
|
time_bucket('1month', ts, 'America/New_York') AS "New York",
|
||||||
|
time_bucket('1month', ts, current_setting('timezone')) AS "current",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone')) AS "2m",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), '2000-02-01'::timestamp) AS "2m origin",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), "offset":='14 day'::interval) AS "2m offset",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), '2000-02-01'::timestamp, '7 day'::interval) AS "2m offset + origin"
|
||||||
|
FROM generate_series('1999-12-01'::timestamptz,'2000-09-01'::timestamptz, '9 day'::interval) ts;
|
||||||
|
UTC | Berlin | New York | current | 2m | 2m origin | 2m offset | 2m offset + origin
|
||||||
|
------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+------------------------+------------------------
|
||||||
|
1999-11-30 19:00:00-05 | 1999-11-30 18:00:00-05 | 1999-12-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-15 00:00:00-05 | 1999-10-08 00:00:00-04
|
||||||
|
1999-11-30 19:00:00-05 | 1999-11-30 18:00:00-05 | 1999-12-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
1999-11-30 19:00:00-05 | 1999-11-30 18:00:00-05 | 1999-12-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
1999-11-30 19:00:00-05 | 1999-11-30 18:00:00-05 | 1999-12-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 1999-11-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
1999-12-31 19:00:00-05 | 1999-12-31 18:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 1999-12-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
2000-01-31 19:00:00-05 | 2000-01-31 18:00:00-05 | 2000-02-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 1999-12-08 00:00:00-05
|
||||||
|
2000-01-31 19:00:00-05 | 2000-01-31 18:00:00-05 | 2000-02-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-01-31 19:00:00-05 | 2000-01-31 18:00:00-05 | 2000-02-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-01-31 19:00:00-05 | 2000-01-31 18:00:00-05 | 2000-02-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-02-29 19:00:00-05 | 2000-02-29 18:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-01-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-02-29 19:00:00-05 | 2000-02-29 18:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-02-29 19:00:00-05 | 2000-02-29 18:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-02-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-03-31 19:00:00-05 | 2000-03-31 17:00:00-05 | 2000-04-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-02-08 00:00:00-05
|
||||||
|
2000-03-31 19:00:00-05 | 2000-03-31 17:00:00-05 | 2000-04-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-04-08 00:00:00-04
|
||||||
|
2000-03-31 19:00:00-05 | 2000-03-31 17:00:00-05 | 2000-04-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-01 00:00:00-05 | 2000-04-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-04-08 00:00:00-04
|
||||||
|
2000-04-30 20:00:00-04 | 2000-04-30 18:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-04-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-04-08 00:00:00-04
|
||||||
|
2000-04-30 20:00:00-04 | 2000-04-30 18:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-04-01 00:00:00-05 | 2000-03-15 00:00:00-05 | 2000-04-08 00:00:00-04
|
||||||
|
2000-04-30 20:00:00-04 | 2000-04-30 18:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-04-01 00:00:00-05 | 2000-05-15 00:00:00-04 | 2000-04-08 00:00:00-04
|
||||||
|
2000-04-30 20:00:00-04 | 2000-04-30 18:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-04-01 00:00:00-05 | 2000-05-15 00:00:00-04 | 2000-04-08 00:00:00-04
|
||||||
|
2000-05-31 20:00:00-04 | 2000-05-31 18:00:00-04 | 2000-06-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-15 00:00:00-04 | 2000-04-08 00:00:00-04
|
||||||
|
2000-05-31 20:00:00-04 | 2000-05-31 18:00:00-04 | 2000-06-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-05-31 20:00:00-04 | 2000-05-31 18:00:00-04 | 2000-06-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-06-30 20:00:00-04 | 2000-06-30 18:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-06-30 20:00:00-04 | 2000-06-30 18:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-05-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-06-30 20:00:00-04 | 2000-06-30 18:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-07-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-06-30 20:00:00-04 | 2000-06-30 18:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-06-01 00:00:00-04 | 2000-07-15 00:00:00-04 | 2000-06-08 00:00:00-04
|
||||||
|
2000-07-31 20:00:00-04 | 2000-07-31 18:00:00-04 | 2000-08-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-15 00:00:00-04 | 2000-08-08 00:00:00-04
|
||||||
|
2000-07-31 20:00:00-04 | 2000-07-31 18:00:00-04 | 2000-08-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-15 00:00:00-04 | 2000-08-08 00:00:00-04
|
||||||
|
2000-07-31 20:00:00-04 | 2000-07-31 18:00:00-04 | 2000-08-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-01 00:00:00-04 | 2000-08-01 00:00:00-04 | 2000-07-15 00:00:00-04 | 2000-08-08 00:00:00-04
|
||||||
|
(31 rows)
|
||||||
|
|
||||||
RESET datestyle;
|
RESET datestyle;
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
--- Test timescaledb_experimental.time_bucket_ng function --
|
--- Test timescaledb_experimental.time_bucket_ng function --
|
||||||
|
@ -634,6 +634,44 @@ SELECT
|
|||||||
time_bucket('3 month', time, '2000-02-01'::timestamptz) AS "3m origin"
|
time_bucket('3 month', time, '2000-02-01'::timestamptz) AS "3m origin"
|
||||||
FROM generate_series('1990-01-03'::timestamptz,'1990-06-03'::timestamptz,'1month'::interval) time;
|
FROM generate_series('1990-01-03'::timestamptz,'1990-06-03'::timestamptz,'1month'::interval) time;
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
--- Test time_bucket with timezones ---
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
-- test NULL args
|
||||||
|
SELECT
|
||||||
|
time_bucket(NULL::interval,now(),'Europe/Berlin'),
|
||||||
|
time_bucket('1day',NULL::timestamptz,'Europe/Berlin'),
|
||||||
|
time_bucket('1day',now(),NULL::text),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin','2020-04-01',NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',NULL,NULL),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',"offset":=NULL::interval),
|
||||||
|
time_bucket('1day','2020-02-03','Europe/Berlin',origin:=NULL::timestamptz);
|
||||||
|
|
||||||
|
SET datestyle TO ISO;
|
||||||
|
SELECT
|
||||||
|
time_bucket('1day', ts) AS "UTC",
|
||||||
|
time_bucket('1day', ts, 'Europe/Berlin') AS "Berlin",
|
||||||
|
time_bucket('1day', ts, 'Europe/London') AS "London",
|
||||||
|
time_bucket('1day', ts, 'America/New_York') AS "New York",
|
||||||
|
time_bucket('1day', ts, 'PST') AS "PST",
|
||||||
|
time_bucket('1day', ts, current_setting('timezone')) AS "current"
|
||||||
|
|
||||||
|
FROM generate_series('1999-12-31 17:00'::timestamptz,'2000-01-02 3:00'::timestamptz, '1hour'::interval) ts;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
time_bucket('1month', ts) AS "UTC",
|
||||||
|
time_bucket('1month', ts, 'Europe/Berlin') AS "Berlin",
|
||||||
|
time_bucket('1month', ts, 'America/New_York') AS "New York",
|
||||||
|
time_bucket('1month', ts, current_setting('timezone')) AS "current",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone')) AS "2m",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), '2000-02-01'::timestamp) AS "2m origin",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), "offset":='14 day'::interval) AS "2m offset",
|
||||||
|
time_bucket('2month', ts, current_setting('timezone'), '2000-02-01'::timestamp, '7 day'::interval) AS "2m offset + origin"
|
||||||
|
|
||||||
|
FROM generate_series('1999-12-01'::timestamptz,'2000-09-01'::timestamptz, '9 day'::interval) ts;
|
||||||
|
|
||||||
RESET datestyle;
|
RESET datestyle;
|
||||||
|
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <catalog/indexing.h>
|
#include <catalog/indexing.h>
|
||||||
#include <catalog/pg_aggregate.h>
|
#include <catalog/pg_aggregate.h>
|
||||||
#include <catalog/pg_collation.h>
|
#include <catalog/pg_collation.h>
|
||||||
|
#include <catalog/pg_namespace.h>
|
||||||
#include <catalog/pg_trigger.h>
|
#include <catalog/pg_trigger.h>
|
||||||
#include <catalog/pg_type.h>
|
#include <catalog/pg_type.h>
|
||||||
#include <catalog/toasting.h>
|
#include <catalog/toasting.h>
|
||||||
@ -184,6 +185,7 @@ typedef struct CAggTimebucketInfo
|
|||||||
Interval *interval; /* stores the interval, NULL if not specified */
|
Interval *interval; /* stores the interval, NULL if not specified */
|
||||||
const char *timezone; /* the name of the timezone, NULL if not specified */
|
const char *timezone; /* the name of the timezone, NULL if not specified */
|
||||||
|
|
||||||
|
FuncExpr *bucket_func; /* function call expr of the bucketing function */
|
||||||
/*
|
/*
|
||||||
* Custom origin value stored as UTC timestamp.
|
* Custom origin value stored as UTC timestamp.
|
||||||
* If not specified, stores infinity.
|
* If not specified, stores infinity.
|
||||||
@ -712,6 +714,24 @@ caggtimebucketinfo_init(CAggTimebucketInfo *src, int32 hypertable_id, Oid hypert
|
|||||||
TIMESTAMP_NOBEGIN(src->origin); /* origin is not specified by default */
|
TIMESTAMP_NOBEGIN(src->origin); /* origin is not specified by default */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Const *
|
||||||
|
check_time_bucket_argument(Node *arg, char *position)
|
||||||
|
{
|
||||||
|
if (IsA(arg, NamedArgExpr))
|
||||||
|
arg = (Node *) castNode(NamedArgExpr, arg)->arg;
|
||||||
|
|
||||||
|
Node *expr = eval_const_expressions(NULL, arg);
|
||||||
|
|
||||||
|
if (!IsA(expr, Const))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("only immutable expressions allowed in time bucket function"),
|
||||||
|
errhint("Use an immutable expression as %s argument to the time bucket function.",
|
||||||
|
position)));
|
||||||
|
|
||||||
|
return castNode(Const, expr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the group-by clauses has exactly 1 time_bucket(.., <col>) where
|
* Check if the group-by clauses has exactly 1 time_bucket(.., <col>) where
|
||||||
* <col> is the hypertable's partitioning column and other invariants. Then fill
|
* <col> is the hypertable's partitioning column and other invariants. Then fill
|
||||||
@ -722,6 +742,7 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
{
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
bool custom_origin = false;
|
||||||
|
|
||||||
/* 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);
|
||||||
@ -737,11 +758,18 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
FuncExpr *fe = ((FuncExpr *) tle->expr);
|
FuncExpr *fe = ((FuncExpr *) tle->expr);
|
||||||
Node *width_arg;
|
Node *width_arg;
|
||||||
Node *col_arg;
|
Node *col_arg;
|
||||||
Node *tz_arg;
|
|
||||||
|
|
||||||
if (!function_allowed_in_cagg_definition(fe->funcid))
|
if (!function_allowed_in_cagg_definition(fe->funcid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* offset variants of time_bucket functions are not
|
||||||
|
* supported at the moment.
|
||||||
|
*/
|
||||||
|
if (list_length(fe->args) >= 5 ||
|
||||||
|
(list_length(fe->args) == 4 && exprType(lfourth(fe->args)) == INTERVALOID))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
@ -750,6 +778,8 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
else
|
else
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
|
tbinfo->bucket_func = fe;
|
||||||
|
|
||||||
/*only column allowed : time_bucket('1day', <column> ) */
|
/*only column allowed : time_bucket('1day', <column> ) */
|
||||||
col_arg = lsecond(fe->args);
|
col_arg = lsecond(fe->args);
|
||||||
|
|
||||||
@ -759,54 +789,12 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
errmsg(
|
errmsg(
|
||||||
"time bucket function must reference a hypertable dimension column")));
|
"time bucket function must reference a hypertable dimension column")));
|
||||||
|
|
||||||
if (list_length(fe->args) == 4)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Timezone and custom origin are specified. In this clause we
|
|
||||||
* save only the timezone. Origin is processed in the following
|
|
||||||
* clause.
|
|
||||||
*/
|
|
||||||
tz_arg = eval_const_expressions(NULL, lfourth(fe->args));
|
|
||||||
|
|
||||||
if (!IsA(tz_arg, Const))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("only immutable expressions allowed in time bucket function"),
|
|
||||||
errhint("Use an immutable expression as fourth argument"
|
|
||||||
" to the time bucket function.")));
|
|
||||||
|
|
||||||
Const *tz = castNode(Const, tz_arg);
|
|
||||||
|
|
||||||
/* This is assured by function_allowed_in_cagg_definition() above. */
|
|
||||||
Assert(tz->consttype == TEXTOID);
|
|
||||||
const char *tz_name = TextDatumGetCString(tz->constvalue);
|
|
||||||
if (!ts_is_valid_timezone_name(tz_name))
|
|
||||||
{
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("invalid timezone name \"%s\"", tz_name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
tbinfo->timezone = tz_name;
|
|
||||||
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list_length(fe->args) >= 3)
|
if (list_length(fe->args) >= 3)
|
||||||
{
|
{
|
||||||
tz_arg = eval_const_expressions(NULL, lthird(fe->args));
|
Const *arg = check_time_bucket_argument(lthird(fe->args), "third");
|
||||||
if (!IsA(tz_arg, Const))
|
if (exprType((Node *) arg) == TEXTOID)
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("only immutable expressions allowed in time bucket function"),
|
|
||||||
errhint("Use an immutable expression as third argument"
|
|
||||||
" to the time bucket function.")));
|
|
||||||
|
|
||||||
Const *tz = castNode(Const, tz_arg);
|
|
||||||
if ((tz->consttype == TEXTOID) && (list_length(fe->args) == 3))
|
|
||||||
{
|
{
|
||||||
/* Timezone specified */
|
const char *tz_name = TextDatumGetCString(arg->constvalue);
|
||||||
const char *tz_name = TextDatumGetCString(tz->constvalue);
|
|
||||||
|
|
||||||
if (!ts_is_valid_timezone_name(tz_name))
|
if (!ts_is_valid_timezone_name(tz_name))
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -817,52 +805,70 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
tbinfo->timezone = tz_name;
|
tbinfo->timezone = tz_name;
|
||||||
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Custom origin specified. This is always treated as
|
|
||||||
* a variable-sized bucket case.
|
|
||||||
*/
|
|
||||||
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
|
||||||
|
|
||||||
if (tz->constisnull)
|
if (list_length(fe->args) >= 4)
|
||||||
|
{
|
||||||
|
Const *arg = check_time_bucket_argument(lfourth(fe->args), "fourth");
|
||||||
|
if (exprType((Node *) arg) == TEXTOID)
|
||||||
|
{
|
||||||
|
const char *tz_name = TextDatumGetCString(arg->constvalue);
|
||||||
|
if (!ts_is_valid_timezone_name(tz_name))
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("invalid origin value: null")));
|
errmsg("invalid timezone name \"%s\"", tz_name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tz->consttype)
|
tbinfo->timezone = tz_name;
|
||||||
|
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for custom origin */
|
||||||
|
switch (exprType(col_arg))
|
||||||
{
|
{
|
||||||
case DATEOID:
|
case DATEOID:
|
||||||
|
/* origin is always 3rd arg for date variants */
|
||||||
|
if (list_length(fe->args) == 3)
|
||||||
|
{
|
||||||
|
custom_origin = true;
|
||||||
tbinfo->origin = DatumGetTimestamp(
|
tbinfo->origin = DatumGetTimestamp(
|
||||||
DirectFunctionCall1(date_timestamp, tz->constvalue));
|
DirectFunctionCall1(date_timestamp,
|
||||||
|
castNode(Const, lthird(fe->args))->constvalue));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TIMESTAMPOID:
|
case TIMESTAMPOID:
|
||||||
tbinfo->origin = DatumGetTimestamp(tz->constvalue);
|
/* origin is always 3rd arg for timestamp variants */
|
||||||
|
if (list_length(fe->args) == 3)
|
||||||
|
{
|
||||||
|
custom_origin = true;
|
||||||
|
tbinfo->origin =
|
||||||
|
DatumGetTimestamp(castNode(Const, lthird(fe->args))->constvalue);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TIMESTAMPTZOID:
|
case TIMESTAMPTZOID:
|
||||||
tbinfo->origin = DatumGetTimestampTz(tz->constvalue);
|
/* origin can be 3rd or 4th arg for timestamptz variants */
|
||||||
break;
|
if (list_length(fe->args) >= 3 && exprType(lthird(fe->args)) == TIMESTAMPTZOID)
|
||||||
default:
|
{
|
||||||
/*
|
custom_origin = true;
|
||||||
* This shouldn't happen. But if somehow it does
|
tbinfo->origin =
|
||||||
* make sure the execution will stop here even in
|
DatumGetTimestampTz(castNode(Const, lthird(fe->args))->constvalue);
|
||||||
* the Release build.
|
|
||||||
*/
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("unsupported time bucket function")));
|
|
||||||
}
|
}
|
||||||
|
else if (list_length(fe->args) >= 4 &&
|
||||||
if (TIMESTAMP_NOT_FINITE(tbinfo->origin))
|
exprType(lfourth(fe->args)) == TIMESTAMPTZOID)
|
||||||
|
{
|
||||||
|
custom_origin = true;
|
||||||
|
tbinfo->origin =
|
||||||
|
DatumGetTimestampTz(castNode(Const, lfourth(fe->args))->constvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (custom_origin && TIMESTAMP_NOT_FINITE(tbinfo->origin))
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("invalid origin value: infinity")));
|
errmsg("invalid origin value: infinity")));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We constify width expression here so any immutable expression will be allowed
|
* We constify width expression here so any immutable expression will be allowed
|
||||||
@ -895,35 +901,9 @@ caggtimebucket_validate(CAggTimebucketInfo *tbinfo, List *groupClause, List *tar
|
|||||||
errhint("Use an immutable expression as first argument"
|
errhint("Use an immutable expression as first argument"
|
||||||
" to the time bucket function.")));
|
" to the time bucket function.")));
|
||||||
|
|
||||||
if ((tbinfo->bucket_width == BUCKET_WIDTH_VARIABLE) && (tbinfo->interval->month != 0))
|
if (tbinfo->interval && tbinfo->interval->month)
|
||||||
{
|
{
|
||||||
/* Monthly buckets case */
|
tbinfo->bucket_width = BUCKET_WIDTH_VARIABLE;
|
||||||
if (!TIMESTAMP_NOT_FINITE(tbinfo->origin))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Origin was specified - make sure it's the first day of the month.
|
|
||||||
* If a timezone was specified the check should be done in this timezone.
|
|
||||||
*/
|
|
||||||
Timestamp origin = tbinfo->origin;
|
|
||||||
if (tbinfo->timezone != NULL)
|
|
||||||
{
|
|
||||||
/* The code is equal to 'timestamptz AT TIME ZONE tzname'. */
|
|
||||||
origin = DatumGetTimestamp(
|
|
||||||
DirectFunctionCall2(timestamptz_zone,
|
|
||||||
CStringGetTextDatum(tbinfo->timezone),
|
|
||||||
TimestampTzGetDatum((TimestampTz) origin)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *day =
|
|
||||||
TextDatumGetCString(DirectFunctionCall2(timestamp_to_char,
|
|
||||||
TimestampGetDatum(origin),
|
|
||||||
CStringGetTextDatum("DD")));
|
|
||||||
if (strcmp(day, "01") != 0)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("for monthly buckets origin must be the first day of the "
|
|
||||||
"month")));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2312,18 +2292,17 @@ cagg_create(const CreateTableAsStmt *create_stmt, ViewStmt *stmt, Query *panquer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `experimental` = true and `name` = "time_bucket_ng" are hardcoded
|
* These values are not used for
|
||||||
* rather than extracted from the query. We happen to know that
|
|
||||||
* monthly buckets can currently be created only with time_bucket_ng(),
|
|
||||||
* thus these values are correct. Besides, they are not used for
|
|
||||||
* anything except Assert's yet for the same reasons. Once the design
|
* anything except Assert's yet for the same reasons. Once the design
|
||||||
* of variable-sized buckets is finalized we will have a better idea
|
* of variable-sized buckets is finalized we will have a better idea
|
||||||
* of what schema is needed exactly. Until then the choice was made
|
* of what schema is needed exactly. Until then the choice was made
|
||||||
* in favor of the most generic schema that can be optimized later.
|
* in favor of the most generic schema that can be optimized later.
|
||||||
*/
|
*/
|
||||||
create_bucket_function_catalog_entry(materialize_hypertable_id,
|
create_bucket_function_catalog_entry(materialize_hypertable_id,
|
||||||
true,
|
get_func_namespace(
|
||||||
"time_bucket_ng",
|
origquery_ht->bucket_func->funcid) !=
|
||||||
|
PG_PUBLIC_NAMESPACE,
|
||||||
|
get_func_name(origquery_ht->bucket_func->funcid),
|
||||||
bucket_width,
|
bucket_width,
|
||||||
origin,
|
origin,
|
||||||
origquery_ht->timezone);
|
origquery_ht->timezone);
|
||||||
|
@ -410,3 +410,58 @@ SELECT relname FROM pg_class WHERE oid = :mat_table;
|
|||||||
-- Cleanup
|
-- Cleanup
|
||||||
DROP TABLE whatever;
|
DROP TABLE whatever;
|
||||||
-- END OF BASIC USAGE TESTS --
|
-- END OF BASIC USAGE TESTS --
|
||||||
|
CREATE TABLE metrics(time timestamptz, device TEXT, value float);
|
||||||
|
SELECT table_name FROM create_hypertable('metrics','time');
|
||||||
|
NOTICE: adding not-null constraint to column "time"
|
||||||
|
table_name
|
||||||
|
------------
|
||||||
|
metrics
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO metrics SELECT generate_series('1999-12-20'::timestamptz,'2000-02-01'::timestamptz,'12 day'::interval), 'dev1', 0.25;
|
||||||
|
SELECT current_setting('timezone');
|
||||||
|
current_setting
|
||||||
|
-----------------
|
||||||
|
PST8PDT
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- should be blocked because non-immutable expression
|
||||||
|
\set ON_ERROR_STOP 0
|
||||||
|
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 day', time, current_setting('timezone')) FROM metrics GROUP BY 1;
|
||||||
|
ERROR: only immutable expressions allowed in time bucket function
|
||||||
|
\set ON_ERROR_STOP 1
|
||||||
|
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 day', time, 'PST8PDT') FROM metrics GROUP BY 1;
|
||||||
|
NOTICE: refreshing continuous aggregate "cagg1"
|
||||||
|
SELECT * FROM cagg1;
|
||||||
|
time_bucket
|
||||||
|
------------------------------
|
||||||
|
Mon Dec 20 00:00:00 1999 PST
|
||||||
|
Sat Jan 01 00:00:00 2000 PST
|
||||||
|
Thu Jan 13 00:00:00 2000 PST
|
||||||
|
Tue Jan 25 00:00:00 2000 PST
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
CREATE MATERIALIZED VIEW cagg2 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT') FROM metrics GROUP BY 1;
|
||||||
|
NOTICE: refreshing continuous aggregate "cagg2"
|
||||||
|
SELECT * FROM cagg2;
|
||||||
|
time_bucket
|
||||||
|
------------------------------
|
||||||
|
Wed Dec 01 00:00:00 1999 PST
|
||||||
|
Sat Jan 01 00:00:00 2000 PST
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- custom origin
|
||||||
|
CREATE MATERIALIZED VIEW cagg3 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT', '2000-01-01'::timestamptz) FROM metrics GROUP BY 1;
|
||||||
|
NOTICE: refreshing continuous aggregate "cagg3"
|
||||||
|
SELECT * FROM cagg3;
|
||||||
|
time_bucket
|
||||||
|
------------------------------
|
||||||
|
Wed Dec 01 00:00:00 1999 PST
|
||||||
|
Sat Jan 01 00:00:00 2000 PST
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- offset not supported atm
|
||||||
|
\set ON_ERROR_STOP 0
|
||||||
|
CREATE MATERIALIZED VIEW cagg4 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT', "offset":= INTERVAL '15 day') FROM metrics GROUP BY 1;
|
||||||
|
ERROR: continuous aggregate view must include a valid time bucket function
|
||||||
|
\set ON_ERROR_STOP 1
|
||||||
|
@ -30,17 +30,6 @@ INSERT INTO conditions (day, city, temperature) VALUES
|
|||||||
('2021-06-26', 'Moscow', 32),
|
('2021-06-26', 'Moscow', 32),
|
||||||
('2021-06-27', 'Moscow', 31);
|
('2021-06-27', 'Moscow', 31);
|
||||||
\set ON_ERROR_STOP 0
|
\set ON_ERROR_STOP 0
|
||||||
-- Make sure NULL can't be specified as an origin
|
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
|
||||||
SELECT city,
|
|
||||||
timescaledb_experimental.time_bucket_ng('7 days', day, null) AS bucket,
|
|
||||||
MIN(temperature),
|
|
||||||
MAX(temperature)
|
|
||||||
FROM conditions
|
|
||||||
GROUP BY city, bucket
|
|
||||||
WITH NO DATA;
|
|
||||||
ERROR: invalid origin value: null
|
|
||||||
-- Make sure 'infinity' can't be specified as an origin
|
-- Make sure 'infinity' can't be specified as an origin
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
||||||
@ -52,17 +41,6 @@ FROM conditions
|
|||||||
GROUP BY city, bucket
|
GROUP BY city, bucket
|
||||||
WITH NO DATA;
|
WITH NO DATA;
|
||||||
ERROR: invalid origin value: infinity
|
ERROR: invalid origin value: infinity
|
||||||
-- For monthly buckets origin should be the first day of the month
|
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
|
||||||
SELECT city,
|
|
||||||
timescaledb_experimental.time_bucket_ng('1 month', day, '2021-06-03') AS bucket,
|
|
||||||
MIN(temperature),
|
|
||||||
MAX(temperature)
|
|
||||||
FROM conditions
|
|
||||||
GROUP BY city, bucket
|
|
||||||
WITH NO DATA;
|
|
||||||
ERROR: for monthly buckets origin must be the first day of the month
|
|
||||||
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
||||||
@ -95,24 +73,6 @@ SELECT mat_hypertable_id AS cagg_id, raw_hypertable_id AS ht_id
|
|||||||
FROM _timescaledb_catalog.continuous_agg
|
FROM _timescaledb_catalog.continuous_agg
|
||||||
WHERE user_view_name = 'conditions_summary_weekly'
|
WHERE user_view_name = 'conditions_summary_weekly'
|
||||||
\gset
|
\gset
|
||||||
-- Make sure this is treated as a variable-sized bucket case
|
|
||||||
SELECT bucket_width
|
|
||||||
FROM _timescaledb_catalog.continuous_agg
|
|
||||||
WHERE mat_hypertable_id = :cagg_id;
|
|
||||||
bucket_width
|
|
||||||
--------------
|
|
||||||
-1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
-- Make sure the origin is saved in the catalog table
|
|
||||||
SELECT experimental, name, bucket_width, origin, timezone
|
|
||||||
FROM _timescaledb_catalog.continuous_aggs_bucket_function
|
|
||||||
WHERE mat_hypertable_id = :cagg_id;
|
|
||||||
experimental | name | bucket_width | origin | timezone
|
|
||||||
--------------+----------------+--------------+--------------------------+----------
|
|
||||||
t | time_bucket_ng | @ 7 days | Mon Jan 03 00:00:00 2000 |
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
-- Make sure truncating of the refresh window works
|
-- Make sure truncating of the refresh window works
|
||||||
\set ON_ERROR_STOP 0
|
\set ON_ERROR_STOP 0
|
||||||
CALL refresh_continuous_aggregate('conditions_summary_weekly', '2021-06-14', '2021-06-20');
|
CALL refresh_continuous_aggregate('conditions_summary_weekly', '2021-06-14', '2021-06-20');
|
||||||
@ -955,7 +915,7 @@ SELECT city,
|
|||||||
MAX(temperature)
|
MAX(temperature)
|
||||||
FROM conditions_timestamptz
|
FROM conditions_timestamptz
|
||||||
GROUP BY city, bucket;
|
GROUP BY city, bucket;
|
||||||
ERROR: for monthly buckets origin must be the first day of the month
|
ERROR: origin must be the first day of the month
|
||||||
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_timestamptz
|
CREATE MATERIALIZED VIEW conditions_summary_timestamptz
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
||||||
@ -1139,7 +1099,7 @@ SELECT add_continuous_aggregate_policy('conditions_summary_timestamptz',
|
|||||||
DROP TABLE conditions_timestamptz CASCADE;
|
DROP TABLE conditions_timestamptz CASCADE;
|
||||||
NOTICE: drop cascades to 3 other objects
|
NOTICE: drop cascades to 3 other objects
|
||||||
NOTICE: drop cascades to 3 other objects
|
NOTICE: drop cascades to 3 other objects
|
||||||
NOTICE: drop cascades to table _timescaledb_internal._hyper_18_248_chunk
|
NOTICE: drop cascades to table _timescaledb_internal._hyper_19_248_chunk
|
||||||
\c :TEST_DBNAME :ROLE_CLUSTER_SUPERUSER
|
\c :TEST_DBNAME :ROLE_CLUSTER_SUPERUSER
|
||||||
DROP DATABASE :DATA_NODE_1;
|
DROP DATABASE :DATA_NODE_1;
|
||||||
DROP DATABASE :DATA_NODE_2;
|
DROP DATABASE :DATA_NODE_2;
|
||||||
|
@ -196,6 +196,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text
|
|||||||
time_bucket(interval,date,interval)
|
time_bucket(interval,date,interval)
|
||||||
time_bucket(interval,timestamp with time zone)
|
time_bucket(interval,timestamp with time zone)
|
||||||
time_bucket(interval,timestamp with time zone,interval)
|
time_bucket(interval,timestamp with time zone,interval)
|
||||||
|
time_bucket(interval,timestamp with time zone,text,timestamp with time zone,interval)
|
||||||
time_bucket(interval,timestamp with time zone,timestamp with time zone)
|
time_bucket(interval,timestamp with time zone,timestamp with time zone)
|
||||||
time_bucket(interval,timestamp without time zone)
|
time_bucket(interval,timestamp without time zone)
|
||||||
time_bucket(interval,timestamp without time zone,interval)
|
time_bucket(interval,timestamp without time zone,interval)
|
||||||
|
@ -268,3 +268,30 @@ SELECT relname FROM pg_class WHERE oid = :mat_table;
|
|||||||
DROP TABLE whatever;
|
DROP TABLE whatever;
|
||||||
|
|
||||||
-- END OF BASIC USAGE TESTS --
|
-- END OF BASIC USAGE TESTS --
|
||||||
|
|
||||||
|
CREATE TABLE metrics(time timestamptz, device TEXT, value float);
|
||||||
|
SELECT table_name FROM create_hypertable('metrics','time');
|
||||||
|
INSERT INTO metrics SELECT generate_series('1999-12-20'::timestamptz,'2000-02-01'::timestamptz,'12 day'::interval), 'dev1', 0.25;
|
||||||
|
|
||||||
|
SELECT current_setting('timezone');
|
||||||
|
|
||||||
|
-- should be blocked because non-immutable expression
|
||||||
|
\set ON_ERROR_STOP 0
|
||||||
|
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 day', time, current_setting('timezone')) FROM metrics GROUP BY 1;
|
||||||
|
\set ON_ERROR_STOP 1
|
||||||
|
|
||||||
|
CREATE MATERIALIZED VIEW cagg1 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 day', time, 'PST8PDT') FROM metrics GROUP BY 1;
|
||||||
|
SELECT * FROM cagg1;
|
||||||
|
|
||||||
|
CREATE MATERIALIZED VIEW cagg2 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT') FROM metrics GROUP BY 1;
|
||||||
|
SELECT * FROM cagg2;
|
||||||
|
|
||||||
|
-- custom origin
|
||||||
|
CREATE MATERIALIZED VIEW cagg3 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT', '2000-01-01'::timestamptz) FROM metrics GROUP BY 1;
|
||||||
|
SELECT * FROM cagg3;
|
||||||
|
|
||||||
|
-- offset not supported atm
|
||||||
|
\set ON_ERROR_STOP 0
|
||||||
|
CREATE MATERIALIZED VIEW cagg4 WITH (timescaledb.continuous,timescaledb.materialized_only=true) AS SELECT time_bucket('1 month', time, 'PST8PDT', "offset":= INTERVAL '15 day') FROM metrics GROUP BY 1;
|
||||||
|
\set ON_ERROR_STOP 1
|
||||||
|
|
||||||
|
@ -30,17 +30,6 @@ INSERT INTO conditions (day, city, temperature) VALUES
|
|||||||
|
|
||||||
\set ON_ERROR_STOP 0
|
\set ON_ERROR_STOP 0
|
||||||
|
|
||||||
-- Make sure NULL can't be specified as an origin
|
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
|
||||||
SELECT city,
|
|
||||||
timescaledb_experimental.time_bucket_ng('7 days', day, null) AS bucket,
|
|
||||||
MIN(temperature),
|
|
||||||
MAX(temperature)
|
|
||||||
FROM conditions
|
|
||||||
GROUP BY city, bucket
|
|
||||||
WITH NO DATA;
|
|
||||||
|
|
||||||
-- Make sure 'infinity' can't be specified as an origin
|
-- Make sure 'infinity' can't be specified as an origin
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
||||||
@ -52,17 +41,6 @@ FROM conditions
|
|||||||
GROUP BY city, bucket
|
GROUP BY city, bucket
|
||||||
WITH NO DATA;
|
WITH NO DATA;
|
||||||
|
|
||||||
-- For monthly buckets origin should be the first day of the month
|
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
|
||||||
SELECT city,
|
|
||||||
timescaledb_experimental.time_bucket_ng('1 month', day, '2021-06-03') AS bucket,
|
|
||||||
MIN(temperature),
|
|
||||||
MAX(temperature)
|
|
||||||
FROM conditions
|
|
||||||
GROUP BY city, bucket
|
|
||||||
WITH NO DATA;
|
|
||||||
|
|
||||||
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
-- Make sure buckets like '1 months 15 days" (fixed+variable-sized) are not allowed
|
||||||
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
CREATE MATERIALIZED VIEW conditions_summary_weekly
|
||||||
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
WITH (timescaledb.continuous, timescaledb.materialized_only=true) AS
|
||||||
@ -95,16 +73,6 @@ FROM _timescaledb_catalog.continuous_agg
|
|||||||
WHERE user_view_name = 'conditions_summary_weekly'
|
WHERE user_view_name = 'conditions_summary_weekly'
|
||||||
\gset
|
\gset
|
||||||
|
|
||||||
-- Make sure this is treated as a variable-sized bucket case
|
|
||||||
SELECT bucket_width
|
|
||||||
FROM _timescaledb_catalog.continuous_agg
|
|
||||||
WHERE mat_hypertable_id = :cagg_id;
|
|
||||||
|
|
||||||
-- Make sure the origin is saved in the catalog table
|
|
||||||
SELECT experimental, name, bucket_width, origin, timezone
|
|
||||||
FROM _timescaledb_catalog.continuous_aggs_bucket_function
|
|
||||||
WHERE mat_hypertable_id = :cagg_id;
|
|
||||||
|
|
||||||
-- Make sure truncating of the refresh window works
|
-- Make sure truncating of the refresh window works
|
||||||
\set ON_ERROR_STOP 0
|
\set ON_ERROR_STOP 0
|
||||||
CALL refresh_continuous_aggregate('conditions_summary_weekly', '2021-06-14', '2021-06-20');
|
CALL refresh_continuous_aggregate('conditions_summary_weekly', '2021-06-14', '2021-06-20');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user