Add parameter check_config to alter_job

Previously users had no way to update the check function
registered with add_job. This commit adds a parameter check_config
to alter_job to allow updating the check function field.

Also, previously the signature expected from a check was of
the form (job_id, config) and there was no validation
that the check function given had the correct signature.
This commit removes the job_id as it is not required and
also checks that the check function has the correct signature
when it is registered with add_job, preventing an error being
thrown at job runtime.
This commit is contained in:
Konstantina Skovola 2022-06-28 16:19:32 +03:00 committed by Konstantina Skovola
parent e0f3e17575
commit dc145b7485
28 changed files with 940 additions and 246 deletions

View File

@ -24,9 +24,10 @@ CREATE OR REPLACE FUNCTION @extschema@.alter_job(
scheduled BOOL = NULL,
config JSONB = NULL,
next_start TIMESTAMPTZ = NULL,
if_exists BOOL = FALSE
if_exists BOOL = FALSE,
check_config REGPROC = NULL
)
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, check_config TEXT)
AS '@MODULE_PATHNAME@', 'ts_job_alter'
LANGUAGE C VOLATILE;

View File

@ -6,7 +6,7 @@ CREATE OR REPLACE PROCEDURE _timescaledb_internal.policy_retention(job_id INTEGE
AS '@MODULE_PATHNAME@', 'ts_policy_retention_proc'
LANGUAGE C;
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_retention_check(job_id INTEGER, config JSONB)
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_retention_check(config JSONB)
RETURNS void AS '@MODULE_PATHNAME@', 'ts_policy_retention_check'
LANGUAGE C;
@ -14,7 +14,7 @@ CREATE OR REPLACE PROCEDURE _timescaledb_internal.policy_reorder(job_id INTEGER,
AS '@MODULE_PATHNAME@', 'ts_policy_reorder_proc'
LANGUAGE C;
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_reorder_check(job_id INTEGER, config JSONB)
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_reorder_check(config JSONB)
RETURNS void AS '@MODULE_PATHNAME@', 'ts_policy_reorder_check'
LANGUAGE C;
@ -22,7 +22,7 @@ CREATE OR REPLACE PROCEDURE _timescaledb_internal.policy_recompression(job_id IN
AS '@MODULE_PATHNAME@', 'ts_policy_recompression_proc'
LANGUAGE C;
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_compression_check(job_id INTEGER, config JSONB)
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_compression_check(config JSONB)
RETURNS void AS '@MODULE_PATHNAME@', 'ts_policy_compression_check'
LANGUAGE C;
@ -30,7 +30,7 @@ CREATE OR REPLACE PROCEDURE _timescaledb_internal.policy_refresh_continuous_aggr
AS '@MODULE_PATHNAME@', 'ts_policy_refresh_cagg_proc'
LANGUAGE C;
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_refresh_continuous_aggregate_check(job_id INTEGER, config JSONB)
CREATE OR REPLACE FUNCTION _timescaledb_internal.policy_refresh_continuous_aggregate_check(config JSONB)
RETURNS void AS '@MODULE_PATHNAME@', 'ts_policy_refresh_cagg_check'
LANGUAGE C;

View File

@ -22,11 +22,8 @@ ALTER TABLE _timescaledb_catalog.chunk
CREATE INDEX chunk_osm_chunk_idx ON _timescaledb_catalog.chunk (osm_chunk, hypertable_id);
DROP FUNCTION IF EXISTS @extschema@.add_job;
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_retention_check(INTEGER, JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_compression_check(INTEGER, JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_reorder_check(INTEGER, JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_refresh_continuous_aggregate_check(INTEGER, JSONB);
DROP FUNCTION IF EXISTS @extschema@.add_job(REGPROC, INTERVAL, JSONB, TIMESTAMPTZ, BOOL);
DROP FUNCTION IF EXISTS @extschema@.alter_job(INTEGER, INTERVAL, INTERVAL, INTEGER, INTERVAL, BOOL, JSONB, TIMESTAMPTZ, BOOL);
-- add fields for check function
ALTER TABLE _timescaledb_config.bgw_job
@ -71,3 +68,5 @@ SET
check_name = 'policy_refresh_continuous_aggregate_check'
WHERE proc_schema = '_timescaledb_internal'
AND proc_name = 'policy_refresh_continuous_aggregate';
DROP VIEW IF EXISTS timescaledb_information.jobs;

View File

@ -176,7 +176,7 @@ DROP TABLE _timescaledb_config.bgw_job;
CREATE SEQUENCE _timescaledb_config.bgw_job_id_seq MINVALUE 1000;
SELECT pg_catalog.pg_extension_config_dump('_timescaledb_config.bgw_job_id_seq', '');
SELECT setval('_timescaledb_config.bgw_job_id_seq', last_value, is_called)
SELECT pg_catalog.setval('_timescaledb_config.bgw_job_id_seq', last_value, is_called)
FROM _timescaledb_internal.tmp_bgw_job_seq_value;
DROP TABLE _timescaledb_internal.tmp_bgw_job_seq_value;
@ -218,8 +218,31 @@ ALTER TABLE _timescaledb_internal.bgw_policy_chunk_stats
FOREIGN KEY(job_id) REFERENCES _timescaledb_config.bgw_job(id)
ON DELETE CASCADE;
DROP FUNCTION IF EXISTS @extschema@.add_job;
DROP FUNCTION IF EXISTS @extschema@.add_job(REGPROC, INTERVAL, JSONB, TIMESTAMPTZ, BOOL, REGPROC);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_retention_check(JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_compression_check(JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_reorder_check(JSONB);
DROP FUNCTION IF EXISTS _timescaledb_internal.policy_refresh_continuous_aggregate_check(JSONB);
DROP FUNCTION IF EXISTS @extschema@.alter_job(INTEGER, INTERVAL, INTERVAL, INTEGER, INTERVAL, BOOL, JSONB, TIMESTAMPTZ, BOOL, REGPROC);
CREATE FUNCTION @extschema@.add_job(proc REGPROC,
schedule_interval INTERVAL,
config JSONB = NULL,
initial_start TIMESTAMPTZ = NULL,
scheduled BOOL = true)
RETURNS INTEGER AS '@MODULE_PATHNAME@', 'ts_job_add' LANGUAGE C VOLATILE;
CREATE FUNCTION @extschema@.alter_job(
job_id INTEGER,
schedule_interval INTERVAL = NULL,
max_runtime INTERVAL = NULL,
max_retries INTEGER = NULL,
retry_period INTERVAL = NULL,
scheduled BOOL = NULL,
config JSONB = NULL,
next_start TIMESTAMPTZ = NULL,
if_exists BOOL = FALSE
)
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'
LANGUAGE C VOLATILE;

View File

@ -98,7 +98,9 @@ SELECT j.id AS job_id,
j.config,
js.next_start,
ht.schema_name AS hypertable_schema,
ht.table_name AS hypertable_name
ht.table_name AS hypertable_name,
j.check_schema,
j.check_name
FROM _timescaledb_config.bgw_job j
LEFT JOIN _timescaledb_catalog.hypertable ht ON ht.id = j.hypertable_id
LEFT JOIN _timescaledb_internal.bgw_job_stat js ON js.job_id = j.id;

View File

@ -10,6 +10,7 @@
#include <catalog/pg_authid.h>
#include <nodes/makefuncs.h>
#include <parser/parse_func.h>
#include <parser/parser.h>
#include <postmaster/bgworker.h>
#include <storage/ipc.h>
#include <tcop/tcopprot.h>
@ -109,16 +110,21 @@ job_execute_procedure(FuncExpr *funcexpr)
void
ts_bgw_job_run_config_check(Oid check, int32 job_id, Jsonb *config)
{
List *args =
list_make2(makeConst(INT4OID, -1, InvalidOid, 4, Int32GetDatum(job_id), false, true),
makeConst(JSONBOID, -1, InvalidOid, -1, JsonbPGetDatum(config), false, false));
FuncExpr *funcexpr =
makeFuncExpr(check, VOIDOID, args, InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
/* Nothing to check if there is no check function provided */
if (!OidIsValid(check))
return;
/* NULL config may be valid */
Const *arg;
if (config == NULL)
arg = makeNullConst(JSONBOID, -1, InvalidOid);
else
arg = makeConst(JSONBOID, -1, InvalidOid, -1, JsonbPGetDatum(config), false, false);
List *args = list_make1(arg);
FuncExpr *funcexpr =
makeFuncExpr(check, VOIDOID, args, InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
switch (get_func_prokind(check))
{
case PROKIND_FUNCTION:
@ -140,10 +146,8 @@ ts_bgw_job_run_config_check(Oid check, int32 job_id, Jsonb *config)
static void
job_config_check(BgwJob *job, Jsonb *config)
{
const Oid proc_args[] = { INT4OID, JSONBOID };
List *name;
Oid proc;
bool started = false;
ObjectWithArgs *object;
/* Both should either be empty or contain a schema and name */
Assert((strlen(NameStr(job->fd.check_schema)) == 0) ==
@ -153,27 +157,25 @@ job_config_check(BgwJob *job, Jsonb *config)
if (strlen(NameStr(job->fd.check_name)) == 0)
return;
if (!IsTransactionOrTransactionBlock())
{
started = true;
StartTransactionCommand();
/* executing sql functions requires snapshot */
PushActiveSnapshot(GetTransactionSnapshot());
}
object = makeNode(ObjectWithArgs);
/* We are using LookupFuncName here, which will find functions but not
* procedures. We could use LookupFuncWithArgs here instead. */
name = list_make2(makeString(NameStr(job->fd.check_schema)),
makeString(NameStr(job->fd.check_name)));
proc = LookupFuncName(name, 2, proc_args, false);
ts_bgw_job_run_config_check(proc, job->fd.id, config);
if (started)
{
/* if job does its own transaction handling it might not have set a snapshot */
if (ActiveSnapshotSet())
PopActiveSnapshot();
CommitTransactionCommand();
}
object->objname = list_make2(makeString(NameStr(job->fd.check_schema)),
makeString(NameStr(job->fd.check_name)));
object->objargs = list_make1(SystemTypeName("jsonb"));
proc = LookupFuncWithArgs(OBJECT_ROUTINE, object, true);
/* a check function has been registered but it can't be found anymore
because it was dropped or renamed. Allow alter_job to run if that's the case
without validating the config but also print a warning */
if (OidIsValid(proc))
ts_bgw_job_run_config_check(proc, job->fd.id, config);
else
elog(WARNING,
"function or procedure %s.%s(config jsonb) not found, skipping config validation for "
"job %d",
NameStr(job->fd.check_schema),
NameStr(job->fd.check_name),
job->fd.id);
}
static BgwJob *
@ -782,9 +784,24 @@ bgw_job_tuple_update_by_id(TupleInfo *ti, void *const data)
repl[AttrNumberGetAttrOffset(Anum_bgw_job_scheduled)] = true;
repl[AttrNumberGetAttrOffset(Anum_bgw_job_config)] = true;
values[AttrNumberGetAttrOffset(Anum_bgw_job_check_schema)] =
NameGetDatum(&updated_job->fd.check_schema);
repl[AttrNumberGetAttrOffset(Anum_bgw_job_check_schema)] = true;
values[AttrNumberGetAttrOffset(Anum_bgw_job_check_name)] =
NameGetDatum(&updated_job->fd.check_name);
repl[AttrNumberGetAttrOffset(Anum_bgw_job_check_name)] = true;
if (strlen(NameStr(updated_job->fd.check_name)) == 0)
{
isnull[AttrNumberGetAttrOffset(Anum_bgw_job_check_name)] = true;
isnull[AttrNumberGetAttrOffset(Anum_bgw_job_check_schema)] = true;
}
if (updated_job->fd.config)
{
job_config_check(bgw_job_from_tupleinfo(ti, sizeof(BgwJob)), updated_job->fd.config);
job_config_check(updated_job, updated_job->fd.config);
values[AttrNumberGetAttrOffset(Anum_bgw_job_config)] =
JsonbPGetDatum(updated_job->fd.config);
}

View File

@ -6,10 +6,8 @@
#include <postgres.h>
#include <utils/builtins.h>
#include <jsonb_utils.h>
#include "bgw/job.h"
#include "dimension.h"
#include "policy.h"
void

View File

@ -158,11 +158,8 @@ validate_compress_after_type(Oid partitioning_type, Oid compress_after_type)
Datum
policy_compression_check(PG_FUNCTION_ARGS)
{
if (PG_NARGS() != 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_VOID();
PolicyCompressionData policy_data;
policy_compression_read_and_validate_config(PG_GETARG_JSONB_P(1), &policy_data);
policy_compression_read_and_validate_config(PG_GETARG_JSONB_P(0), &policy_data);
ts_cache_release(policy_data.hcache);
PG_RETURN_VOID();

View File

@ -220,10 +220,7 @@ policy_refresh_cagg_proc(PG_FUNCTION_ARGS)
Datum
policy_refresh_cagg_check(PG_FUNCTION_ARGS)
{
if (PG_NARGS() != 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_VOID();
policy_refresh_cagg_read_and_validate_config(PG_GETARG_JSONB_P(1), NULL);
policy_refresh_cagg_read_and_validate_config(PG_GETARG_JSONB_P(0), NULL);
PG_RETURN_VOID();
}

View File

@ -10,6 +10,9 @@
#include <utils/acl.h>
#include <utils/builtins.h>
#include <parser/parse_func.h>
#include <parser/parser.h>
#include <bgw/job.h>
#include <bgw/job_stat.h>
@ -25,7 +28,37 @@
/* Default retry period for reorder_jobs is currently 5 minutes */
#define DEFAULT_RETRY_PERIOD (5 * USECS_PER_MINUTE)
#define ALTER_JOB_NUM_COLS 8
#define ALTER_JOB_NUM_COLS 9
/*
* This function ensures that the check function has the required signature
* @param check A valid Oid
*/
static inline void
validate_check_signature(Oid check)
{
Oid proc = InvalidOid;
ObjectWithArgs *object;
NameData check_name = { 0 };
NameData check_schema = { 0 };
namestrcpy(&check_schema, get_namespace_name(get_func_namespace(check)));
namestrcpy(&check_name, get_func_name(check));
object = makeNode(ObjectWithArgs);
object->objname =
list_make2(makeString(NameStr(check_schema)), makeString(NameStr(check_name)));
object->objargs = list_make1(SystemTypeName("jsonb"));
proc = LookupFuncWithArgs(OBJECT_ROUTINE, object, true);
if (!OidIsValid(proc))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("function or procedure %s.%s(config jsonb) not found",
NameStr(check_schema),
NameStr(check_name)),
errhint("The check function's signature must be (config jsonb).")));
}
/*
* CREATE FUNCTION add_job(
@ -110,8 +143,11 @@ job_add(PG_FUNCTION_ARGS)
namestrcpy(&proc_name, func_name);
namestrcpy(&owner_name, GetUserNameFromId(owner, false));
if (config)
ts_bgw_job_run_config_check(check, 0, config);
/* The check exists but may not have the expected signature: (config jsonb) */
if (OidIsValid(check))
validate_check_signature(check);
ts_bgw_job_run_config_check(check, 0, config);
job_id = ts_bgw_job_insert_relation(&application_name,
schedule_interval,
@ -206,6 +242,7 @@ job_run(PG_FUNCTION_ARGS)
* 6 config JSONB = NULL,
* 7 next_start TIMESTAMPTZ = NULL
* 8 if_exists BOOL = FALSE,
* 9 check_config REGPROC = NULL
* ) RETURNS TABLE (
* job_id INTEGER,
* schedule_interval INTERVAL,
@ -215,6 +252,7 @@ job_run(PG_FUNCTION_ARGS)
* scheduled BOOL,
* config JSONB,
* next_start TIMESTAMPTZ
* check_config TEXT
* )
*/
Datum
@ -229,6 +267,13 @@ job_alter(PG_FUNCTION_ARGS)
int job_id = PG_GETARG_INT32(0);
bool if_exists = PG_GETARG_BOOL(8);
BgwJob *job;
NameData check_name = { 0 };
NameData check_schema = { 0 };
Oid check = PG_ARGISNULL(9) ? InvalidOid : PG_GETARG_OID(9);
char *check_name_str = NULL;
/* Added space for period and NULL */
char schema_qualified_check_name[2 * NAMEDATALEN + 2] = { 0 };
bool unregister_check = (!PG_ARGISNULL(9) && !OidIsValid(check));
TS_PREVENT_FUNC_IF_READ_ONLY();
@ -259,6 +304,50 @@ job_alter(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(6))
job->fd.config = PG_GETARG_JSONB_P(6);
if (!PG_ARGISNULL(9))
{
if (OidIsValid(check))
{
check_name_str = get_func_name(check);
if (check_name_str == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function with OID %d does not exist", check)));
if (pg_proc_aclcheck(check, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied for function \"%s\"", check_name_str),
errhint("Job owner must have EXECUTE privilege on the function.")));
namestrcpy(&check_schema, get_namespace_name(get_func_namespace(check)));
namestrcpy(&check_name, check_name_str);
/* The check exists but may not have the expected signature: (config jsonb) */
validate_check_signature(check);
namestrcpy(&job->fd.check_schema, NameStr(check_schema));
namestrcpy(&job->fd.check_name, NameStr(check_name));
snprintf(schema_qualified_check_name,
sizeof(schema_qualified_check_name) / sizeof(schema_qualified_check_name[0]),
"%s.%s",
NameStr(check_schema),
check_name_str);
}
}
else
snprintf(schema_qualified_check_name,
sizeof(schema_qualified_check_name) / sizeof(schema_qualified_check_name[0]),
"%s.%s",
NameStr(job->fd.check_schema),
NameStr(job->fd.check_name));
if (unregister_check)
{
NameData empty_namedata = { 0 };
namestrcpy(&job->fd.check_schema, NameStr(empty_namedata));
namestrcpy(&job->fd.check_name, NameStr(empty_namedata));
}
ts_bgw_job_update_by_id(job_id, job);
if (!PG_ARGISNULL(7))
@ -285,6 +374,13 @@ job_alter(PG_FUNCTION_ARGS)
values[7] = TimestampTzGetDatum(next_start);
if (unregister_check)
nulls[8] = true;
else if (strlen(NameStr(job->fd.check_schema)) > 0)
values[8] = CStringGetTextDatum(schema_qualified_check_name);
else
nulls[8] = true;
tuple = heap_form_tuple(tupdesc, values, nulls);
return HeapTupleGetDatum(tuple);
}

View File

@ -109,12 +109,9 @@ check_valid_index(Hypertable *ht, Name index_name)
Datum
policy_reorder_check(PG_FUNCTION_ARGS)
{
if (PG_NARGS() != 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_VOID();
TS_PREVENT_FUNC_IF_READ_ONLY();
policy_reorder_read_and_validate_config(PG_GETARG_JSONB_P(1), NULL);
policy_reorder_read_and_validate_config(PG_GETARG_JSONB_P(0), NULL);
PG_RETURN_VOID();
}

View File

@ -43,12 +43,9 @@ policy_retention_proc(PG_FUNCTION_ARGS)
Datum
policy_retention_check(PG_FUNCTION_ARGS)
{
if (PG_NARGS() != 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_VOID();
TS_PREVENT_FUNC_IF_READ_ONLY();
policy_retention_read_and_validate_config(PG_GETARG_JSONB_P(1), NULL);
policy_retention_read_and_validate_config(PG_GETARG_JSONB_P(0), NULL);
PG_RETURN_VOID();
}

View File

@ -74,13 +74,13 @@ SELECT add_job('custom_func_definer', '1h', config:='{"type":"function"}'::jsonb
(1 row)
SELECT * FROM timescaledb_information.jobs WHERE job_id != 1 ORDER BY 1;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+----------------------------+-------------------+-------------+-------------+--------------+-------------+---------------------+-------------------+-----------+-----------------------+------------+-------------------+-----------------
1000 | User-Defined Action [1000] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | |
1001 | User-Defined Action [1001] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_proc | default_perm_user | t | {"type": "procedure"} | | |
1002 | User-Defined Action [1002] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_proc2 | default_perm_user | t | {"type": "procedure"} | | |
1003 | User-Defined Action [1003] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | |
1004 | User-Defined Action [1004] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func_definer | default_perm_user | t | {"type": "function"} | | |
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+----------------------------+-------------------+-------------+-------------+--------------+-------------+---------------------+-------------------+-----------+-----------------------+------------+-------------------+-----------------+--------------+------------
1000 | User-Defined Action [1000] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | | | |
1001 | User-Defined Action [1001] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_proc | default_perm_user | t | {"type": "procedure"} | | | | |
1002 | User-Defined Action [1002] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_proc2 | default_perm_user | t | {"type": "procedure"} | | | | |
1003 | User-Defined Action [1003] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | | | |
1004 | User-Defined Action [1004] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func_definer | default_perm_user | t | {"type": "function"} | | | | |
(5 rows)
SELECT count(*) FROM _timescaledb_config.bgw_job WHERE config->>'type' IN ('procedure', 'function');
@ -574,3 +574,328 @@ SELECT _timescaledb_internal.stop_background_workers();
t
(1 row)
SELECT _timescaledb_internal.restart_background_workers();
restart_background_workers
----------------------------
t
(1 row)
\set ON_ERROR_STOP 0
-- add test for custom jobs with custom check functions
-- create the functions/procedures to be used as checking functions
CREATE OR REPLACE PROCEDURE test_config_check_proc(config jsonb)
LANGUAGE PLPGSQL
AS $$
DECLARE
drop_after interval;
BEGIN
SELECT jsonb_object_field_text (config, 'drop_after')::interval INTO STRICT drop_after;
IF drop_after IS NULL THEN
RAISE EXCEPTION 'Config must be not NULL and have drop_after';
END IF ;
END
$$;
CREATE OR REPLACE FUNCTION test_config_check_func(config jsonb) RETURNS VOID
AS $$
DECLARE
drop_after interval;
BEGIN
IF config IS NULL THEN
RETURN;
END IF;
SELECT jsonb_object_field_text (config, 'drop_after')::interval INTO STRICT drop_after;
IF drop_after IS NULL THEN
RAISE EXCEPTION 'Config can be NULL but must have drop_after if not';
END IF ;
END
$$ LANGUAGE PLPGSQL;
-- step 2, create a procedure to run as a custom job
CREATE OR REPLACE PROCEDURE test_proc_with_check(job_id int, config jsonb)
LANGUAGE PLPGSQL
AS $$
BEGIN
RAISE NOTICE 'Will only print this if config passes checks, my config is %', config;
END
$$;
-- step 3, add the job with the config check function passed as argument
-- test procedures
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_proc'::regproc);
ERROR: Config must be not NULL and have drop_after
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_proc'::regproc);
ERROR: Config must be not NULL and have drop_after
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "chicken"}', check_config => 'test_config_check_proc'::regproc);
ERROR: invalid input syntax for type interval: "chicken"
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "2 weeks"}', check_config => 'test_config_check_proc'::regproc)
as job_with_proc_check_id \gset
-- test functions
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func'::regproc);
ERROR: Config can be NULL but must have drop_after if not
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_func'::regproc);
add_job
---------
1006
(1 row)
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "chicken"}', check_config => 'test_config_check_func'::regproc);
ERROR: invalid input syntax for type interval: "chicken"
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "2 weeks"}', check_config => 'test_config_check_func'::regproc)
as job_with_func_check_id \gset
--- test alter_job
select alter_job(:job_with_func_check_id, config => '{"drop_after":"chicken"}');
ERROR: invalid input syntax for type interval: "chicken"
select alter_job(:job_with_func_check_id, config => '{"drop_after":"5 years"}');
alter_job
-----------------------------------------------------------------------------------------------------------------
(1007,"@ 5 secs","@ 0",-1,"@ 5 mins",t,"{""drop_after"": ""5 years""}",-infinity,public.test_config_check_func)
(1 row)
select alter_job(:job_with_proc_check_id, config => '{"drop_after":"4 days"}');
alter_job
----------------------------------------------------------------------------------------------------------------
(1005,"@ 5 secs","@ 0",-1,"@ 5 mins",t,"{""drop_after"": ""4 days""}",-infinity,public.test_config_check_proc)
(1 row)
-- test that jobs with an incorrect check function signature will not be registered
-- these are all incorrect function signatures
CREATE OR REPLACE FUNCTION test_config_check_func_0args() RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take no arguments and will validate anything you give me!';
END
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION test_config_check_func_2args(config jsonb, intarg int) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take two arguments (jsonb, int) and I should fail to run!';
END
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION test_config_check_func_intarg(config int) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take one argument which is an integer and I should fail to run!';
END
$$ LANGUAGE PLPGSQL;
-- -- this should fail, it has an incorrect check function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_0args'::regproc);
ERROR: function or procedure public.test_config_check_func_0args(config jsonb) not found
-- -- so should this
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_2args'::regproc);
ERROR: function or procedure public.test_config_check_func_2args(config jsonb) not found
-- and this
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_intarg'::regproc);
ERROR: function or procedure public.test_config_check_func_intarg(config jsonb) not found
-- and this fails as it calls a nonexistent function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_nonexistent_check_func'::regproc);
ERROR: function "test_nonexistent_check_func" does not exist at character 82
-- when called with a valid check function and a NULL config no check should occur
CREATE OR REPLACE FUNCTION test_config_check_func(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message will get printed for both NULL and not NULL config';
END
$$ LANGUAGE PLPGSQL;
SET client_min_messages = NOTICE;
-- check done for both NULL and non-NULL config
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_func'::regproc);
NOTICE: This message will get printed for both NULL and not NULL config
add_job
---------
1008
(1 row)
-- check done
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func'::regproc) as job_id \gset
NOTICE: This message will get printed for both NULL and not NULL config
-- check function not returning void
CREATE OR REPLACE FUNCTION test_config_check_func_returns_int(config jsonb) RETURNS INT
AS $$
BEGIN
raise notice 'I print a message, and then I return least(1,2)';
RETURN LEAST(1, 2);
END
$$ LANGUAGE PLPGSQL;
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_returns_int'::regproc) as job_id_int \gset
NOTICE: I print a message, and then I return least(1,2)
-- drop the registered check function, verify that alter_job will work and print a warning that
-- the check is being skipped due to the check function missing
ALTER FUNCTION test_config_check_func RENAME TO renamed_func;
select alter_job(:job_id, schedule_interval => '1 hour');
WARNING: function or procedure public.test_config_check_func(config jsonb) not found, skipping config validation for job 1009
alter_job
------------------------------------------------------------------------------------
(1009,"@ 1 hour","@ 0",-1,"@ 5 mins",t,{},-infinity,public.test_config_check_func)
(1 row)
DROP FUNCTION test_config_check_func_returns_int;
select alter_job(:job_id_int, config => '{"field":"value"}');
WARNING: function or procedure public.test_config_check_func_returns_int(config jsonb) not found, skipping config validation for job 1010
alter_job
----------------------------------------------------------------------------------------------------------------------
(1010,"@ 5 secs","@ 0",-1,"@ 5 mins",t,"{""field"": ""value""}",-infinity,public.test_config_check_func_returns_int)
(1 row)
-- rename the check function and then call alter_job to register the new name
select alter_job(:job_id, check_config => 'renamed_func'::regproc);
NOTICE: This message will get printed for both NULL and not NULL config
alter_job
--------------------------------------------------------------------------
(1009,"@ 1 hour","@ 0",-1,"@ 5 mins",t,{},-infinity,public.renamed_func)
(1 row)
-- run alter again, should get a config check
select alter_job(:job_id, config => '{}');
NOTICE: This message will get printed for both NULL and not NULL config
alter_job
--------------------------------------------------------------------------
(1009,"@ 1 hour","@ 0",-1,"@ 5 mins",t,{},-infinity,public.renamed_func)
(1 row)
-- do not drop the current check function but register a new one
CREATE OR REPLACE FUNCTION substitute_check_func(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message is a substitute of the previously printed one';
END
$$ LANGUAGE PLPGSQL;
-- register the new check
select alter_job(:job_id, check_config => 'substitute_check_func');
NOTICE: This message is a substitute of the previously printed one
alter_job
-----------------------------------------------------------------------------------
(1009,"@ 1 hour","@ 0",-1,"@ 5 mins",t,{},-infinity,public.substitute_check_func)
(1 row)
select alter_job(:job_id, config => '{}');
NOTICE: This message is a substitute of the previously printed one
alter_job
-----------------------------------------------------------------------------------
(1009,"@ 1 hour","@ 0",-1,"@ 5 mins",t,{},-infinity,public.substitute_check_func)
(1 row)
RESET client_min_messages;
-- test an oid that doesn't exist
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 17424217::regproc);
ERROR: function with OID 17424217 does not exist
\c :TEST_DBNAME :ROLE_SUPERUSER
-- test a function with insufficient privileges
create schema test_schema;
create role user_noexec with login;
grant usage on schema test_schema to user_noexec;
CREATE OR REPLACE FUNCTION test_schema.test_config_check_func_privileges(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message will only get printed if privileges suffice';
END
$$ LANGUAGE PLPGSQL;
revoke execute on function test_schema.test_config_check_func_privileges from public;
-- verify the user doesn't have execute permissions on the function
select has_function_privilege('user_noexec', 'test_schema.test_config_check_func_privileges(jsonb)', 'execute');
has_function_privilege
------------------------
f
(1 row)
\c :TEST_DBNAME user_noexec
-- user_noexec should not have exec permissions on this function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_schema.test_config_check_func_privileges'::regproc);
ERROR: permission denied for function "test_config_check_func_privileges"
\c :TEST_DBNAME :ROLE_SUPERUSER
-- check that alter_job rejects a check function with invalid signature
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'renamed_func') as job_id_alter \gset
NOTICE: This message will get printed for both NULL and not NULL config
select alter_job(:job_id_alter, check_config => 'test_config_check_func_0args');
ERROR: function or procedure public.test_config_check_func_0args(config jsonb) not found
select alter_job(:job_id_alter);
NOTICE: This message will get printed for both NULL and not NULL config
alter_job
--------------------------------------------------------------------------
(1011,"@ 5 secs","@ 0",-1,"@ 5 mins",t,{},-infinity,public.renamed_func)
(1 row)
-- test that we can unregister the check function
select alter_job(:job_id_alter, check_config => 0);
alter_job
-------------------------------------------------------
(1011,"@ 5 secs","@ 0",-1,"@ 5 mins",t,{},-infinity,)
(1 row)
-- no message printed now
select alter_job(:job_id_alter, config => '{}');
alter_job
-------------------------------------------------------
(1011,"@ 5 secs","@ 0",-1,"@ 5 mins",t,{},-infinity,)
(1 row)
-- test what happens if the check function contains a COMMIT
-- procedure with transaction handling
CREATE OR REPLACE PROCEDURE custom_proc2_jsonb(config jsonb) LANGUAGE PLPGSQL AS
$$
BEGIN
-- RAISE NOTICE 'Starting some transactions inside procedure';
INSERT INTO custom_log VALUES(1, $1, 'custom_proc 1 COMMIT');
COMMIT;
END
$$;
select add_job('test_proc_with_check', '5 secs', config => '{}') as job_id_err \gset
select alter_job(:job_id_err, check_config => 'custom_proc2_jsonb');
ERROR: portal snapshots (0) did not account for all active snapshots (1)
select alter_job(:job_id_err, schedule_interval => '3 minutes');
alter_job
-------------------------------------------------------
(1012,"@ 3 mins","@ 0",-1,"@ 5 mins",t,{},-infinity,)
(1 row)
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'custom_proc2_jsonb') as job_id_commit \gset
ERROR: portal snapshots (0) did not account for all active snapshots (1)
-- test the case where we have a background job that registers jobs with a check fn
CREATE OR REPLACE PROCEDURE add_scheduled_jobs_with_check(job_id int, config jsonb) LANGUAGE PLPGSQL AS
$$
BEGIN
perform add_job('test_proc_with_check', schedule_interval => '10 secs', config => '{}', check_config => 'renamed_func');
END
$$;
select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
-- wait for enough time
SELECT wait_for_job_to_run(:last_job_id, 1);
wait_for_job_to_run
---------------------
t
(1 row)
select total_runs, total_successes, last_run_status from timescaledb_information.job_stats where job_id = :last_job_id;
total_runs | total_successes | last_run_status
------------+-----------------+-----------------
1 | 1 | Success
(1 row)
-- test coverage for alter_job
-- registering an invalid oid
select alter_job(:job_id_alter, check_config => 123456789::regproc);
ERROR: function with OID 123456789 does not exist
-- registering a function with insufficient privileges
\c :TEST_DBNAME user_noexec
select * from add_job('test_proc_with_check', '5 secs', config => '{}') as job_id_owner \gset
select * from alter_job(:job_id_owner, check_config => 'test_schema.test_config_check_func_privileges'::regproc);
ERROR: permission denied for function "test_config_check_func_privileges"
\c :TEST_DBNAME :ROLE_SUPERUSER
DROP SCHEMA test_schema CASCADE;
NOTICE: drop cascades to function test_schema.test_config_check_func_privileges(jsonb)
DROP ROLE user_noexec;
-- test with aggregate check proc
create function jsonb_add (j1 jsonb, j2 jsonb) returns jsonb
AS $$
BEGIN
RETURN j1 || j2;
END
$$ LANGUAGE PLPGSQL;
create table jsonb_values (j jsonb, i int);
insert into jsonb_values values ('{"refresh_after":"2 weeks"}', 1), ('{"compress_after":"2 weeks"}', 2), ('{"drop_after":"2 weeks"}', 3);
CREATE AGGREGATE sum_jsb (jsonb)
(
sfunc = jsonb_add,
stype = jsonb,
initcond = '{}'
);
-- for test coverage, check unsupported aggregate type
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'sum_jsb'::regproc);
ERROR: unsupported function type

View File

@ -1420,9 +1420,9 @@ SELECT wait_for_timer_to_run(0);
SELECT insert_job('another', 'bgw_test_job_1', INTERVAL '100ms', INTERVAL '100s', INTERVAL '1s') AS job_id \gset
-- call alter_job to trigger cache invalidation
SELECT alter_job(:job_id,scheduled:=true);
alter_job
----------------------------------------------------------------
(1026,"@ 0.1 secs","@ 1 min 40 secs",5,"@ 1 sec",t,,-infinity)
alter_job
-----------------------------------------------------------------
(1026,"@ 0.1 secs","@ 1 min 40 secs",5,"@ 1 sec",t,,-infinity,)
(1 row)
SELECT ts_bgw_params_reset_time(50000, true);
@ -1522,9 +1522,9 @@ SELECT wait_for_timer_to_run(400000);
SELECT insert_job('new_job', 'bgw_test_job_1', INTERVAL '10ms', INTERVAL '100s', INTERVAL '1s') AS job_id \gset
-- call alter_job to trigger cache invalidation
SELECT alter_job(:job_id,scheduled:=true);
alter_job
-----------------------------------------------------------------
(1027,"@ 0.01 secs","@ 1 min 40 secs",5,"@ 1 sec",t,,-infinity)
alter_job
------------------------------------------------------------------
(1027,"@ 0.01 secs","@ 1 min 40 secs",5,"@ 1 sec",t,,-infinity,)
(1 row)
SELECT ts_bgw_params_reset_time(450000, true);

View File

@ -102,9 +102,9 @@ SELECT count(*) FROM _timescaledb_config.bgw_job WHERE proc_schema = '_timescale
-- job was created
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+------------+-------------------+--------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | | public | test_reorder_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+------------+-------------------+--------------------+-----------------------+----------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | | public | test_reorder_table | _timescaledb_internal | policy_reorder_check
(1 row)
-- no stats
@ -138,9 +138,9 @@ SELECT * FROM sorted_bgw_log;
(2 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+------------------------------+-------------------+--------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Fri Dec 31 16:00:00 1999 PST | public | test_reorder_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+------------------------------+-------------------+--------------------+-----------------------+----------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Fri Dec 31 16:00:00 1999 PST | public | test_reorder_table | _timescaledb_internal | policy_reorder_check
(1 row)
-- job ran once, successfully
@ -178,9 +178,9 @@ SELECT * FROM sorted_bgw_log;
(4 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+----------------------------------+-------------------+--------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Fri Dec 31 16:00:00.025 1999 PST | public | test_reorder_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+----------------------------------+-------------------+--------------------+-----------------------+----------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Fri Dec 31 16:00:00.025 1999 PST | public | test_reorder_table | _timescaledb_internal | policy_reorder_check
(1 row)
-- two runs
@ -222,9 +222,9 @@ SELECT * FROM sorted_bgw_log;
(6 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+---------------------------------+-------------------+--------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Tue Jan 04 16:00:00.05 2000 PST | public | test_reorder_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+---------------------------------+-------------------+--------------------+-----------------------+----------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Tue Jan 04 16:00:00.05 2000 PST | public | test_reorder_table | _timescaledb_internal | policy_reorder_check
(1 row)
SELECT *
@ -266,9 +266,9 @@ SELECT * FROM sorted_bgw_log;
(7 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+---------------------------------+-------------------+--------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Tue Jan 04 16:00:00.05 2000 PST | public | test_reorder_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-----------------------+-------------------+-------------+-------------+--------------+-----------------------+----------------+-------------------+-----------+-------------------------------------------------------------------+---------------------------------+-------------------+--------------------+-----------------------+----------------------
1000 | Reorder Policy [1000] | @ 4 days | @ 0 | -1 | @ 5 mins | _timescaledb_internal | policy_reorder | default_perm_user | t | {"index_name": "test_reorder_table_time_idx", "hypertable_id": 1} | Tue Jan 04 16:00:00.05 2000 PST | public | test_reorder_table | _timescaledb_internal | policy_reorder_check
(1 row)
SELECT *
@ -305,8 +305,8 @@ SELECT remove_reorder_policy('test_reorder_table');
(1 row)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+------------------+-------------------+-------------+-------------+--------------+-------------+-----------+-------+-----------+--------+------------+-------------------+-----------------
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+------------------+-------------------+-------------+-------------+--------------+-------------+-----------+-------+-----------+--------+------------+-------------------+-----------------+--------------+------------
(0 rows)
SELECT job_id, next_start, last_finish as until_next, last_run_success, total_runs, total_successes, total_failures, total_crashes
@ -336,8 +336,8 @@ SELECT * FROM sorted_bgw_log;
(8 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:reorder_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+------------------+-------------------+-------------+-------------+--------------+-------------+-----------+-------+-----------+--------+------------+-------------------+-----------------
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+------------------+-------------------+-------------+-------------+--------------+-------------+-----------+-------+-----------+--------+------------+-------------------+-----------------+--------------+------------
(0 rows)
-- still only 3 chunks clustered
@ -409,15 +409,15 @@ SELECT count(*) FROM _timescaledb_config.bgw_job WHERE proc_schema = '_timescale
(1 row)
SELECT alter_job(:drop_chunks_job_id, schedule_interval => INTERVAL '1 second');
alter_job
--------------------------------------------------------------------------------------------------------------
(1001,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""hypertable_id"": 2}",-infinity)
alter_job
-----------------------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""hypertable_id"": 2}",-infinity,_timescaledb_internal.policy_retention_check)
(1 row)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:drop_chunks_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------+-------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | | public | test_drop_chunks_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------+-------------------+------------------------+-----------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | | public | test_drop_chunks_table | _timescaledb_internal | policy_retention_check
(1 row)
-- no stats
@ -454,9 +454,9 @@ SELECT * FROM sorted_bgw_log;
(2 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:drop_chunks_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:01 1999 PST | public | test_drop_chunks_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------+-----------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:01 1999 PST | public | test_drop_chunks_table | _timescaledb_internal | policy_retention_check
(1 row)
-- job ran once, successfully
@ -493,9 +493,9 @@ SELECT * FROM sorted_bgw_log;
(3 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:drop_chunks_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:01 1999 PST | public | test_drop_chunks_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------+-----------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:01 1999 PST | public | test_drop_chunks_table | _timescaledb_internal | policy_retention_check
(1 row)
-- still only 1 run
@ -545,9 +545,9 @@ SELECT * FROM sorted_bgw_log;
(6 rows)
SELECT * FROM timescaledb_information.jobs WHERE job_id=:drop_chunks_job_id;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:02 1999 PST | public | test_drop_chunks_table
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+-------------------------+-------------------+-------------+-------------+--------------+-----------------------+------------------+-------------------+-----------+------------------------------------------------+------------------------------+-------------------+------------------------+-----------------------+------------------------
1001 | Retention Policy [1001] | @ 1 sec | @ 5 mins | -1 | @ 5 mins | _timescaledb_internal | policy_retention | default_perm_user | t | {"drop_after": "@ 4 mons", "hypertable_id": 2} | Fri Dec 31 16:00:02 1999 PST | public | test_drop_chunks_table | _timescaledb_internal | policy_retention_check
(1 row)
-- 2 runs
@ -622,16 +622,16 @@ SELECT add_retention_policy('test_drop_chunks_table_tsntz', INTERVAL '4 months')
-- Test that retention policy is being logged
SELECT alter_job(id,config:=jsonb_set(config,'{verbose_log}', 'true'))
FROM _timescaledb_config.bgw_job WHERE id = :drop_chunks_date_job_id;
alter_job
-------------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 1 day","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""verbose_log"": true, ""hypertable_id"": 3}",-infinity)
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 1 day","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""verbose_log"": true, ""hypertable_id"": 3}",-infinity,_timescaledb_internal.policy_retention_check)
(1 row)
SELECT alter_job(id,config:=jsonb_set(config,'{verbose_log}', 'true'))
FROM _timescaledb_config.bgw_job WHERE id = :drop_chunks_tsntz_job_id;
alter_job
-------------------------------------------------------------------------------------------------------------------------------------
(1003,"@ 1 day","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""verbose_log"": true, ""hypertable_id"": 4}",-infinity)
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1003,"@ 1 day","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""verbose_log"": true, ""hypertable_id"": 4}",-infinity,_timescaledb_internal.policy_retention_check)
(1 row)
CALL run_job(:drop_chunks_date_job_id);

View File

@ -269,9 +269,9 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
--alter the refresh interval and check if next_start is altered
SELECT alter_job(:job_id, schedule_interval => '1m', retry_period => '1m');
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:01:00 2000 PST")
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:01:00 2000 PST",_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT job_id, next_start - last_finish as until_next, total_runs
@ -309,9 +309,9 @@ SELECT (next_start - '30s'::interval) AS "NEW_NEXT_START"
FROM _timescaledb_internal.bgw_job_stat
WHERE job_id=:job_id \gset
SELECT alter_job(:job_id, next_start => :'NEW_NEXT_START');
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:02:30 2000 PST")
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:02:30 2000 PST",_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint * 1000000)+(extract(epoch from interval '2 minute 30 seconds')::bigint * 1000000), true);

View File

@ -301,9 +301,9 @@ SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint
--alter the refresh interval and check if next_start is altered
SELECT alter_job(:job_id, schedule_interval => '1m', retry_period => '1m');
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:01:00 2000 PST")
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:01:00 2000 PST",_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT job_id, next_start - last_finish as until_next, total_runs
@ -341,9 +341,9 @@ SELECT (next_start - '30s'::interval) AS "NEW_NEXT_START"
FROM _timescaledb_internal.bgw_job_stat
WHERE job_id=:job_id \gset
SELECT alter_job(:job_id, next_start => :'NEW_NEXT_START');
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:02:30 2000 PST")
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 min","@ 0",-1,"@ 1 min",t,"{""end_offset"": 4, ""start_offset"": null, ""mat_hypertable_id"": 2}","Sat Jan 01 04:02:30 2000 PST",_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT ts_bgw_params_reset_time((extract(epoch from interval '12 hour')::bigint * 1000000)+(extract(epoch from interval '2 minute 30 seconds')::bigint * 1000000), true);

View File

@ -97,9 +97,9 @@ WHERE hypertable_name = '_materialized_hypertable_2' ORDER BY range_start_intege
SELECT add_retention_policy( 'drop_chunks_view1', drop_after => 10) as drop_chunks_job_id1 \gset
SELECT alter_job(:drop_chunks_job_id1, schedule_interval => INTERVAL '1 second');
alter_job
----------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": 10, ""hypertable_id"": 2}",-infinity)
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": 10, ""hypertable_id"": 2}",-infinity,_timescaledb_internal.policy_retention_check)
(1 row)
SELECT ts_bgw_db_scheduler_test_run_and_wait_for_scheduler_finish(2000000);

View File

@ -579,9 +579,9 @@ SELECT _timescaledb_internal.alter_job_set_hypertable_id( :job_id, 'max_mat_view
(1 row)
SELECT * FROM timescaledb_information.jobs WHERE job_id != 1 ORDER BY 1;
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name
--------+----------------------------+-------------------+-------------+-------------+--------------+-------------+-------------+-------------------+-----------+----------------------+------------+-----------------------+----------------------------
1026 | User-Defined Action [1026] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | _timescaledb_internal | _materialized_hypertable_5
job_id | application_name | schedule_interval | max_runtime | max_retries | retry_period | proc_schema | proc_name | owner | scheduled | config | next_start | hypertable_schema | hypertable_name | check_schema | check_name
--------+----------------------------+-------------------+-------------+-------------+--------------+-------------+-------------+-------------------+-----------+----------------------+------------+-----------------------+----------------------------+--------------+------------
1026 | User-Defined Action [1026] | @ 1 hour | @ 0 | -1 | @ 5 mins | public | custom_func | default_perm_user | t | {"type": "function"} | | _timescaledb_internal | _materialized_hypertable_5 | |
(1 row)
SELECT timescaledb_experimental.remove_all_policies('max_mat_view_date', true); -- ignore custom job

View File

@ -101,9 +101,9 @@ SELECT schedule_interval FROM _timescaledb_config.bgw_job WHERE id = 1000;
-- You can change this setting with ALTER VIEW (equivalently, specify in WITH clause of CREATE VIEW)
SELECT alter_job(1000, schedule_interval := '1h');
alter_job
----------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 hour","@ 0",-1,"@ 2 hours",t,"{""end_offset"": ""@ 2 hours"", ""start_offset"": null, ""mat_hypertable_id"": 2}",-infinity)
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 hour","@ 0",-1,"@ 2 hours",t,"{""end_offset"": ""@ 2 hours"", ""start_offset"": null, ""mat_hypertable_id"": 2}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job WHERE id = 1000;

View File

@ -81,9 +81,9 @@ SELECT count(*) FROM _timescaledb_config.bgw_job WHERE proc_schema = '_timescale
(1 row)
SELECT alter_job(:retention_job_id, schedule_interval => INTERVAL '1 second');
alter_job
--------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""hypertable_id"": 1}",-infinity)
alter_job
-----------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 5 mins",-1,"@ 5 mins",t,"{""drop_after"": ""@ 4 mons"", ""hypertable_id"": 1}",-infinity,_timescaledb_internal.policy_retention_check)
(1 row)
SELECT * FROM _timescaledb_config.bgw_job where id=:retention_job_id;

View File

@ -38,17 +38,17 @@ select * from _timescaledb_config.bgw_job where id = :compressjob_id;
(1 row)
select * from alter_job(:compressjob_id, schedule_interval=>'1s');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------+------------
1000 | @ 1 sec | @ 0 | -1 | @ 1 hour | t | {"hypertable_id": 1, "compress_after": "@ 60 days"} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------+------------+------------------------------------------------
1000 | @ 1 sec | @ 0 | -1 | @ 1 hour | t | {"hypertable_id": 1, "compress_after": "@ 60 days"} | -infinity | _timescaledb_internal.policy_compression_check
(1 row)
--enable maxchunks to 1 so that only 1 chunk is compressed by the job
SELECT alter_job(id,config:=jsonb_set(config,'{maxchunks_to_compress}', '1'))
FROM _timescaledb_config.bgw_job WHERE id = :compressjob_id;
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 1, ""compress_after"": ""@ 60 days"", ""maxchunks_to_compress"": 1}",-infinity)
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 1, ""compress_after"": ""@ 60 days"", ""maxchunks_to_compress"": 1}",-infinity,_timescaledb_internal.policy_compression_check)
(1 row)
select * from _timescaledb_config.bgw_job where id >= 1000 ORDER BY id;
@ -328,16 +328,16 @@ SELECT add_compression_policy AS job_id
-- job compresses only 1 chunk at a time --
SELECT alter_job(id,config:=jsonb_set(config,'{maxchunks_to_compress}', '1'))
FROM _timescaledb_config.bgw_job WHERE id = :job_id;
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------
(1004,"@ 12 hours","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 11, ""compress_after"": ""@ 1 day"", ""maxchunks_to_compress"": 1}",-infinity)
alter_job
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1004,"@ 12 hours","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 11, ""compress_after"": ""@ 1 day"", ""maxchunks_to_compress"": 1}",-infinity,_timescaledb_internal.policy_compression_check)
(1 row)
SELECT alter_job(id,config:=jsonb_set(config,'{verbose_log}', 'true'))
FROM _timescaledb_config.bgw_job WHERE id = :job_id;
alter_job
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1004,"@ 12 hours","@ 0",-1,"@ 1 hour",t,"{""verbose_log"": true, ""hypertable_id"": 11, ""compress_after"": ""@ 1 day"", ""maxchunks_to_compress"": 1}",-infinity)
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1004,"@ 12 hours","@ 0",-1,"@ 1 hour",t,"{""verbose_log"": true, ""hypertable_id"": 11, ""compress_after"": ""@ 1 day"", ""maxchunks_to_compress"": 1}",-infinity,_timescaledb_internal.policy_compression_check)
(1 row)
set client_min_messages TO LOG;
@ -553,9 +553,9 @@ SELECT chunk_status FROM compressed_chunk_info_view WHERE hypertable_name = 'met
-- disable recompress in compress job
SELECT alter_job(id,config:=jsonb_set(config,'{recompress}','false')) FROM _timescaledb_config.bgw_job WHERE id = :JOB_COMPRESS;
alter_job
--------------------------------------------------------------------------------------------------------------------------------------
(1006,"@ 7 days","@ 0",-1,"@ 5 mins",t,"{""recompress"": false, ""hypertable_id"": 16, ""compress_after"": ""@ 7 days""}",-infinity)
alter_job
---------------------------------------------------------------------------------------------------------------------------------------
(1006,"@ 7 days","@ 0",-1,"@ 5 mins",t,"{""recompress"": false, ""hypertable_id"": 16, ""compress_after"": ""@ 7 days""}",-infinity,)
(1 row)
-- nothing to do
@ -587,9 +587,9 @@ SELECT chunk_status FROM compressed_chunk_info_view WHERE hypertable_name = 'met
-- reenable recompress in compress job
SELECT alter_job(id,config:=jsonb_set(config,'{recompress}','true')) FROM _timescaledb_config.bgw_job WHERE id = :JOB_COMPRESS;
alter_job
-------------------------------------------------------------------------------------------------------------------------------------
(1006,"@ 7 days","@ 0",-1,"@ 5 mins",t,"{""recompress"": true, ""hypertable_id"": 16, ""compress_after"": ""@ 7 days""}",-infinity)
alter_job
--------------------------------------------------------------------------------------------------------------------------------------
(1006,"@ 7 days","@ 0",-1,"@ 5 mins",t,"{""recompress"": true, ""hypertable_id"": 16, ""compress_after"": ""@ 7 days""}",-infinity,)
(1 row)
-- should recompress now

View File

@ -855,9 +855,9 @@ SELECT add_continuous_aggregate_policy('mat_with_test', NULL, '5 h'::interval, '
(1 row)
SELECT alter_job(id, schedule_interval => '1h') FROM _timescaledb_config.bgw_job;
alter_job
------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 1 hour","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity)
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 1 hour","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;
@ -867,9 +867,9 @@ SELECT schedule_interval FROM _timescaledb_config.bgw_job;
(1 row)
SELECT alter_job(id, schedule_interval => '2h') FROM _timescaledb_config.bgw_job;
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity)
alter_job
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;
@ -948,9 +948,9 @@ SELECT add_continuous_aggregate_policy('mat_with_test', NULL, 500::integer, '12
(1 row)
SELECT alter_job(id, schedule_interval => '2h') FROM _timescaledb_config.bgw_job;
alter_job
---------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": 500, ""start_offset"": null, ""mat_hypertable_id"": 23}",-infinity)
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": 500, ""start_offset"": null, ""mat_hypertable_id"": 23}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;

View File

@ -869,9 +869,9 @@ SELECT add_continuous_aggregate_policy('mat_with_test', NULL, '5 h'::interval, '
(1 row)
SELECT alter_job(id, schedule_interval => '1h') FROM _timescaledb_config.bgw_job;
alter_job
------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 1 hour","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity)
alter_job
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 1 hour","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;
@ -881,9 +881,9 @@ SELECT schedule_interval FROM _timescaledb_config.bgw_job;
(1 row)
SELECT alter_job(id, schedule_interval => '2h') FROM _timescaledb_config.bgw_job;
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity)
alter_job
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1001,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": ""@ 5 hours"", ""start_offset"": null, ""mat_hypertable_id"": 20}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;
@ -967,9 +967,9 @@ SELECT add_continuous_aggregate_policy('mat_with_test', NULL, 500::integer, '12
(1 row)
SELECT alter_job(id, schedule_interval => '2h') FROM _timescaledb_config.bgw_job;
alter_job
---------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": 500, ""start_offset"": null, ""mat_hypertable_id"": 23}",-infinity)
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1002,"@ 2 hours","@ 0",-1,"@ 12 hours",t,"{""end_offset"": 500, ""start_offset"": null, ""mat_hypertable_id"": 23}",-infinity,_timescaledb_internal.policy_refresh_continuous_aggregate_check)
(1 row)
SELECT schedule_interval FROM _timescaledb_config.bgw_job;

View File

@ -660,9 +660,9 @@ select * from _timescaledb_config.bgw_job where id = :compressjob_id;
(1 row)
select * from alter_job(:compressjob_id, schedule_interval=>'1s');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------+------------
1000 | @ 1 sec | @ 0 | -1 | @ 1 hour | t | {"hypertable_id": 2, "compress_after": "@ 60 days"} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------+------------+------------------------------------------------
1000 | @ 1 sec | @ 0 | -1 | @ 1 hour | t | {"hypertable_id": 2, "compress_after": "@ 60 days"} | -infinity | _timescaledb_internal.policy_compression_check
(1 row)
select * from _timescaledb_config.bgw_job where id >= 1000 ORDER BY id;
@ -674,9 +674,9 @@ select * from _timescaledb_config.bgw_job where id >= 1000 ORDER BY id;
-- we want only 1 chunk to be compressed --
SELECT alter_job(id,config:=jsonb_set(config,'{maxchunks_to_compress}', '1'))
FROM _timescaledb_config.bgw_job WHERE id = :compressjob_id;
alter_job
--------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 2, ""compress_after"": ""@ 60 days"", ""maxchunks_to_compress"": 1}",-infinity)
alter_job
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(1000,"@ 1 sec","@ 0",-1,"@ 1 hour",t,"{""hypertable_id"": 2, ""compress_after"": ""@ 60 days"", ""maxchunks_to_compress"": 1}",-infinity,_timescaledb_internal.policy_compression_check)
(1 row)
insert into conditions

View File

@ -626,72 +626,72 @@ select add_reorder_policy('test_table', 'test_table_time_idx') as job_id \gset
-- No change
select * from alter_job(:job_id);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 84 hours | @ 0 | -1 | @ 5 mins | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 84 hours | @ 0 | -1 | @ 5 mins | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
-- Changes expected
select * from alter_job(:job_id, INTERVAL '3 years', INTERVAL '5 min', 5, INTERVAL '123 sec');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+-----------------+-----------+-----------------------------------------------------------+------------
1014 | @ 3 years | @ 5 mins | 5 | @ 2 mins 3 secs | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+-----------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 3 years | @ 5 mins | 5 | @ 2 mins 3 secs | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, INTERVAL '123 years');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+-----------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 5 mins | 5 | @ 2 mins 3 secs | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+-----------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 5 mins | 5 | @ 2 mins 3 secs | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, retry_period => INTERVAL '33 hours');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 5 mins | 5 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 5 mins | 5 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, max_runtime => INTERVAL '456 sec');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | 5 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | 5 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, max_retries => 0);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | 0 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | 0 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, max_retries => -1);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | -1 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | -1 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, max_retries => 20);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
-- No change
select * from alter_job(:job_id, max_runtime => NULL);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select * from alter_job(:job_id, max_retries => NULL);
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 123 years | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
--change schedule_interval when bgw_job_stat does not exist
select * from alter_job(:job_id, schedule_interval=>'1 min');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 1 min | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 1 min | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
select count(*) = 0 from _timescaledb_internal.bgw_job_stat where job_id = :job_id;
@ -702,23 +702,23 @@ select count(*) = 0 from _timescaledb_internal.bgw_job_stat where job_id = :job_
--set next_start when bgw_job_stat does not exist
select * from alter_job(:job_id, next_start=>'2001-01-01 01:01:01');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------
1014 | @ 1 min | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Mon Jan 01 01:01:01 2001 PST
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------+--------------------------------------------
1014 | @ 1 min | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Mon Jan 01 01:01:01 2001 PST | _timescaledb_internal.policy_reorder_check
(1 row)
--change schedule_interval when no last_finish set
select * from alter_job(:job_id, schedule_interval=>'10 min');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 10 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 10 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | -infinity | _timescaledb_internal.policy_reorder_check
(1 row)
--next_start overrides any schedule_interval changes
select * from alter_job(:job_id, schedule_interval=>'20 min', next_start=>'2002-01-01 01:01:01');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------
1014 | @ 20 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Tue Jan 01 01:01:01 2002 PST
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------+--------------------------------------------
1014 | @ 20 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Tue Jan 01 01:01:01 2002 PST | _timescaledb_internal.policy_reorder_check
(1 row)
--set the last_finish manually
@ -727,30 +727,30 @@ UPDATE _timescaledb_internal.bgw_job_stat SET last_finish = '2003-01-01:01:01:01
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
--not changing the interval doesn't change the next_start
select * from alter_job(:job_id, schedule_interval=>'20 min');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------
1014 | @ 20 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Tue Jan 01 01:01:01 2002 PST
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------+--------------------------------------------
1014 | @ 20 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Tue Jan 01 01:01:01 2002 PST | _timescaledb_internal.policy_reorder_check
(1 row)
--changing the interval changes next_start
select * from alter_job(:job_id, schedule_interval=>'30 min');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------
1014 | @ 30 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Wed Jan 01 01:31:01 2003 PST
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------+--------------------------------------------
1014 | @ 30 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Wed Jan 01 01:31:01 2003 PST | _timescaledb_internal.policy_reorder_check
(1 row)
--explicit next start overrides.
select * from alter_job(:job_id, schedule_interval=>'40 min', next_start=>'2004-01-01 01:01:01');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------
1014 | @ 40 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Thu Jan 01 01:01:01 2004 PST
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------------------------+--------------------------------------------
1014 | @ 40 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | Thu Jan 01 01:01:01 2004 PST | _timescaledb_internal.policy_reorder_check
(1 row)
--test pausing
select * from alter_job(:job_id, next_start=>'infinity');
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------
1014 | @ 40 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | infinity
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+------------------+-------------+--------------+-----------+-----------------------------------------------------------+------------+--------------------------------------------
1014 | @ 40 mins | @ 7 mins 36 secs | 20 | @ 33 hours | t | {"index_name": "test_table_time_idx", "hypertable_id": 7} | infinity | _timescaledb_internal.policy_reorder_check
(1 row)
--test that you can use now() to unpause
@ -805,9 +805,9 @@ ERROR: configuration hypertable id 47 not found
-- Check if_exists boolean works correctly
select * from alter_job(1234, if_exists => TRUE);
NOTICE: job 1234 not found, skipping
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start
--------+-------------------+-------------+-------------+--------------+-----------+--------+------------
| | | | | | |
job_id | schedule_interval | max_runtime | max_retries | retry_period | scheduled | config | next_start | check_config
--------+-------------------+-------------+-------------+--------------+-----------+--------+------------+--------------
| | | | | | | |
(1 row)
\set ON_ERROR_STOP 0

