Skip to content

Commit

Permalink
Fix cagg trigger on compat schema layer
Browse files Browse the repository at this point in the history
The trigger `continuous_agg_invalidation_trigger` receive the hypertable
id as parameter as the following example:

Triggers:
    ts_cagg_invalidation_trigger AFTER INSERT OR DELETE OR UPDATE ON
       _timescaledb_internal._hyper_3_59_chunk
    FOR EACH ROW EXECUTE FUNCTION
       _timescaledb_functions.continuous_agg_invalidation_trigger('3')

The problem is in the compatibility layer using PL/pgSQL code there's no
way to passdown the parameter from the wrapper trigger function created
to the underlying trigger function in another schema.

To solve this we simple create a new function in the deprecated
`_timescaledb_internal` schema pointing to the function trigger and
inside the C code we emit the WARNING message if the function is called
from the deprecated schema.
  • Loading branch information
fabriziomello committed Oct 6, 2023
1 parent b514d05 commit 9c09d8f
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 11 deletions.
12 changes: 2 additions & 10 deletions sql/compat.sql
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,8 @@ BEGIN
END$$
SET search_path TO pg_catalog,pg_temp;


CREATE OR REPLACE FUNCTION _timescaledb_internal.continuous_agg_invalidation_trigger() RETURNS trigger LANGUAGE PLPGSQL AS $$
BEGIN
IF current_setting('timescaledb.enable_deprecation_warnings', true)::bool THEN
RAISE WARNING 'function _timescaledb_internal.continuous_agg_invalidation_trigger() is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.';
END IF;
RETURN _timescaledb_functions.continuous_agg_invalidation_trigger();
END$$
SET search_path TO pg_catalog,pg_temp;

CREATE OR REPLACE FUNCTION _timescaledb_internal.continuous_agg_invalidation_trigger() RETURNS TRIGGER
AS '@MODULE_PATHNAME@', 'ts_continuous_agg_invalidation_trigger' LANGUAGE C;

-- we have to prefix slices, schema_name and table_name parameter with _ here to not clash with output names otherwise plpgsql will complain
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk(hypertable regclass,_slices jsonb,_schema_name name=NULL,_table_name name=NULL,chunk_table regclass=NULL) RETURNS TABLE(chunk_id INTEGER, hypertable_id INTEGER, schema_name NAME, table_name NAME, relkind "char", slices JSONB, created BOOLEAN) LANGUAGE PLPGSQL AS $$
Expand Down
2 changes: 1 addition & 1 deletion src/guc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern bool ts_telemetry_on(void);
extern bool ts_function_telemetry_on(void);
#endif

extern bool ts_guc_enable_deprecation_warnings;
extern TSDLLEXPORT bool ts_guc_enable_deprecation_warnings;
extern bool ts_guc_enable_optimizations;
extern bool ts_guc_enable_constraint_aware_append;
extern bool ts_guc_enable_ordered_append;
Expand Down
9 changes: 9 additions & 0 deletions tsl/src/continuous_aggs/insert.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "chunk.h"
#include "dimension.h"
#include "guc.h"
#include "hypertable.h"
#include "hypertable_cache.h"
#include "invalidation.h"
Expand Down Expand Up @@ -222,6 +223,14 @@ continuous_agg_trigfn(PG_FUNCTION_ARGS)
if (trigdata == NULL || trigdata->tg_trigger == NULL || trigdata->tg_trigger->tgnargs < 0)
elog(ERROR, "must supply hypertable id");

if (ts_guc_enable_deprecation_warnings && OidIsValid(trigdata->tg_trigger->tgfoid) &&
strcmp(get_namespace_name(get_func_namespace(trigdata->tg_trigger->tgfoid)),
INTERNAL_SCHEMA_NAME) == 0)
elog(WARNING,
"function _timescaledb_internal.continuous_agg_invalidation_trigger() is deprecated "
"and has been moved to _timescaledb_functions schema. this compatibility function "
"will be removed in a future version.");

hypertable_id_str = trigdata->tg_trigger->tgargs[0];
hypertable_id = atol(hypertable_id_str);

