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:
parent
e1056c003c
commit
d83ee3d6a0
@ -186,8 +186,8 @@ typedef struct repack_table
|
||||
Oid ckid; /* target: CK OID */
|
||||
const char *create_pktype; /* CREATE TYPE pk */
|
||||
const char *create_log; /* CREATE TABLE log */
|
||||
const char *create_trigger; /* CREATE TRIGGER z_repack_trigger */
|
||||
const char *enable_trigger; /* ALTER TABLE ENABLE ALWAYS TRIGGER z_repack_trigger */
|
||||
const char *create_trigger; /* CREATE TRIGGER a_repack_trigger */
|
||||
const char *enable_trigger; /* ALTER TABLE ENABLE ALWAYS TRIGGER a_repack_trigger */
|
||||
const char *create_table; /* CREATE TABLE table AS SELECT */
|
||||
const char *drop_columns; /* ALTER TABLE DROP COLUMNs */
|
||||
const char *delete_log; /* DELETE FROM log */
|
||||
@ -1024,7 +1024,7 @@ repack_one_table(repack_table *table, const char *orderby)
|
||||
const char *appname = getenv("PGAPPNAME");
|
||||
|
||||
/* Keep track of whether we have gotten through setup to install
|
||||
* the z_repack_trigger, log table, etc. ourselves. We don't want to
|
||||
* the a_repack_trigger, log table, etc. ourselves. We don't want to
|
||||
* go through repack_cleanup() if we didn't actually set up the
|
||||
* trigger ourselves, lest we be cleaning up another pg_repack's mess,
|
||||
* or worse, interfering with a still-running pg_repack.
|
||||
@ -1126,13 +1126,13 @@ repack_one_table(repack_table *table, const char *orderby)
|
||||
|
||||
|
||||
/*
|
||||
* Check z_repack_trigger is the trigger executed last so that
|
||||
* other before triggers cannot modify triggered tuples.
|
||||
* Check a_repack_trigger is the after trigger executed first
|
||||
* so that other before triggers cannot modify triggered tuples.
|
||||
*/
|
||||
res = execute("SELECT repack.conflicted_triggers($1)", 1, params);
|
||||
if (PQntuples(res) > 0)
|
||||
{
|
||||
if (0 == strcmp("z_repack_trigger", PQgetvalue(res, 0, 0)))
|
||||
if (0 == strcmp("a_repack_trigger", PQgetvalue(res, 0, 0)))
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode(E_PG_COMMAND),
|
||||
@ -1153,10 +1153,10 @@ repack_one_table(repack_table *table, const char *orderby)
|
||||
errmsg("trigger \"%s\" conflicting on table \"%s\"",
|
||||
PQgetvalue(res, 0, 0), table->target_name),
|
||||
errdetail(
|
||||
"The trigger \"z_repack_trigger\" must be the last of the"
|
||||
" BEFORE triggers to fire on the table (triggers fire in"
|
||||
"The trigger \"a_repack_trigger\" must be the first of the"
|
||||
" AFTER triggers to fire on the table (triggers fire in"
|
||||
" alphabetical order). Please rename the trigger so that"
|
||||
" it sorts before \"z_repack_trigger\": you can use"
|
||||
" it sorts after \"a_repack_trigger\": you can use"
|
||||
" \"ALTER TRIGGER %s ON %s RENAME TO newname\".",
|
||||
PQgetvalue(res, 0, 0), table->target_name)));
|
||||
}
|
||||
@ -1232,7 +1232,7 @@ repack_one_table(repack_table *table, const char *orderby)
|
||||
*/
|
||||
command("COMMIT", 0, NULL);
|
||||
|
||||
/* The main connection has now committed its z_repack_trigger,
|
||||
/* The main connection has now committed its a_repack_trigger,
|
||||
* log table, and temp. table. If any error occurs from this point
|
||||
* on and we bail out, we should try to clean those up.
|
||||
*/
|
||||
|
@ -362,7 +362,7 @@ ERROR: query failed: ERROR: column "col" does not exist
|
||||
|
||||
Specify existing columns.
|
||||
|
||||
WARNING: the table "tbl" already has a trigger called z_repack_trigger
|
||||
WARNING: the table "tbl" already has a trigger called a_repack_trigger
|
||||
The trigger was probably installed during a previous attempt to run
|
||||
pg_repack on the table which was interrupted and for some reason failed
|
||||
to clean up the temporary objects.
|
||||
@ -371,14 +371,14 @@ WARNING: the table "tbl" already has a trigger called z_repack_trigger
|
||||
extension: see the installation_ section for the details.
|
||||
|
||||
WARNING: trigger "trg" conflicting on table "tbl"
|
||||
The target table has a trigger whose name follows ``z_repack_trigger``
|
||||
The target table has a trigger whose name follows ``a_repack_trigger``
|
||||
in alphabetical order.
|
||||
|
||||
The ``z_repack_trigger`` should be the last BEFORE trigger to fire.
|
||||
The ``a_repack_trigger`` should be the first AFTER trigger to fire.
|
||||
Please rename your trigger so that it sorts alphabetically before
|
||||
pg_repack's one; you can use::
|
||||
|
||||
ALTER TRIGGER zzz_my_trigger ON sometable RENAME TO yyy_my_trigger;
|
||||
ALTER TRIGGER aaa_my_trigger ON sometable RENAME TO bbb_my_trigger;
|
||||
|
||||
ERROR: Another pg_repack command may be running on the table. Please try again
|
||||
later.
|
||||
|
@ -651,7 +651,7 @@ ERROR: query failed: ERROR: column "col" does not exist
|
||||
対象のテーブルが ``--order-by`` オプションで指定したカラムを持っていない場合に表示されます。
|
||||
存在しているカラムを指定してください。
|
||||
|
||||
.. WARNING: the table "tbl" already has a trigger called z_repack_trigger
|
||||
.. WARNING: the table "tbl" already has a trigger called a_repack_trigger
|
||||
The trigger was probably installed during a previous attempt to run
|
||||
pg_repack on the table which was interrupted and for some reason failed
|
||||
to clean up the temporary objects.
|
||||
@ -661,31 +661,31 @@ ERROR: query failed: ERROR: column "col" does not exist
|
||||
|
||||
.. class:: diag
|
||||
|
||||
WARNING: the table "tbl" already has a trigger called z_repack_trigger
|
||||
WARNING: the table "tbl" already has a trigger called a_repack_trigger
|
||||
以前に実行したが何らかの理由で中断したか、あるいは失敗したpg_repackコマンドにより、
|
||||
対象テーブルにpg_repackが利用するトリガが残存している場合に表示されます。
|
||||
pg_repackを一度削除して、再度登録することで、こうした一時オブジェクトを削除できます。
|
||||
`インストール`_ を参照してください。
|
||||
|
||||
.. WARNING: trigger "trg" conflicting on table "tbl"
|
||||
The target table has a trigger whose name follows ``z_repack_trigger``
|
||||
The target table has a trigger whose name follows ``a_repack_trigger``
|
||||
in alphabetical order.
|
||||
|
||||
The ``z_repack_trigger`` should be the last BEFORE trigger to fire.
|
||||
The ``a_repack_trigger`` should be the first AFTER trigger to fire.
|
||||
Please rename your trigger so that it sorts alphabetically before
|
||||
pg_repack's one; you can use::
|
||||
|
||||
ALTER TRIGGER zzz_my_trigger ON sometable RENAME TO yyy_my_trigger;
|
||||
ALTER TRIGGER aaa_my_trigger ON sometable RENAME TO bbb_my_trigger;
|
||||
|
||||
.. class:: diag
|
||||
|
||||
WARNING: trigger "trg" conflicting on table "tbl"
|
||||
対象のテーブルが、pg_repackが利用する ``z_repack_trigger`` という名前のトリガ
|
||||
よりもアルファベット順で後ろになるような名前のトリガを持っている場合に表示されます。
|
||||
``z_repack_trigger`` トリガは最後に実行されるBEFOREトリガになる必要があります。
|
||||
対象のテーブルが、pg_repackが利用する ``a_repack_trigger`` という名前のトリガ
|
||||
よりもアルファベット順で前になるような名前のトリガを持っている場合に表示されます。
|
||||
``a_repack_trigger`` トリガは最初に実行されるAFTERトリガになる必要があります。
|
||||
該当のトリガ名称を変更してください。::
|
||||
|
||||
ALTER TRIGGER zzz_my_trigger ON sometable RENAME TO yyy_my_trigger;
|
||||
ALTER TRIGGER aaa_my_trigger ON sometable RENAME TO bbb_my_trigger;
|
||||
|
||||
.. ERROR: Another pg_repack command may be running on the table. Please try again
|
||||
later.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -338,23 +338,23 @@ CREATE FUNCTION trgtest() RETURNS trigger AS
|
||||
$$BEGIN RETURN NEW; END$$
|
||||
LANGUAGE plpgsql;
|
||||
CREATE TABLE trg1 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_triggeq BEFORE UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_trigges AFTER UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg1
|
||||
INFO: repacking table "trg1"
|
||||
CREATE TABLE trg2 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_trigger BEFORE UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_trigger AFTER UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg2
|
||||
INFO: repacking table "trg2"
|
||||
WARNING: the table "trg2" already has a trigger called "z_repack_trigger"
|
||||
WARNING: the table "trg2" already has a trigger called "a_repack_trigger"
|
||||
DETAIL: The trigger was probably installed during a previous attempt to run pg_repack on the table which was interrupted and for some reason failed to clean up the temporary objects. Please drop the trigger or drop and recreate the pg_repack extension altogether to remove all the temporary objects left over.
|
||||
CREATE TABLE trg3 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_trigges BEFORE UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_triggeq AFTER UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg3
|
||||
INFO: repacking table "trg3"
|
||||
WARNING: trigger "z_repack_trigges" conflicting on table "trg3"
|
||||
DETAIL: The trigger "z_repack_trigger" must be the last of the BEFORE triggers to fire on the table (triggers fire in alphabetical order). Please rename the trigger so that it sorts before "z_repack_trigger": you can use "ALTER TRIGGER z_repack_trigges ON trg3 RENAME TO newname".
|
||||
WARNING: trigger "a_repack_triggeq" conflicting on table "trg3"
|
||||
DETAIL: The trigger "a_repack_trigger" must be the first of the AFTER triggers to fire on the table (triggers fire in alphabetical order). Please rename the trigger so that it sorts after "a_repack_trigger": you can use "ALTER TRIGGER a_repack_triggeq ON trg3 RENAME TO newname".
|
||||
CREATE TABLE trg4 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER zzzzzz AFTER UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a BEFORE UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg4
|
||||
INFO: repacking table "trg4"
|
||||
--
|
||||
|
@ -197,16 +197,16 @@ CREATE FUNCTION trgtest() RETURNS trigger AS
|
||||
$$BEGIN RETURN NEW; END$$
|
||||
LANGUAGE plpgsql;
|
||||
CREATE TABLE trg1 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_triggeq BEFORE UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_trigges AFTER UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg1
|
||||
CREATE TABLE trg2 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_trigger BEFORE UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_trigger AFTER UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg2
|
||||
CREATE TABLE trg3 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER z_repack_trigges BEFORE UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a_repack_triggeq AFTER UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg3
|
||||
CREATE TABLE trg4 (id integer PRIMARY KEY);
|
||||
CREATE TRIGGER zzzzzz AFTER UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
CREATE TRIGGER a BEFORE UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest();
|
||||
\! pg_repack --dbname=contrib_regression --table=trg4
|
||||
|
||||
--
|
||||
|
Loading…
x
Reference in New Issue
Block a user