View File

@ -98,15 +98,15 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text
_timescaledb_internal.partialize_agg(anyelement)
_timescaledb_internal.ping_data_node(name)
_timescaledb_internal.policy_compression(integer,jsonb)
_timescaledb_internal.policy_compression_check(integer,jsonb)
_timescaledb_internal.policy_compression_check(jsonb)
_timescaledb_internal.policy_compression_execute(integer,integer,anyelement,integer,boolean,boolean)
_timescaledb_internal.policy_recompression(integer,jsonb)
_timescaledb_internal.policy_refresh_continuous_aggregate(integer,jsonb)
_timescaledb_internal.policy_refresh_continuous_aggregate_check(integer,jsonb)
_timescaledb_internal.policy_refresh_continuous_aggregate_check(jsonb)
_timescaledb_internal.policy_reorder(integer,jsonb)
_timescaledb_internal.policy_reorder_check(integer,jsonb)
_timescaledb_internal.policy_reorder_check(jsonb)
_timescaledb_internal.policy_retention(integer,jsonb)
_timescaledb_internal.policy_retention_check(integer,jsonb)
_timescaledb_internal.policy_retention_check(jsonb)
_timescaledb_internal.process_ddl_event()
_timescaledb_internal.range_value_to_pretty(bigint,regtype)
_timescaledb_internal.relation_size(regclass)
@ -140,7 +140,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text
add_job(regproc,interval,jsonb,timestamp with time zone,boolean,regproc)
add_reorder_policy(regclass,name,boolean)
add_retention_policy(regclass,"any",boolean,interval)
alter_job(integer,interval,interval,integer,interval,boolean,jsonb,timestamp with time zone,boolean)
alter_job(integer,interval,interval,integer,interval,boolean,jsonb,timestamp with time zone,boolean,regproc)
approximate_row_count(regclass)
attach_data_node(name,regclass,boolean,boolean)
attach_tablespace(name,regclass,boolean)

