Skip to content

Commit 272adf4

Browse files
committed
Disallow CREATE/DROP SUBSCRIPTION in transaction block
Disallow CREATE SUBSCRIPTION and DROP SUBSCRIPTION in a transaction block when the replication slot is to be created or dropped, since that cannot be rolled back. based on patch by Masahiko Sawada <sawada.mshk@gmail.com>
1 parent 3473027 commit 272adf4

File tree

7 files changed

+66
-15
lines changed

7 files changed

+66
-15
lines changed

doc/src/sgml/ref/create_subscription.sgml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ CREATE SUBSCRIPTION <replaceable class="PARAMETER">subscription_name</replaceabl
5151
subscription at the commit of the transaction where this command is run.
5252
</para>
5353

54+
<para>
55+
<command>CREATE SUBSCRIPTION</command> cannot be executed inside a
56+
transaction block when <literal>CREATE SLOT</literal> is specified.
57+
</para>
58+
5459
<para>
5560
Additional info about subscriptions and logical replication as a whole
5661
can is available at <xref linkend="logical-replication-subscription"> and

doc/src/sgml/ref/drop_subscription.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ DROP SUBSCRIPTION [ IF EXISTS ] <replaceable class="parameter">name</replaceable
3838
</para>
3939

4040
<para>
41-
The replication worker associated with the subscription will not stop until
42-
after the transaction that issued this command has committed.
41+
<command>DROP SUBSCRIPTION</command> cannot be executed inside a
42+
transaction block when <literal>DROP SLOT</literal> is specified.
4343
</para>
4444
</refsect1>
4545

src/backend/commands/subscriptioncmds.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "access/heapam.h"
2020
#include "access/htup_details.h"
21+
#include "access/xact.h"
2122

2223
#include "catalog/indexing.h"
2324
#include "catalog/objectaccess.h"
@@ -204,7 +205,7 @@ publicationListToArray(List *publist)
204205
* Create new subscription.
205206
*/
206207
ObjectAddress
207-
CreateSubscription(CreateSubscriptionStmt *stmt)
208+
CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
208209
{
209210
Relation rel;
210211
ObjectAddress myself;
@@ -221,6 +222,23 @@ CreateSubscription(CreateSubscriptionStmt *stmt)
221222
bool create_slot;
222223
List *publications;
223224

225+
/*
226+
* Parse and check options.
227+
* Connection and publication should not be specified here.
228+
*/
229+
parse_subscription_options(stmt->options, NULL, NULL,
230+
&enabled_given, &enabled,
231+
&create_slot, &slotname);
232+
233+
/*
234+
* Since creating a replication slot is not transactional, rolling back
235+
* the transaction leaves the created replication slot. So we cannot run
236+
* CREATE SUBSCRIPTION inside a transaction block if creating a
237+
* replication slot.
238+
*/
239+
if (create_slot)
240+
PreventTransactionChain(isTopLevel, "CREATE SUBSCRIPTION ... CREATE SLOT");
241+
224242
if (!superuser())
225243
ereport(ERROR,
226244
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -239,13 +257,6 @@ CreateSubscription(CreateSubscriptionStmt *stmt)
239257
stmt->subname)));
240258
}
241259

242-
/*
243-
* Parse and check options.
244-
* Connection and publication should not be specified here.
245-
*/
246-
parse_subscription_options(stmt->options, NULL, NULL,
247-
&enabled_given, &enabled,
248-
&create_slot, &slotname);
249260
if (slotname == NULL)
250261
slotname = stmt->subname;
251262

