Change trigger type to AFTER trigger.
During repacking table, if a transaction executes INSERT CONFLICT ON UPDATE/DO NOTHING, because we define BEFORE trigger on target table, the contents of operation log table becomes inconsistent easliy. As a result, pg_reapck fails with a high probability. To resolve this issue, this changes the trigger type from BEFORE to AFTER. We define AFTER trigger that is the first of the AFTER trigger to fire on the table.
This commit is contained in:
@ -68,8 +68,8 @@ LANGUAGE sql STABLE STRICT;
|
||||
CREATE FUNCTION repack.get_create_trigger(relid oid, pkid oid)
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT 'CREATE TRIGGER z_repack_trigger' ||
|
||||
' BEFORE INSERT OR DELETE OR UPDATE ON ' || repack.oid2text($1) ||
|
||||
SELECT 'CREATE TRIGGER a_repack_trigger' ||
|
||||
' AFTER INSERT OR DELETE OR UPDATE ON ' || repack.oid2text($1) ||
|
||||
' FOR EACH ROW EXECUTE PROCEDURE repack.repack_trigger(' ||
|
||||
'''INSERT INTO repack.log_' || $1 || '(pk, row) VALUES(' ||
|
||||
' CASE WHEN $1 IS NULL THEN NULL ELSE (ROW($1.' ||
|
||||
@ -82,7 +82,7 @@ CREATE FUNCTION repack.get_enable_trigger(relid oid)
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT 'ALTER TABLE ' || repack.oid2text($1) ||
|
||||
' ENABLE ALWAYS TRIGGER z_repack_trigger';
|
||||
' ENABLE ALWAYS TRIGGER a_repack_trigger';
|
||||
$$
|
||||
LANGUAGE sql STABLE STRICT;
|
||||
|
||||
@ -223,8 +223,8 @@ LANGUAGE C VOLATILE STRICT SECURITY DEFINER;
|
||||
CREATE FUNCTION repack.conflicted_triggers(oid) RETURNS SETOF name AS
|
||||
$$
|
||||
SELECT tgname FROM pg_trigger
|
||||
WHERE tgrelid = $1 AND tgname >= 'z_repack_trigger'
|
||||
AND (tgtype & 2) = 2 -- BEFORE trigger
|
||||
WHERE tgrelid = $1 AND tgname <= 'a_repack_trigger'
|
||||
AND (tgtype & 2) = 0 -- AFTER trigger
|
||||
ORDER BY tgname;
|
||||
$$
|
||||
LANGUAGE sql STABLE STRICT;
|
||||
|
@ -151,7 +151,7 @@ repack_trigger(PG_FUNCTION_ARGS)
|
||||
|
||||
/* make sure it's called as a trigger at all */
|
||||
if (!CALLED_AS_TRIGGER(fcinfo) ||
|
||||
!TRIGGER_FIRED_BEFORE(trigdata->tg_event) ||
|
||||
!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
|
||||
!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event) ||
|
||||
trigdata->tg_trigger->tgnargs != 1)
|
||||
elog(ERROR, "repack_trigger: invalid trigger call");
|
||||
@ -921,7 +921,7 @@ repack_swap(PG_FUNCTION_ARGS)
|
||||
/* drop repack trigger */
|
||||
execute_with_format(
|
||||
SPI_OK_UTILITY,
|
||||
"DROP TRIGGER IF EXISTS z_repack_trigger ON %s.%s CASCADE",
|
||||
"DROP TRIGGER IF EXISTS a_repack_trigger ON %s.%s CASCADE",
|
||||
nspname, relname);
|
||||
|
||||
SPI_finish();
|
||||
@ -962,7 +962,7 @@ repack_drop(PG_FUNCTION_ARGS)
|
||||
* To prevent concurrent lockers of the repack target table from causing
|
||||
* deadlocks, take an exclusive lock on it. Consider that the following
|
||||
* commands take exclusive lock on tables log_xxx and the target table
|
||||
* itself when deleting the z_repack_trigger on it, while concurrent
|
||||
* itself when deleting the a_repack_trigger on it, while concurrent
|
||||
* updaters require row exclusive lock on the target table and in
|
||||
* addition, on the log_xxx table, because of the trigger.
|
||||
*
|
||||
@ -1011,7 +1011,7 @@ repack_drop(PG_FUNCTION_ARGS)
|
||||
{
|
||||
execute_with_format(
|
||||
SPI_OK_UTILITY,
|
||||
"DROP TRIGGER IF EXISTS z_repack_trigger ON %s.%s CASCADE",
|
||||
"DROP TRIGGER IF EXISTS a_repack_trigger ON %s.%s CASCADE",
|
||||
nspname, relname);
|
||||
--numobj;
|
||||
}
|
||||
|
Reference in New Issue
Block a user