--This file provides a utility for executing dblink commands transactionally (almost) with the local transaction. --Most command executed by the *_exec functions will be committed only when the local transaction commits. --Registers a dblink connection to be commited on local pre-commit or aborted on local abort. CREATE OR REPLACE FUNCTION _timescaledb_internal.register_dblink_precommit_connection(text) RETURNS VOID AS '$libdir/timescaledb', 'register_dblink_precommit_connection' LANGUAGE C VOLATILE STRICT; --Called by _timescaledb_internal.meta_transaction_exec to start a transaction. Should not be called directly. --Returns the dblink connection name for the started transaction. CREATE OR REPLACE FUNCTION _timescaledb_internal.meta_transaction_start() RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE conn_exists BOOLEAN; conn_name TEXT = 'meta_conn'; BEGIN SELECT conn_name = ANY (conn) INTO conn_exists FROM dblink_get_connections() conn; IF conn_exists IS NULL OR NOT conn_exists THEN --tells c code to commit in precommit. PERFORM dblink_connect(conn_name, _timescaledb_internal.get_meta_server_name()); PERFORM dblink_exec(conn_name, 'BEGIN'); PERFORM _timescaledb_internal.register_dblink_precommit_connection(conn_name); END IF; RETURN conn_name; END $BODY$; --This should be called to execute code on a meta node. It is not necessary to --call _timescaledb_internal.meta_transaction_start() beforehand. The code excuted by this function --will be automatically committed when the local transaction commits (in pre-commit). CREATE OR REPLACE FUNCTION _timescaledb_internal.meta_transaction_exec( sql_code text ) RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE conn_name TEXT; BEGIN IF _timescaledb_internal.get_meta_database_name() <> current_database() THEN SELECT _timescaledb_internal.meta_transaction_start() INTO conn_name; PERFORM * FROM dblink(conn_name, sql_code) AS t(r TEXT); ELSE EXECUTE sql_code; END IF; END $BODY$; --This should be called to execute code on a meta node with a text return. It is not necessary to --call _timescaledb_internal.meta_transaction_start() beforehand. The code excuted by this function --will be automatically committed when the local transaction commits (in pre-commit). CREATE OR REPLACE FUNCTION _timescaledb_internal.meta_transaction_exec_with_return( sql_code text ) RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE conn_name TEXT; return_value TEXT; BEGIN IF _timescaledb_internal.get_meta_database_name() <> current_database() THEN SELECT _timescaledb_internal.meta_transaction_start() INTO conn_name; SELECT t.r INTO return_value FROM dblink(conn_name, sql_code) AS t(r TEXT); ELSE EXECUTE sql_code INTO return_value; END IF; RETURN return_value; END $BODY$; --This should be called to execute code on a meta node in a way that doesn't wait for the local commit. --i.e. This command is committed on meta right away w/o waiting for the local commit. --A consequence is that the remote command will not be rolled back if the local transaction is. CREATE OR REPLACE FUNCTION _timescaledb_internal.meta_immediate_commit_exec_with_return( sql_code text ) RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE return_value TEXT; BEGIN IF _timescaledb_internal.get_meta_database_name() <> current_database() THEN SELECT t.r INTO return_value FROM dblink(_timescaledb_internal.get_meta_server_name(), sql_code) AS t(r TEXT); ELSE EXECUTE sql_code INTO return_value; END IF; RETURN return_value; END $BODY$; --Called by _timescaledb_meta.node_transaction_exec_with_return to start a transaction. Should not be called directly. --Returns the dblink connection name for the started transaction. CREATE OR REPLACE FUNCTION _timescaledb_meta.node_transaction_start(database_name NAME, server_name NAME) RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE conn_exists BOOLEAN; conn_name TEXT; BEGIN IF database_name = current_database() THEN RETURN NULL; END IF; conn_name = 'conn_'|| server_name; SELECT conn_name = ANY (conn) INTO conn_exists FROM dblink_get_connections() conn; IF conn_exists IS NULL OR NOT conn_exists THEN --tells c code to commit in precommit. PERFORM dblink_connect(conn_name, server_name); PERFORM dblink_exec(conn_name, 'BEGIN'); PERFORM _timescaledb_internal.register_dblink_precommit_connection(conn_name); END IF; RETURN conn_name; END $BODY$; --This should be called to execute code on a meta node with a text return. It is not necessary to --call _timescaledb_internal.node_transaction_start() beforehand. The code excuted by this function --will be automatically committed when the local transaction commits (in pre-commit). CREATE OR REPLACE FUNCTION _timescaledb_meta.node_transaction_exec_with_return( database_name NAME, server_name NAME, sql_code TEXT ) RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE conn_name TEXT; return_value TEXT; BEGIN SELECT _timescaledb_meta.node_transaction_start(database_name, server_name) INTO conn_name; IF conn_name IS NOT NULL THEN SELECT t.r INTO return_value FROM dblink(conn_name, sql_code) AS t(r TEXT); ELSE EXECUTE sql_code INTO return_value; END IF; RETURN return_value; END $BODY$; --This should be called to execute code on a data node in a way that doesn't wait for the local commit. --i.e. This command is committed on meta right away w/o waiting for the local commit. --A consequence is that the remote command will not be rolled back if the local transaction is. CREATE OR REPLACE FUNCTION _timescaledb_internal.node_immediate_commit_exec_with_return( database_name NAME, server_name NAME, sql_code TEXT ) RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE return_value TEXT; BEGIN IF database_name <> current_database() THEN SELECT t.r INTO return_value FROM dblink(server_name, sql_code) AS t(r TEXT); ELSE EXECUTE sql_code INTO return_value; END IF; RETURN return_value; END $BODY$;