@@ -424,7 +435,7 @@ AlterSubscription(AlterSubscriptionStmt *stmt)
424435
* Drop a subscription
425436
*/
426437
void
427-
DropSubscription(DropSubscriptionStmt *stmt)
438+
DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
428439
{
429440
Relation rel;
430441
ObjectAddress myself;
@@ -441,6 +452,15 @@ DropSubscription(DropSubscriptionStmt *stmt)
441452
WalReceiverConn *wrconn = NULL;
442453
StringInfoData cmd;
443454

455+
/*
456+
* Since dropping a replication slot is not transactional, the replication
457+
* slot stays dropped even if the transaction rolls back. So we cannot
458+
* run DROP SUBSCRIPTION inside a transaction block if dropping the
459+
* replication slot.
460+
*/
461+
if (stmt->drop_slot)
462+
PreventTransactionChain(isTopLevel, "DROP SUBSCRIPTION ... DROP SLOT");
463+
444464
rel = heap_open(SubscriptionRelationId, RowExclusiveLock);
445465

446466
tup = SearchSysCache2(SUBSCRIPTIONNAME, MyDatabaseId,

src/backend/tcop/utility.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,15 +1609,16 @@ ProcessUtilitySlow(ParseState *pstate,
16091609
break;
16101610

16111611
case T_CreateSubscriptionStmt:
1612-
address = CreateSubscription((CreateSubscriptionStmt *) parsetree);
1612+
address = CreateSubscription((CreateSubscriptionStmt *) parsetree,
1613+
isTopLevel);
16131614
break;
16141615

16151616
case T_AlterSubscriptionStmt:
16161617
address = AlterSubscription((AlterSubscriptionStmt *) parsetree);
16171618
break;
16181619

16191620
case T_DropSubscriptionStmt:
1620-
DropSubscription((DropSubscriptionStmt *) parsetree);
1621+
DropSubscription((DropSubscriptionStmt *) parsetree, isTopLevel);
16211622
/* no commands stashed for DROP */
16221623
commandCollected = true;
16231624
break;

src/include/commands/subscriptioncmds.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
#include "catalog/objectaddress.h"
1919
#include "nodes/parsenodes.h"
2020

21-
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt);
21+
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt,
22+
bool isTopLevel);
2223
extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt);
23-
extern void DropSubscription(DropSubscriptionStmt *stmt);
24+
extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
2425

2526
extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
2627
extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId);

src/test/regress/expected/subscription.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ ERROR: syntax error at or near "PUBLICATION"
1414
LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo;
1515
^
1616
set client_min_messages to error;
17+
-- fail - cannot do CREATE SUBSCRIPTION CREATE SLOT inside transaction block
18+
BEGIN;
19+
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (CREATE SLOT);
20+
ERROR: CREATE SUBSCRIPTION ... CREATE SLOT cannot run inside a transaction block
21+
COMMIT;
1722
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
1823
ERROR: invalid connection string syntax: missing "=" after "testconn" in connection info string
1924

@@ -69,6 +74,13 @@ ALTER SUBSCRIPTION testsub RENAME TO testsub_foo;
6974
testsub_foo | regress_subscription_user | f | {testpub,testpub1}
7075
(1 row)
7176

77+
-- fail - cannot do DROP SUBSCRIPTION DROP SLOT inside transaction block
78+
BEGIN;
79+
DROP SUBSCRIPTION testsub DROP SLOT;
80+
ERROR: DROP SUBSCRIPTION ... DROP SLOT cannot run inside a transaction block
81+
COMMIT;
82+
BEGIN;
7283
DROP SUBSCRIPTION testsub_foo NODROP SLOT;
84+
COMMIT;
7385
RESET SESSION AUTHORIZATION;
7486
DROP ROLE regress_subscription_user;

src/test/regress/sql/subscription.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ CREATE SUBSCRIPTION testsub CONNECTION 'foo';
1212
CREATE SUBSCRIPTION testsub PUBLICATION foo;
1313

1414
set client_min_messages to error;
15+
-- fail - cannot do CREATE SUBSCRIPTION CREATE SLOT inside transaction block
16+
BEGIN;
17+
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (CREATE SLOT);
18+
COMMIT;
19+
1520
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
1621
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (DISABLED, NOCREATE SLOT);
1722
reset client_min_messages;
@@ -42,7 +47,14 @@ ALTER SUBSCRIPTION testsub RENAME TO testsub_foo;
4247

4348
\dRs
4449

50+
-- fail - cannot do DROP SUBSCRIPTION DROP SLOT inside transaction block
51+
BEGIN;
52+
DROP SUBSCRIPTION testsub DROP SLOT;
53+
COMMIT;
54+
55+
BEGIN;
4556
DROP SUBSCRIPTION testsub_foo NODROP SLOT;
57+
COMMIT;
4658

4759
RESET SESSION AUTHORIZATION;
4860
DROP ROLE regress_subscription_user;

0 commit comments

Comments
 (0)