|
|
@ -94,7 +94,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, |
|
|
|
*synchronous_commit = NULL; |
|
|
|
*synchronous_commit = NULL; |
|
|
|
|
|
|
|
|
|
|
|
/* Parse options */ |
|
|
|
/* Parse options */ |
|
|
|
foreach (lc, options) |
|
|
|
foreach(lc, options) |
|
|
|
{ |
|
|
|
{ |
|
|
|
DefElem *defel = (DefElem *) lfirst(lc); |
|
|
|
DefElem *defel = (DefElem *) lfirst(lc); |
|
|
|
|
|
|
|
|
|
|
@ -200,8 +200,8 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Do additional checking for disallowed combination when |
|
|
|
* Do additional checking for disallowed combination when slot_name = NONE |
|
|
|
* slot_name = NONE was used. |
|
|
|
* was used. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (slot_name && *slot_name_given && !*slot_name) |
|
|
|
if (slot_name && *slot_name_given && !*slot_name) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -367,7 +367,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
values[Anum_pg_subscription_subsynccommit - 1] = |
|
|
|
values[Anum_pg_subscription_subsynccommit - 1] = |
|
|
|
CStringGetTextDatum(synchronous_commit); |
|
|
|
CStringGetTextDatum(synchronous_commit); |
|
|
|
values[Anum_pg_subscription_subpublications - 1] = |
|
|
|
values[Anum_pg_subscription_subpublications - 1] = |
|
|
|
publicationListToArray(publications); |
|
|
|
publicationListToArray(publications); |
|
|
|
|
|
|
|
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); |
|
|
|
tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); |
|
|
|
|
|
|
|
|
|
|
@ -386,12 +386,12 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (connect) |
|
|
|
if (connect) |
|
|
|
{ |
|
|
|
{ |
|
|
|
XLogRecPtr lsn; |
|
|
|
XLogRecPtr lsn; |
|
|
|
char *err; |
|
|
|
char *err; |
|
|
|
WalReceiverConn *wrconn; |
|
|
|
WalReceiverConn *wrconn; |
|
|
|
List *tables; |
|
|
|
List *tables; |
|
|
|
ListCell *lc; |
|
|
|
ListCell *lc; |
|
|
|
char table_state; |
|
|
|
char table_state; |
|
|
|
|
|
|
|
|
|
|
|
/* Try to connect to the publisher. */ |
|
|
|
/* Try to connect to the publisher. */ |
|
|
|
wrconn = walrcv_connect(conninfo, true, stmt->subname, &err); |
|
|
|
wrconn = walrcv_connect(conninfo, true, stmt->subname, &err); |
|
|
@ -412,7 +412,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
* info. |
|
|
|
* info. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
tables = fetch_table_list(wrconn, publications); |
|
|
|
tables = fetch_table_list(wrconn, publications); |
|
|
|
foreach (lc, tables) |
|
|
|
foreach(lc, tables) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RangeVar *rv = (RangeVar *) lfirst(lc); |
|
|
|
RangeVar *rv = (RangeVar *) lfirst(lc); |
|
|
|
Oid relid; |
|
|
|
Oid relid; |
|
|
@ -431,9 +431,9 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
(errmsg("synchronized table states"))); |
|
|
|
(errmsg("synchronized table states"))); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* If requested, create permanent slot for the subscription. |
|
|
|
* If requested, create permanent slot for the subscription. We |
|
|
|
* We won't use the initial snapshot for anything, so no need |
|
|
|
* won't use the initial snapshot for anything, so no need to |
|
|
|
* to export it. |
|
|
|
* export it. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (create_slot) |
|
|
|
if (create_slot) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -442,8 +442,8 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
walrcv_create_slot(wrconn, slotname, false, |
|
|
|
walrcv_create_slot(wrconn, slotname, false, |
|
|
|
CRS_NOEXPORT_SNAPSHOT, &lsn); |
|
|
|
CRS_NOEXPORT_SNAPSHOT, &lsn); |
|
|
|
ereport(NOTICE, |
|
|
|
ereport(NOTICE, |
|
|
|
(errmsg("created replication slot \"%s\" on publisher", |
|
|
|
(errmsg("created replication slot \"%s\" on publisher", |
|
|
|
slotname))); |
|
|
|
slotname))); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
PG_CATCH(); |
|
|
|
PG_CATCH(); |
|
|
@ -478,7 +478,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
static void |
|
|
|
static void |
|
|
|
AlterSubscription_refresh(Subscription *sub, bool copy_data) |
|
|
|
AlterSubscription_refresh(Subscription *sub, bool copy_data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *err; |
|
|
|
char *err; |
|
|
|
List *pubrel_names; |
|
|
|
List *pubrel_names; |
|
|
|
List *subrel_states; |
|
|
|
List *subrel_states; |
|
|
|
Oid *subrel_local_oids; |
|
|
|
Oid *subrel_local_oids; |
|
|
@ -505,31 +505,31 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data) |
|
|
|
subrel_states = GetSubscriptionRelations(sub->oid); |
|
|
|
subrel_states = GetSubscriptionRelations(sub->oid); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Build qsorted array of local table oids for faster lookup. |
|
|
|
* Build qsorted array of local table oids for faster lookup. This can |
|
|
|
* This can potentially contain all tables in the database so |
|
|
|
* potentially contain all tables in the database so speed of lookup is |
|
|
|
* speed of lookup is important. |
|
|
|
* important. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
subrel_local_oids = palloc(list_length(subrel_states) * sizeof(Oid)); |
|
|
|
subrel_local_oids = palloc(list_length(subrel_states) * sizeof(Oid)); |
|
|
|
off = 0; |
|
|
|
off = 0; |
|
|
|
foreach(lc, subrel_states) |
|
|
|
foreach(lc, subrel_states) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SubscriptionRelState *relstate = (SubscriptionRelState *) lfirst(lc); |
|
|
|
SubscriptionRelState *relstate = (SubscriptionRelState *) lfirst(lc); |
|
|
|
|
|
|
|
|
|
|
|
subrel_local_oids[off++] = relstate->relid; |
|
|
|
subrel_local_oids[off++] = relstate->relid; |
|
|
|
} |
|
|
|
} |
|
|
|
qsort(subrel_local_oids, list_length(subrel_states), |
|
|
|
qsort(subrel_local_oids, list_length(subrel_states), |
|
|
|
sizeof(Oid), oid_cmp); |
|
|
|
sizeof(Oid), oid_cmp); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Walk over the remote tables and try to match them to locally |
|
|
|
* Walk over the remote tables and try to match them to locally known |
|
|
|
* known tables. If the table is not known locally create a new state |
|
|
|
* tables. If the table is not known locally create a new state for it. |
|
|
|
* for it. |
|
|
|
|
|
|
|
* |
|
|
|
* |
|
|
|
* Also builds array of local oids of remote tables for the next step. |
|
|
|
* Also builds array of local oids of remote tables for the next step. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
off = 0; |
|
|
|
off = 0; |
|
|
|
pubrel_local_oids = palloc(list_length(pubrel_names) * sizeof(Oid)); |
|
|
|
pubrel_local_oids = palloc(list_length(pubrel_names) * sizeof(Oid)); |
|
|
|
|
|
|
|
|
|
|
|
foreach (lc, pubrel_names) |
|
|
|
foreach(lc, pubrel_names) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RangeVar *rv = (RangeVar *) lfirst(lc); |
|
|
|
RangeVar *rv = (RangeVar *) lfirst(lc); |
|
|
|
Oid relid; |
|
|
|
Oid relid; |
|
|
@ -546,7 +546,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data) |
|
|
|
list_length(subrel_states), sizeof(Oid), oid_cmp)) |
|
|
|
list_length(subrel_states), sizeof(Oid), oid_cmp)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SetSubscriptionRelState(sub->oid, relid, |
|
|
|
SetSubscriptionRelState(sub->oid, relid, |
|
|
|
copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY, |
|
|
|
copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY, |
|
|
|
InvalidXLogRecPtr); |
|
|
|
InvalidXLogRecPtr); |
|
|
|
ereport(NOTICE, |
|
|
|
ereport(NOTICE, |
|
|
|
(errmsg("added subscription for table %s.%s", |
|
|
|
(errmsg("added subscription for table %s.%s", |
|
|
@ -556,20 +556,20 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Next remove state for tables we should not care about anymore using |
|
|
|
* Next remove state for tables we should not care about anymore using the |
|
|
|
* the data we collected above |
|
|
|
* data we collected above |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
qsort(pubrel_local_oids, list_length(pubrel_names), |
|
|
|
qsort(pubrel_local_oids, list_length(pubrel_names), |
|
|
|
sizeof(Oid), oid_cmp); |
|
|
|
sizeof(Oid), oid_cmp); |
|
|
|
|
|
|
|
|
|
|
|
for (off = 0; off < list_length(subrel_states); off++) |
|
|
|
for (off = 0; off < list_length(subrel_states); off++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Oid relid = subrel_local_oids[off]; |
|
|
|
Oid relid = subrel_local_oids[off]; |
|
|
|
|
|
|
|
|
|
|
|
if (!bsearch(&relid, pubrel_local_oids, |
|
|
|
if (!bsearch(&relid, pubrel_local_oids, |
|
|
|
list_length(pubrel_names), sizeof(Oid), oid_cmp)) |
|
|
|
list_length(pubrel_names), sizeof(Oid), oid_cmp)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *namespace; |
|
|
|
char *namespace; |
|
|
|
|
|
|
|
|
|
|
|
RemoveSubscriptionRel(sub->oid, relid); |
|
|
|
RemoveSubscriptionRel(sub->oid, relid); |
|
|
|
|
|
|
|
|
|
|
@ -596,7 +596,7 @@ AlterSubscription(AlterSubscriptionStmt *stmt) |
|
|
|
HeapTuple tup; |
|
|
|
HeapTuple tup; |
|
|
|
Oid subid; |
|
|
|
Oid subid; |
|
|
|
bool update_tuple = false; |
|
|
|
bool update_tuple = false; |
|
|
|
Subscription *sub; |
|
|
|
Subscription *sub; |
|
|
|
|
|
|
|
|
|
|
|
rel = heap_open(SubscriptionRelationId, RowExclusiveLock); |
|
|
|
rel = heap_open(SubscriptionRelationId, RowExclusiveLock); |
|
|
|
|
|
|
|
|
|
|
@ -644,7 +644,7 @@ AlterSubscription(AlterSubscriptionStmt *stmt) |
|
|
|
|
|
|
|
|
|
|
|
if (slotname) |
|
|
|
if (slotname) |
|
|
|
values[Anum_pg_subscription_subslotname - 1] = |
|
|
|
values[Anum_pg_subscription_subslotname - 1] = |
|
|
|
DirectFunctionCall1(namein, CStringGetDatum(slotname)); |
|
|
|
DirectFunctionCall1(namein, CStringGetDatum(slotname)); |
|
|
|
else |
|
|
|
else |
|
|
|
nulls[Anum_pg_subscription_subslotname - 1] = true; |
|
|
|
nulls[Anum_pg_subscription_subslotname - 1] = true; |
|
|
|
replaces[Anum_pg_subscription_subslotname - 1] = true; |
|
|
|
replaces[Anum_pg_subscription_subslotname - 1] = true; |
|
|
@ -663,8 +663,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt) |
|
|
|
|
|
|
|
|
|
|
|
case ALTER_SUBSCRIPTION_ENABLED: |
|
|
|
case ALTER_SUBSCRIPTION_ENABLED: |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool enabled, |
|
|
|
bool enabled, |
|
|
|
enabled_given; |
|
|
|
enabled_given; |
|
|
|
|
|
|
|
|
|
|
|
parse_subscription_options(stmt->options, NULL, |
|
|
|
parse_subscription_options(stmt->options, NULL, |
|
|
|
&enabled_given, &enabled, NULL, |
|
|
|
&enabled_given, &enabled, NULL, |
|
|
@ -702,14 +702,14 @@ AlterSubscription(AlterSubscriptionStmt *stmt) |
|
|
|
case ALTER_SUBSCRIPTION_PUBLICATION: |
|
|
|
case ALTER_SUBSCRIPTION_PUBLICATION: |
|
|
|
case ALTER_SUBSCRIPTION_PUBLICATION_REFRESH: |
|
|
|
case ALTER_SUBSCRIPTION_PUBLICATION_REFRESH: |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool copy_data; |
|
|
|
bool copy_data; |
|
|
|
|
|
|
|
|
|
|
|
parse_subscription_options(stmt->options, NULL, NULL, NULL, |
|
|
|
parse_subscription_options(stmt->options, NULL, NULL, NULL, |
|
|
|
NULL, NULL, NULL, ©_data, |
|
|
|
NULL, NULL, NULL, ©_data, |
|
|
|
NULL); |
|
|
|
NULL); |
|
|
|
|
|
|
|
|
|
|
|
values[Anum_pg_subscription_subpublications - 1] = |
|
|
|
values[Anum_pg_subscription_subpublications - 1] = |
|
|
|
publicationListToArray(stmt->publication); |
|
|
|
publicationListToArray(stmt->publication); |
|
|
|
replaces[Anum_pg_subscription_subpublications - 1] = true; |
|
|
|
replaces[Anum_pg_subscription_subpublications - 1] = true; |
|
|
|
|
|
|
|
|
|
|
|
update_tuple = true; |
|
|
|
update_tuple = true; |
|
|
@ -733,7 +733,7 @@ AlterSubscription(AlterSubscriptionStmt *stmt) |
|
|
|
|
|
|
|
|
|
|
|
case ALTER_SUBSCRIPTION_REFRESH: |
|
|
|
case ALTER_SUBSCRIPTION_REFRESH: |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool copy_data; |
|
|
|
bool copy_data; |
|
|
|
|
|
|
|
|
|
|
|
if (!sub->enabled) |
|
|
|
if (!sub->enabled) |
|
|
|
ereport(ERROR, |
|
|
|
ereport(ERROR, |
|
|
@ -791,14 +791,13 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
char *slotname; |
|
|
|
char *slotname; |
|
|
|
char originname[NAMEDATALEN]; |
|
|
|
char originname[NAMEDATALEN]; |
|
|
|
char *err = NULL; |
|
|
|
char *err = NULL; |
|
|
|
RepOriginId originid; |
|
|
|
RepOriginId originid; |
|
|
|
WalReceiverConn *wrconn = NULL; |
|
|
|
WalReceiverConn *wrconn = NULL; |
|
|
|
StringInfoData cmd; |
|
|
|
StringInfoData cmd; |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Lock pg_subscription with AccessExclusiveLock to ensure |
|
|
|
* Lock pg_subscription with AccessExclusiveLock to ensure that the |
|
|
|
* that the launcher doesn't restart new worker during dropping |
|
|
|
* launcher doesn't restart new worker during dropping the subscription |
|
|
|
* the subscription |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
rel = heap_open(SubscriptionRelationId, AccessExclusiveLock); |
|
|
|
rel = heap_open(SubscriptionRelationId, AccessExclusiveLock); |
|
|
|
|
|
|
|
|
|
|
@ -833,8 +832,8 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
InvokeObjectDropHook(SubscriptionRelationId, subid, 0); |
|
|
|
InvokeObjectDropHook(SubscriptionRelationId, subid, 0); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Lock the subscription so nobody else can do anything with it |
|
|
|
* Lock the subscription so nobody else can do anything with it (including |
|
|
|
* (including the replication workers). |
|
|
|
* the replication workers). |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
LockSharedObject(SubscriptionRelationId, subid, 0, AccessExclusiveLock); |
|
|
|
LockSharedObject(SubscriptionRelationId, subid, 0, AccessExclusiveLock); |
|
|
|
|
|
|
|
|
|
|
@ -895,7 +894,10 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
if (originid != InvalidRepOriginId) |
|
|
|
if (originid != InvalidRepOriginId) |
|
|
|
replorigin_drop(originid); |
|
|
|
replorigin_drop(originid); |
|
|
|
|
|
|
|
|
|
|
|
/* If there is no slot associated with the subscription, we can finish here. */ |
|
|
|
/*
|
|
|
|
|
|
|
|
* If there is no slot associated with the subscription, we can finish |
|
|
|
|
|
|
|
* here. |
|
|
|
|
|
|
|
*/ |
|
|
|
if (!slotname) |
|
|
|
if (!slotname) |
|
|
|
{ |
|
|
|
{ |
|
|
|
heap_close(rel, NoLock); |
|
|
|
heap_close(rel, NoLock); |
|
|
@ -903,8 +905,8 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Otherwise drop the replication slot at the publisher node using |
|
|
|
* Otherwise drop the replication slot at the publisher node using the |
|
|
|
* the replication connection. |
|
|
|
* replication connection. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
load_file("libpqwalreceiver", false); |
|
|
|
load_file("libpqwalreceiver", false); |
|
|
|
|
|
|
|
|
|
|
@ -922,14 +924,15 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) |
|
|
|
|
|
|
|
|
|
|
|
PG_TRY(); |
|
|
|
PG_TRY(); |
|
|
|
{ |
|
|
|
{ |
|
|
|
WalRcvExecResult *res; |
|
|
|
WalRcvExecResult *res; |
|
|
|
|
|
|
|
|
|
|
|
res = walrcv_exec(wrconn, cmd.data, 0, NULL); |
|
|
|
res = walrcv_exec(wrconn, cmd.data, 0, NULL); |
|
|
|
|
|
|
|
|
|
|
|
if (res->status != WALRCV_OK_COMMAND) |
|
|
|
if (res->status != WALRCV_OK_COMMAND) |
|
|
|
ereport(ERROR, |
|
|
|
ereport(ERROR, |
|
|
|
(errmsg("could not drop the replication slot \"%s\" on publisher", |
|
|
|
(errmsg("could not drop the replication slot \"%s\" on publisher", |
|
|
|
slotname), |
|
|
|
slotname), |
|
|
|
errdetail("The error was: %s", res->err))); |
|
|
|
errdetail("The error was: %s", res->err))); |
|
|
|
else |
|
|
|
else |
|
|
|
ereport(NOTICE, |
|
|
|
ereport(NOTICE, |
|
|
|
(errmsg("dropped replication slot \"%s\" on publisher", |
|
|
|
(errmsg("dropped replication slot \"%s\" on publisher", |
|
|
@ -973,9 +976,9 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) |
|
|
|
if (!superuser_arg(newOwnerId)) |
|
|
|
if (!superuser_arg(newOwnerId)) |
|
|
|
ereport(ERROR, |
|
|
|
ereport(ERROR, |
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
|
|
|
errmsg("permission denied to change owner of subscription \"%s\"", |
|
|
|
errmsg("permission denied to change owner of subscription \"%s\"", |
|
|
|
NameStr(form->subname)), |
|
|
|
NameStr(form->subname)), |
|
|
|
errhint("The owner of a subscription must be a superuser."))); |
|
|
|
errhint("The owner of a subscription must be a superuser."))); |
|
|
|
|
|
|
|
|
|
|
|
form->subowner = newOwnerId; |
|
|
|
form->subowner = newOwnerId; |
|
|
|
CatalogTupleUpdate(rel, &tup->t_self, tup); |
|
|
|
CatalogTupleUpdate(rel, &tup->t_self, tup); |
|
|
@ -1055,24 +1058,24 @@ AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId) |
|
|
|
static List * |
|
|
|
static List * |
|
|
|
fetch_table_list(WalReceiverConn *wrconn, List *publications) |
|
|
|
fetch_table_list(WalReceiverConn *wrconn, List *publications) |
|
|
|
{ |
|
|
|
{ |
|
|
|
WalRcvExecResult *res; |
|
|
|
WalRcvExecResult *res; |
|
|
|
StringInfoData cmd; |
|
|
|
StringInfoData cmd; |
|
|
|
TupleTableSlot *slot; |
|
|
|
TupleTableSlot *slot; |
|
|
|
Oid tableRow[2] = {TEXTOID, TEXTOID}; |
|
|
|
Oid tableRow[2] = {TEXTOID, TEXTOID}; |
|
|
|
ListCell *lc; |
|
|
|
ListCell *lc; |
|
|
|
bool first; |
|
|
|
bool first; |
|
|
|
List *tablelist = NIL; |
|
|
|
List *tablelist = NIL; |
|
|
|
|
|
|
|
|
|
|
|
Assert(list_length(publications) > 0); |
|
|
|
Assert(list_length(publications) > 0); |
|
|
|
|
|
|
|
|
|
|
|
initStringInfo(&cmd); |
|
|
|
initStringInfo(&cmd); |
|
|
|
appendStringInfo(&cmd, "SELECT DISTINCT t.schemaname, t.tablename\n" |
|
|
|
appendStringInfo(&cmd, "SELECT DISTINCT t.schemaname, t.tablename\n" |
|
|
|
" FROM pg_catalog.pg_publication_tables t\n" |
|
|
|
" FROM pg_catalog.pg_publication_tables t\n" |
|
|
|
" WHERE t.pubname IN ("); |
|
|
|
" WHERE t.pubname IN ("); |
|
|
|
first = true; |
|
|
|
first = true; |
|
|
|
foreach (lc, publications) |
|
|
|
foreach(lc, publications) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *pubname = strVal(lfirst(lc)); |
|
|
|
char *pubname = strVal(lfirst(lc)); |
|
|
|
|
|
|
|
|
|
|
|
if (first) |
|
|
|
if (first) |
|
|
|
first = false; |
|
|
|
first = false; |
|
|
|