Expand Down
28 changes: 28 additions & 0 deletions tsl/test/shared/expected/compat.out
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ ERROR: hypertable cannot be NULL
SELECT _timescaledb_internal.create_compressed_chunk(0,0,0,0,0,0,0,0,0,0);
WARNING: function _timescaledb_internal.create_compressed_chunk(regclass,regclass,bigint,bigint,bigint,bigint,bigint,bigint,bigint,bigint) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.
ERROR: invalid Oid
SELECT _timescaledb_internal.continuous_agg_invalidation_trigger();
ERROR: must supply hypertable id
SELECT _timescaledb_internal.data_node_chunk_info(NULL,NULL,NULL);
WARNING: function _timescaledb_internal.data_node_chunk_info(name,name,name) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.
data_node_chunk_info
Expand Down Expand Up @@ -421,3 +423,29 @@ WARNING: procedure _timescaledb_internal.policy_retention(integer,jsonb) is dep
CALL _timescaledb_internal.wait_subscription_sync(NULL,NULL,0,0);
WARNING: procedure _timescaledb_internal.wait_subscription_sync(name,name,integer,numeric) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.
ERROR: subscription sync wait timedout
\set ON_ERROR_STOP 1
-- tests for the cagg invalidation trigger on the deprecated schema
CREATE TABLE sensor_data (
time timestamptz NOT NULL,
sensor_id integer NOT NULL,
cpu double precision NULL,
temperature double precision NULL
);
SELECT hypertable_id FROM create_hypertable('sensor_data','time') \gset
CREATE MATERIALIZED VIEW sensor_data_hourly WITH (timescaledb.continuous, timescaledb.materialized_only=false) AS
SELECT sensor_id,
time_bucket(INTERVAL '1 hour', time) AS timestamp,
min(time) AS first_data_received,
max(time) AS last_data_received
FROM sensor_data
GROUP BY sensor_id, time_bucket(INTERVAL '1 hour', time)
WITH DATA;
NOTICE: continuous aggregate "sensor_data_hourly" is already up-to-date
DROP TRIGGER ts_cagg_invalidation_trigger ON sensor_data;
CREATE TRIGGER ts_cagg_invalidation_trigger
AFTER INSERT OR DELETE OR UPDATE ON sensor_data
FOR EACH ROW EXECUTE FUNCTION _timescaledb_internal.continuous_agg_invalidation_trigger(:'hypertable_id');
-- should WARN about the deprecated schema usage
SET timescaledb.enable_deprecation_warnings = 'on'; -- make sure the GUC is enabled
INSERT INTO sensor_data values('1980-01-01 00:00:00-00', 1, 1, 1);
WARNING: function _timescaledb_internal.continuous_agg_invalidation_trigger() is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.
31 changes: 31 additions & 0 deletions tsl/test/shared/sql/compat.sql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ SELECT _timescaledb_internal.create_chunk(0,NULL,NULL,NULL,0);
SELECT _timescaledb_internal.create_chunk_replica_table(0,NULL);
SELECT _timescaledb_internal.create_chunk_table(0,NULL,NULL,NULL);
SELECT _timescaledb_internal.create_compressed_chunk(0,0,0,0,0,0,0,0,0,0);
SELECT _timescaledb_internal.continuous_agg_invalidation_trigger();
SELECT _timescaledb_internal.data_node_chunk_info(NULL,NULL,NULL);
SELECT _timescaledb_internal.data_node_compressed_chunk_stats(NULL,NULL,NULL);
SELECT _timescaledb_internal.data_node_hypertable_info(NULL,NULL,NULL);
Expand Down Expand Up @@ -107,3 +108,33 @@ CALL _timescaledb_internal.policy_reorder(0,NULL);
CALL _timescaledb_internal.policy_retention(0,NULL);
CALL _timescaledb_internal.wait_subscription_sync(NULL,NULL,0,0);

\set ON_ERROR_STOP 1

-- tests for the cagg invalidation trigger on the deprecated schema
CREATE TABLE sensor_data (
time timestamptz NOT NULL,
sensor_id integer NOT NULL,
cpu double precision NULL,
temperature double precision NULL
);

SELECT hypertable_id FROM create_hypertable('sensor_data','time') \gset

CREATE MATERIALIZED VIEW sensor_data_hourly WITH (timescaledb.continuous, timescaledb.materialized_only=false) AS
SELECT sensor_id,
time_bucket(INTERVAL '1 hour', time) AS timestamp,
min(time) AS first_data_received,
max(time) AS last_data_received
FROM sensor_data
GROUP BY sensor_id, time_bucket(INTERVAL '1 hour', time)
WITH DATA;

DROP TRIGGER ts_cagg_invalidation_trigger ON sensor_data;

CREATE TRIGGER ts_cagg_invalidation_trigger
AFTER INSERT OR DELETE OR UPDATE ON sensor_data
FOR EACH ROW EXECUTE FUNCTION _timescaledb_internal.continuous_agg_invalidation_trigger(:'hypertable_id');

-- should WARN about the deprecated schema usage
SET timescaledb.enable_deprecation_warnings = 'on'; -- make sure the GUC is enabled
INSERT INTO sensor_data values('1980-01-01 00:00:00-00', 1, 1, 1);

0 comments on commit 9c09d8f

Please sign in to comment.