View File

@ -317,3 +317,248 @@ FROM _timescaledb_config.bgw_job WHERE id = :job_id_5;
-- Stop Background Workers
SELECT _timescaledb_internal.stop_background_workers();
SELECT _timescaledb_internal.restart_background_workers();
\set ON_ERROR_STOP 0
-- add test for custom jobs with custom check functions
-- create the functions/procedures to be used as checking functions
CREATE OR REPLACE PROCEDURE test_config_check_proc(config jsonb)
LANGUAGE PLPGSQL
AS $$
DECLARE
drop_after interval;
BEGIN
SELECT jsonb_object_field_text (config, 'drop_after')::interval INTO STRICT drop_after;
IF drop_after IS NULL THEN
RAISE EXCEPTION 'Config must be not NULL and have drop_after';
END IF ;
END
$$;
CREATE OR REPLACE FUNCTION test_config_check_func(config jsonb) RETURNS VOID
AS $$
DECLARE
drop_after interval;
BEGIN
IF config IS NULL THEN
RETURN;
END IF;
SELECT jsonb_object_field_text (config, 'drop_after')::interval INTO STRICT drop_after;
IF drop_after IS NULL THEN
RAISE EXCEPTION 'Config can be NULL but must have drop_after if not';
END IF ;
END
$$ LANGUAGE PLPGSQL;
-- step 2, create a procedure to run as a custom job
CREATE OR REPLACE PROCEDURE test_proc_with_check(job_id int, config jsonb)
LANGUAGE PLPGSQL
AS $$
BEGIN
RAISE NOTICE 'Will only print this if config passes checks, my config is %', config;
END
$$;
-- step 3, add the job with the config check function passed as argument
-- test procedures
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_proc'::regproc);
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_proc'::regproc);
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "chicken"}', check_config => 'test_config_check_proc'::regproc);
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "2 weeks"}', check_config => 'test_config_check_proc'::regproc)
as job_with_proc_check_id \gset
-- test functions
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func'::regproc);
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_func'::regproc);
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "chicken"}', check_config => 'test_config_check_func'::regproc);
select add_job('test_proc_with_check', '5 secs', config => '{"drop_after": "2 weeks"}', check_config => 'test_config_check_func'::regproc)
as job_with_func_check_id \gset
--- test alter_job
select alter_job(:job_with_func_check_id, config => '{"drop_after":"chicken"}');
select alter_job(:job_with_func_check_id, config => '{"drop_after":"5 years"}');
select alter_job(:job_with_proc_check_id, config => '{"drop_after":"4 days"}');
-- test that jobs with an incorrect check function signature will not be registered
-- these are all incorrect function signatures
CREATE OR REPLACE FUNCTION test_config_check_func_0args() RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take no arguments and will validate anything you give me!';
END
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION test_config_check_func_2args(config jsonb, intarg int) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take two arguments (jsonb, int) and I should fail to run!';
END
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION test_config_check_func_intarg(config int) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'I take one argument which is an integer and I should fail to run!';
END
$$ LANGUAGE PLPGSQL;
-- -- this should fail, it has an incorrect check function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_0args'::regproc);
-- -- so should this
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_2args'::regproc);
-- and this
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_intarg'::regproc);
-- and this fails as it calls a nonexistent function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_nonexistent_check_func'::regproc);
-- when called with a valid check function and a NULL config no check should occur
CREATE OR REPLACE FUNCTION test_config_check_func(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message will get printed for both NULL and not NULL config';
END
$$ LANGUAGE PLPGSQL;
SET client_min_messages = NOTICE;
-- check done for both NULL and non-NULL config
select add_job('test_proc_with_check', '5 secs', config => NULL, check_config => 'test_config_check_func'::regproc);
-- check done
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func'::regproc) as job_id \gset
-- check function not returning void
CREATE OR REPLACE FUNCTION test_config_check_func_returns_int(config jsonb) RETURNS INT
AS $$
BEGIN
raise notice 'I print a message, and then I return least(1,2)';
RETURN LEAST(1, 2);
END
$$ LANGUAGE PLPGSQL;
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_config_check_func_returns_int'::regproc) as job_id_int \gset
-- drop the registered check function, verify that alter_job will work and print a warning that
-- the check is being skipped due to the check function missing
ALTER FUNCTION test_config_check_func RENAME TO renamed_func;
select alter_job(:job_id, schedule_interval => '1 hour');
DROP FUNCTION test_config_check_func_returns_int;
select alter_job(:job_id_int, config => '{"field":"value"}');
-- rename the check function and then call alter_job to register the new name
select alter_job(:job_id, check_config => 'renamed_func'::regproc);
-- run alter again, should get a config check
select alter_job(:job_id, config => '{}');
-- do not drop the current check function but register a new one
CREATE OR REPLACE FUNCTION substitute_check_func(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message is a substitute of the previously printed one';
END
$$ LANGUAGE PLPGSQL;
-- register the new check
select alter_job(:job_id, check_config => 'substitute_check_func');
select alter_job(:job_id, config => '{}');
RESET client_min_messages;
-- test an oid that doesn't exist
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 17424217::regproc);
\c :TEST_DBNAME :ROLE_SUPERUSER
-- test a function with insufficient privileges
create schema test_schema;
create role user_noexec with login;
grant usage on schema test_schema to user_noexec;
CREATE OR REPLACE FUNCTION test_schema.test_config_check_func_privileges(config jsonb) RETURNS VOID
AS $$
BEGIN
RAISE NOTICE 'This message will only get printed if privileges suffice';
END
$$ LANGUAGE PLPGSQL;
revoke execute on function test_schema.test_config_check_func_privileges from public;
-- verify the user doesn't have execute permissions on the function
select has_function_privilege('user_noexec', 'test_schema.test_config_check_func_privileges(jsonb)', 'execute');
\c :TEST_DBNAME user_noexec
-- user_noexec should not have exec permissions on this function
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'test_schema.test_config_check_func_privileges'::regproc);
\c :TEST_DBNAME :ROLE_SUPERUSER
-- check that alter_job rejects a check function with invalid signature
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'renamed_func') as job_id_alter \gset
select alter_job(:job_id_alter, check_config => 'test_config_check_func_0args');
select alter_job(:job_id_alter);
-- test that we can unregister the check function
select alter_job(:job_id_alter, check_config => 0);
-- no message printed now
select alter_job(:job_id_alter, config => '{}');
-- test what happens if the check function contains a COMMIT
-- procedure with transaction handling
CREATE OR REPLACE PROCEDURE custom_proc2_jsonb(config jsonb) LANGUAGE PLPGSQL AS
$$
BEGIN
-- RAISE NOTICE 'Starting some transactions inside procedure';
INSERT INTO custom_log VALUES(1, $1, 'custom_proc 1 COMMIT');
COMMIT;
END
$$;
select add_job('test_proc_with_check', '5 secs', config => '{}') as job_id_err \gset
select alter_job(:job_id_err, check_config => 'custom_proc2_jsonb');
select alter_job(:job_id_err, schedule_interval => '3 minutes');
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'custom_proc2_jsonb') as job_id_commit \gset
-- test the case where we have a background job that registers jobs with a check fn
CREATE OR REPLACE PROCEDURE add_scheduled_jobs_with_check(job_id int, config jsonb) LANGUAGE PLPGSQL AS
$$
BEGIN
perform add_job('test_proc_with_check', schedule_interval => '10 secs', config => '{}', check_config => 'renamed_func');
END
$$;
select add_job('add_scheduled_jobs_with_check', schedule_interval => '1 hour') as last_job_id \gset
-- wait for enough time
SELECT wait_for_job_to_run(:last_job_id, 1);
select total_runs, total_successes, last_run_status from timescaledb_information.job_stats where job_id = :last_job_id;
-- test coverage for alter_job
-- registering an invalid oid
select alter_job(:job_id_alter, check_config => 123456789::regproc);
-- registering a function with insufficient privileges
\c :TEST_DBNAME user_noexec
select * from add_job('test_proc_with_check', '5 secs', config => '{}') as job_id_owner \gset
select * from alter_job(:job_id_owner, check_config => 'test_schema.test_config_check_func_privileges'::regproc);
\c :TEST_DBNAME :ROLE_SUPERUSER
DROP SCHEMA test_schema CASCADE;
DROP ROLE user_noexec;
-- test with aggregate check proc
create function jsonb_add (j1 jsonb, j2 jsonb) returns jsonb
AS $$
BEGIN
RETURN j1 || j2;
END
$$ LANGUAGE PLPGSQL;
create table jsonb_values (j jsonb, i int);
insert into jsonb_values values ('{"refresh_after":"2 weeks"}', 1), ('{"compress_after":"2 weeks"}', 2), ('{"drop_after":"2 weeks"}', 3);
CREATE AGGREGATE sum_jsb (jsonb)
(
sfunc = jsonb_add,
stype = jsonb,
initcond = '{}'
);
-- for test coverage, check unsupported aggregate type
select add_job('test_proc_with_check', '5 secs', config => '{}', check_config => 'sum_jsb'::regproc);