From d83ee3d6a06f34f6c9942916788e018242325cfd Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Thu, 19 Jan 2017 13:47:18 +0900 Subject: [PATCH 1/2] 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. --- bin/pg_repack.c | 20 ++++++++++---------- doc/pg_repack.rst | 8 ++++---- doc/pg_repack_jp.rst | 18 +++++++++--------- lib/pg_repack.sql.in | 10 +++++----- lib/repack.c | 8 ++++---- regress/expected/repack.out | 14 +++++++------- regress/sql/repack.sql | 8 ++++---- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/bin/pg_repack.c b/bin/pg_repack.c index 8ccb1ae..5ca0853 100644 --- a/bin/pg_repack.c +++ b/bin/pg_repack.c @@ -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. */ diff --git a/doc/pg_repack.rst b/doc/pg_repack.rst index c51e1d2..0b12e7a 100644 --- a/doc/pg_repack.rst +++ b/doc/pg_repack.rst @@ -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. diff --git a/doc/pg_repack_jp.rst b/doc/pg_repack_jp.rst index 02b9bd2..cdfcc00 100644 --- a/doc/pg_repack_jp.rst +++ b/doc/pg_repack_jp.rst @@ -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. diff --git a/lib/pg_repack.sql.in b/lib/pg_repack.sql.in index 72942d2..1d68647 100644 --- a/lib/pg_repack.sql.in +++ b/lib/pg_repack.sql.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; diff --git a/lib/repack.c b/lib/repack.c index a79449c..ed10bbb 100644 --- a/lib/repack.c +++ b/lib/repack.c @@ -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; } diff --git a/regress/expected/repack.out b/regress/expected/repack.out index 4c5635b..1adab12 100644 --- a/regress/expected/repack.out +++ b/regress/expected/repack.out @@ -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" -- diff --git a/regress/sql/repack.sql b/regress/sql/repack.sql index 03e72cd..37f291c 100644 --- a/regress/sql/repack.sql +++ b/regress/sql/repack.sql @@ -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 -- From 375f03c0c37d9c000e3d9adb2d03273a17083eb9 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 24 Jan 2017 14:09:05 +0900 Subject: [PATCH 2/2] Change trigger name from a_repack_trigger to repack_trigger. In AFTER trigger context, since triggered tuple is not changed by any other triggers we can call it just repack_trigger. --- bin/pg_repack.c | 47 +++++++++++++------------------------ doc/pg_repack.rst | 12 +--------- doc/pg_repack_jp.rst | 22 +++-------------- lib/pg_repack.sql.in | 7 +++--- lib/repack.c | 6 ++--- regress/expected/repack.out | 14 ++++------- regress/sql/repack.sql | 9 +++---- 7 files changed, 33 insertions(+), 84 deletions(-) diff --git a/bin/pg_repack.c b/bin/pg_repack.c index 5ca0853..d4aa226 100644 --- a/bin/pg_repack.c +++ b/bin/pg_repack.c @@ -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 a_repack_trigger */ - const char *enable_trigger; /* ALTER TABLE ENABLE ALWAYS TRIGGER a_repack_trigger */ + const char *create_trigger; /* CREATE TRIGGER repack_trigger */ + const char *enable_trigger; /* ALTER TABLE ENABLE ALWAYS TRIGGER 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 a_repack_trigger, log table, etc. ourselves. We don't want to + * the 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,43 +1126,28 @@ repack_one_table(repack_table *table, const char *orderby) /* - * Check a_repack_trigger is the after trigger executed first - * so that other before triggers cannot modify triggered tuples. + * Check if repack_trigger is not conflict with existing trigger. We can + * find it out later but we check it in advance and go to cleanup if needed. + * In AFTER trigger context, since triggered tuple is not changed by other + * trigger we don't care about the fire order. */ res = execute("SELECT repack.conflicted_triggers($1)", 1, params); if (PQntuples(res) > 0) { - if (0 == strcmp("a_repack_trigger", PQgetvalue(res, 0, 0))) - { - ereport(WARNING, + ereport(WARNING, (errcode(E_PG_COMMAND), errmsg("the table \"%s\" already has a trigger called \"%s\"", - table->target_name, PQgetvalue(res, 0, 0)), + table->target_name, "repack_trigger"), errdetail( - "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" + "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."))); - } - else - { - ereport(WARNING, - (errcode(E_PG_COMMAND), - errmsg("trigger \"%s\" conflicting on table \"%s\"", - PQgetvalue(res, 0, 0), table->target_name), - errdetail( - "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 %s ON %s RENAME TO newname\".", - PQgetvalue(res, 0, 0), table->target_name))); - } - + " to remove all the temporary objects left over."))); goto cleanup; } + CLEARPGRES(res); command(table->create_pktype, 0, NULL); @@ -1232,7 +1217,7 @@ repack_one_table(repack_table *table, const char *orderby) */ command("COMMIT", 0, NULL); - /* The main connection has now committed its a_repack_trigger, + /* The main connection has now committed its 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. */ diff --git a/doc/pg_repack.rst b/doc/pg_repack.rst index 0b12e7a..1600ce0 100644 --- a/doc/pg_repack.rst +++ b/doc/pg_repack.rst @@ -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 a_repack_trigger +WARNING: the table "tbl" already has a trigger called 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. @@ -370,16 +370,6 @@ WARNING: the table "tbl" already has a trigger called a_repack_trigger You can remove all the temporary objects by dropping and re-creating the extension: see the installation_ section for the details. -WARNING: trigger "trg" conflicting on table "tbl" - The target table has a trigger whose name follows ``a_repack_trigger`` - in alphabetical order. - - 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 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. diff --git a/doc/pg_repack_jp.rst b/doc/pg_repack_jp.rst index cdfcc00..7332d9a 100644 --- a/doc/pg_repack_jp.rst +++ b/doc/pg_repack_jp.rst @@ -661,17 +661,17 @@ ERROR: query failed: ERROR: column "col" does not exist .. class:: diag -WARNING: the table "tbl" already has a trigger called a_repack_trigger +WARNING: the table "tbl" already has a trigger called repack_trigger 以前に実行したが何らかの理由で中断したか、あるいは失敗したpg_repackコマンドにより、 対象テーブルにpg_repackが利用するトリガが残存している場合に表示されます。 pg_repackを一度削除して、再度登録することで、こうした一時オブジェクトを削除できます。 `インストール`_ を参照してください。 .. WARNING: trigger "trg" conflicting on table "tbl" - The target table has a trigger whose name follows ``a_repack_trigger`` + The target table has a trigger whose name follows ``repack_trigger`` in alphabetical order. - The ``a_repack_trigger`` should be the first AFTER trigger to fire. + The ``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:: @@ -679,22 +679,6 @@ WARNING: the table "tbl" already has a trigger called a_repack_trigger .. class:: diag -WARNING: trigger "trg" conflicting on table "tbl" - 対象のテーブルが、pg_repackが利用する ``a_repack_trigger`` という名前のトリガ - よりもアルファベット順で前になるような名前のトリガを持っている場合に表示されます。 - ``a_repack_trigger`` トリガは最初に実行されるAFTERトリガになる必要があります。 - 該当のトリガ名称を変更してください。:: - - 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. - - There is a chance of deadlock when two concurrent pg_repack commands are run - on the same table. So, try to run the command after some time. - -.. class:: diag - ERROR: Another pg_repack command may be running on the table. Please try again 同じテーブルに複数のpg_repackが同時に実行されている場合に表示されます。 これはデッドロックを引き起こす可能性があるため、片方のpg_repackが終了するのを diff --git a/lib/pg_repack.sql.in b/lib/pg_repack.sql.in index 1d68647..d294548 100644 --- a/lib/pg_repack.sql.in +++ b/lib/pg_repack.sql.in @@ -68,7 +68,7 @@ LANGUAGE sql STABLE STRICT; CREATE FUNCTION repack.get_create_trigger(relid oid, pkid oid) RETURNS text AS $$ - SELECT 'CREATE TRIGGER a_repack_trigger' || + SELECT 'CREATE TRIGGER 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(' || @@ -82,7 +82,7 @@ CREATE FUNCTION repack.get_enable_trigger(relid oid) RETURNS text AS $$ SELECT 'ALTER TABLE ' || repack.oid2text($1) || - ' ENABLE ALWAYS TRIGGER a_repack_trigger'; + ' ENABLE ALWAYS TRIGGER repack_trigger'; $$ LANGUAGE sql STABLE STRICT; @@ -223,8 +223,7 @@ 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 <= 'a_repack_trigger' - AND (tgtype & 2) = 0 -- AFTER trigger + WHERE tgrelid = $1 AND tgname = 'repack_trigger' ORDER BY tgname; $$ LANGUAGE sql STABLE STRICT; diff --git a/lib/repack.c b/lib/repack.c index ed10bbb..e7e4539 100644 --- a/lib/repack.c +++ b/lib/repack.c @@ -921,7 +921,7 @@ repack_swap(PG_FUNCTION_ARGS) /* drop repack trigger */ execute_with_format( SPI_OK_UTILITY, - "DROP TRIGGER IF EXISTS a_repack_trigger ON %s.%s CASCADE", + "DROP TRIGGER IF EXISTS 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 a_repack_trigger on it, while concurrent + * itself when deleting the 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 a_repack_trigger ON %s.%s CASCADE", + "DROP TRIGGER IF EXISTS repack_trigger ON %s.%s CASCADE", nspname, relname); --numobj; } diff --git a/regress/expected/repack.out b/regress/expected/repack.out index 1adab12..b1ba8c2 100644 --- a/regress/expected/repack.out +++ b/regress/expected/repack.out @@ -338,25 +338,19 @@ CREATE FUNCTION trgtest() RETURNS trigger AS $$BEGIN RETURN NEW; END$$ LANGUAGE plpgsql; CREATE TABLE trg1 (id integer PRIMARY KEY); -CREATE TRIGGER a_repack_trigges AFTER UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER repack_trigger_1 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 a_repack_trigger AFTER UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER 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 "a_repack_trigger" +WARNING: the table "trg2" already has a trigger called "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 a_repack_triggeq AFTER UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER repack_trigger_1 BEFORE UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest(); \! pg_repack --dbname=contrib_regression --table=trg3 INFO: repacking table "trg3" -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 a BEFORE UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest(); -\! pg_repack --dbname=contrib_regression --table=trg4 -INFO: repacking table "trg4" -- -- Dry run -- diff --git a/regress/sql/repack.sql b/regress/sql/repack.sql index 37f291c..7f9098d 100644 --- a/regress/sql/repack.sql +++ b/regress/sql/repack.sql @@ -197,17 +197,14 @@ CREATE FUNCTION trgtest() RETURNS trigger AS $$BEGIN RETURN NEW; END$$ LANGUAGE plpgsql; CREATE TABLE trg1 (id integer PRIMARY KEY); -CREATE TRIGGER a_repack_trigges AFTER UPDATE ON trg1 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER repack_trigger_1 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 a_repack_trigger AFTER UPDATE ON trg2 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER 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 a_repack_triggeq AFTER UPDATE ON trg3 FOR EACH ROW EXECUTE PROCEDURE trgtest(); +CREATE TRIGGER repack_trigger_1 BEFORE 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 a BEFORE UPDATE ON trg4 FOR EACH ROW EXECUTE PROCEDURE trgtest(); -\! pg_repack --dbname=contrib_regression --table=trg4 -- -- Dry run