28#include "catalog/pg_authid_d.h"
29#include "catalog/pg_database_d.h"
66#define SUBOPT_CONNECT 0x00000001
67#define SUBOPT_ENABLED 0x00000002
68#define SUBOPT_CREATE_SLOT 0x00000004
69#define SUBOPT_SLOT_NAME 0x00000008
70#define SUBOPT_COPY_DATA 0x00000010
71#define SUBOPT_SYNCHRONOUS_COMMIT 0x00000020
72#define SUBOPT_REFRESH 0x00000040
73#define SUBOPT_BINARY 0x00000080
74#define SUBOPT_STREAMING 0x00000100
75#define SUBOPT_TWOPHASE_COMMIT 0x00000200
76#define SUBOPT_DISABLE_ON_ERR 0x00000400
77#define SUBOPT_PASSWORD_REQUIRED 0x00000800
78#define SUBOPT_RUN_AS_OWNER 0x00001000
79#define SUBOPT_FAILOVER 0x00002000
80#define SUBOPT_RETAIN_DEAD_TUPLES 0x00004000
81#define SUBOPT_MAX_RETENTION_DURATION 0x00008000
82#define SUBOPT_WAL_RECEIVER_TIMEOUT 0x00010000
83#define SUBOPT_LSN 0x00020000
84#define SUBOPT_ORIGIN 0x00040000
85#define SUBOPT_CONFLICT_LOG_DEST 0x00080000
88#define IsSet(val, bits) (((val) & (bits)) == (bits))
180 opts->connect =
true;
182 opts->enabled =
true;
184 opts->create_slot =
true;
186 opts->copy_data =
true;
188 opts->refresh =
true;
190 opts->binary =
false;
194 opts->twophase =
false;
196 opts->disableonerr =
false;
198 opts->passwordrequired =
true;
200 opts->runasowner =
false;
202 opts->failover =
false;
204 opts->retaindeadtuples =
false;
206 opts->maxretention = 0;
364 strcmp(
defel->defname,
"max_retention_duration") == 0)
372 if (
opts->maxretention < 0)
375 errmsg(
"max_retention_duration cannot be negative"));
398 errmsg(
"unrecognized origin value: \"%s\"",
opts->origin));
428 strcmp(
defel->defname,
"wal_receiver_timeout") == 0)
452 strcmp(
defel->defname,
"conflict_log_destination") == 0)
466 errmsg(
"unrecognized subscription parameter: \"%s\"",
defel->defname)));
481 errmsg(
"%s and %s are mutually exclusive options",
482 "connect = false",
"enabled = true")));
484 if (
opts->create_slot &&
488 errmsg(
"%s and %s are mutually exclusive options",
489 "connect = false",
"create_slot = true")));
491 if (
opts->copy_data &&
495 errmsg(
"%s and %s are mutually exclusive options",
496 "connect = false",
"copy_data = true")));
499 opts->enabled =
false;
500 opts->create_slot =
false;
501 opts->copy_data =
false;
508 if (!
opts->slot_name &&
517 errmsg(
"%s and %s are mutually exclusive options",
518 "slot_name = NONE",
"enabled = true")));
523 errmsg(
"subscription with %s must also set %s",
524 "slot_name = NONE",
"enabled = false")));
527 if (
opts->create_slot)
533 errmsg(
"%s and %s are mutually exclusive options",
534 "slot_name = NONE",
"create_slot = true")));
539 errmsg(
"subscription with %s must also set %s",
540 "slot_name = NONE",
"create_slot = false")));
568#define appendQuotedIdentifier(b, s) appendQuotedString(b, s, '"')
569#define appendQuotedLiteral(b, s) appendQuotedString(b, s, '\'')
572 * Check that the specified publications are present on the publisher.
575check_publications(WalReceiverConn *wrconn, List *publications)
577 WalRcvExecResult *res;
579 TupleTableSlot *slot;
580 List *publicationsCopy = NIL;
581 Oid tableRow[1] = {TEXTOID};
583 initStringInfo(&cmd);
584 appendStringInfoString(&cmd, "SELECT t.pubname FROM\n"
585 " pg_catalog.pg_publication t WHERE\n"
587 GetPublicationsStr(publications, &cmd, true);
588 appendStringInfoChar(&cmd, ')');
590 res = walrcv_exec(wrconn, cmd.data, 1, tableRow);
593 if (res->status != WALRCV_OK_TUPLES)
595 errmsg("could not receive list of publications from the publisher: %s",
598 publicationsCopy = list_copy(publications);
600 /* Process publication(s). */
601 slot = MakeSingleTupleTableSlot(res->tupledesc, &TTSOpsMinimalTuple);
602 while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
607 pubname = TextDatumGetCString(slot_getattr(slot, 1, &isnull));
610 /* Delete the publication present in publisher from the list. */
611 publicationsCopy = list_delete(publicationsCopy, makeString(pubname));
612 ExecClearTuple(slot);
615 ExecDropSingleTupleTableSlot(slot);
617 walrcv_clear_result(res);
619 if (list_length(publicationsCopy))
621 /* Prepare the list of non-existent publication(s) for error message. */
622 StringInfoData pubnames;
624 initStringInfo(&pubnames);
626 GetPublicationsStr(publicationsCopy, &pubnames, false);
628 errcode(ERRCODE_UNDEFINED_OBJECT),
629 errmsg_plural("publication %s does not exist on the publisher",
630 "publications %s do not exist on the publisher",
631 list_length(publicationsCopy),
637 * Auxiliary function to build a text array out of a list of String nodes.
640publicationListToArray(List *publist)
644 MemoryContext memcxt;
645 MemoryContext oldcxt;
647 /* Create memory context for temporary allocations. */
648 memcxt = AllocSetContextCreate(CurrentMemoryContext,
649 "publicationListToArray to array",
650 ALLOCSET_DEFAULT_SIZES);
651 oldcxt = MemoryContextSwitchTo(memcxt);
653 datums = palloc_array(Datum, list_length(publist));
655 check_duplicates_in_publist(publist, datums);
657 MemoryContextSwitchTo(oldcxt);
659 arr = construct_array_builtin(datums, list_length(publist), TEXTOID);
661 MemoryContextDelete(memcxt);
663 return PointerGetDatum(arr);
667 * Create new subscription.
670CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
674 ObjectAddress myself;
676 bool nulls[Natts_pg_subscription];
677 Datum values[Natts_pg_subscription];
678 Oid owner = GetUserId();
682 char originname[NAMEDATALEN];
684 uint32 supported_opts;
687 Oid logrelid = InvalidOid;
690 * Parse and check options.
692 * Connection and publication should not be specified here.
694 supported_opts = (SUBOPT_CONNECT | SUBOPT_ENABLED | SUBOPT_CREATE_SLOT |
695 SUBOPT_SLOT_NAME | SUBOPT_COPY_DATA |
696 SUBOPT_SYNCHRONOUS_COMMIT | SUBOPT_BINARY |
697 SUBOPT_STREAMING | SUBOPT_TWOPHASE_COMMIT |
698 SUBOPT_DISABLE_ON_ERR | SUBOPT_PASSWORD_REQUIRED |
699 SUBOPT_RUN_AS_OWNER | SUBOPT_FAILOVER |
700 SUBOPT_RETAIN_DEAD_TUPLES |
701 SUBOPT_MAX_RETENTION_DURATION |
702 SUBOPT_WAL_RECEIVER_TIMEOUT | SUBOPT_ORIGIN |
703 SUBOPT_CONFLICT_LOG_DEST);
704 parse_subscription_options(pstate, stmt->options, supported_opts, &opts);
707 * Since creating a replication slot is not transactional, rolling back
708 * the transaction leaves the created replication slot. So we cannot run
709 * CREATE SUBSCRIPTION inside a transaction block if creating a
712 if (opts.create_slot)
713 PreventInTransactionBlock(isTopLevel, "CREATE SUBSCRIPTION ... WITH (create_slot = true)");
716 * We don't want to allow unprivileged users to be able to trigger
717 * attempts to access arbitrary network destinations, so require the user
718 * to have been specifically authorized to create subscriptions.
720 if (!has_privs_of_role(owner, ROLE_PG_CREATE_SUBSCRIPTION))
722 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
723 errmsg("permission denied to create subscription"),
724 errdetail("Only roles with privileges of the \"%s\" role may create subscriptions.",
725 "pg_create_subscription")));
745 errmsg(
"password_required=false is superuser-only"),
746 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
752#ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
754 elog(
WARNING,
"subscriptions created by regression test cases should have names starting with \"regress_\"");
766 errmsg(
"subscription \"%s\" already exists",
775 opts.retaindeadtuples,
opts.retaindeadtuples,
776 (
opts.maxretention > 0));
783 if (
opts.synchronous_commit ==
NULL)
784 opts.synchronous_commit =
"off";
791 if (
opts.wal_receiver_timeout ==
NULL)
792 opts.wal_receiver_timeout =
"-1";
797 if (
stmt->servername)
820 conninfo =
stmt->conninfo;
826 publications =
stmt->publication;
830 memset(nulls,
false,
sizeof(nulls));
902 if (
stmt->servername)
961 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
979 if (
opts.retaindeadtuples)
1020 if (
opts.create_slot)
1052 (
errmsg(
"created replication slot \"%s\" on publisher",
1064 (
errmsg(
"subscription was created, but is not connected"),
1065 errhint(
"To initiate replication, you must manually create the replication slot, enable the subscription, and alter the subscription to refresh publications.")));
1081 if (
opts.enabled ||
opts.retaindeadtuples)
1125 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
1340 errmsg_internal(
"sequence \"%s.%s\" removed from subscription \"%s\"",
1378 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
1414#ifdef USE_ASSERT_CHECKING
1434 errmsg_internal(
"sequence \"%s.%s\" of subscription \"%s\" set to INIT state",
1506 errmsg(
"cannot set option \"%s\" for enabled subscription",
1520 errmsg(
"cannot set option \"%s\" for a subscription that does not have a slot name",
1635 errmsg(
"subscription \"%s\" does not exist",
1743 errmsg(
"password_required=false is superuser-only"),
1744 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
1751 memset(nulls,
false,
sizeof(nulls));
1772 errmsg(
"cannot set %s for enabled subscription",
1773 "slot_name = NONE")));
1783 if (
opts.synchronous_commit)
1818 errmsg(
"password_required=false is superuser-only"),
1819 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
1857 errmsg(
"\"slot_name\" and \"two_phase\" cannot be altered at the same time")));
1873 errmsg(
"cannot alter \"two_phase\" when logical replication worker is still running"),
1874 errhint(
"Try again after some time.")));
1887 errmsg(
"cannot disable \"two_phase\" when prepared transactions exist"),
1888 errhint(
"Resolve these transactions and try again.")));
1957 errmsg(
"cannot alter retain_dead_tuples when logical replication worker is still running"),
1958 errhint(
"Try again after some time.")));
2009 origin =
opts.origin;
2035 opts.conflictlogdest,
2058 errmsg(
"cannot enable subscription that does not have a slot name")));
2098 if (
form->subserver)
2121 errmsg(
"subscription owner \"%s\" does not have permission on foreign server \"%s\"",
2156 if (
form->subserver)
2201 errmsg(
"ALTER SUBSCRIPTION with refresh is not allowed for disabled subscriptions"),
2202 errhint(
"Use ALTER SUBSCRIPTION ... SET PUBLICATION ... WITH (refresh = false).")));
2211 errmsg(
"ALTER SUBSCRIPTION with refresh and copy_data is not allowed when two_phase is enabled"),
2212 errhint(
"Use ALTER SUBSCRIPTION ... SET PUBLICATION with refresh = false, or with copy_data = false, or use DROP/CREATE SUBSCRIPTION.")));
2248 errmsg(
"ALTER SUBSCRIPTION with refresh is not allowed for disabled subscriptions"),
2252 "ALTER SUBSCRIPTION ... ADD PUBLICATION ... WITH (refresh = false)" :
2253 "ALTER SUBSCRIPTION ... DROP PUBLICATION ... WITH (refresh = false)")));
2262 errmsg(
"ALTER SUBSCRIPTION with refresh and copy_data is not allowed when two_phase is enabled"),
2264 errhint(
"Use %s with refresh = false, or with copy_data = false, or use DROP/CREATE SUBSCRIPTION.",
2266 "ALTER SUBSCRIPTION ... ADD PUBLICATION" :
2267 "ALTER SUBSCRIPTION ... DROP PUBLICATION")));
2286 errmsg(
"%s is not allowed for disabled subscriptions",
2287 "ALTER SUBSCRIPTION ... REFRESH PUBLICATION")));
2309 errmsg(
"ALTER SUBSCRIPTION ... REFRESH PUBLICATION with copy_data is not allowed when two_phase is enabled"),
2310 errhint(
"Use ALTER SUBSCRIPTION ... REFRESH PUBLICATION with copy_data = false, or use DROP/CREATE SUBSCRIPTION.")));
2324 errmsg(
"%s is not allowed for disabled subscriptions",
2325 "ALTER SUBSCRIPTION ... REFRESH SEQUENCES"));
2356 errmsg(
"skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
2369 elog(
ERROR,
"unrecognized ALTER SUBSCRIPTION kind %d",
2415 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
2477 *
err =
psprintf(
_(
"subscription owner \"%s\" does not have permission on foreign server \"%s\""),
2512 elog(
ERROR,
"cache lookup failed for relation %u",
2525 errmsg(
"dropped conflict log table \"%s\" for subscription \"%s\"",
2544 char *subconninfo =
NULL;
2548 char *conninfo =
NULL;
2574 if (!
stmt->missing_ok)
2577 errmsg(
"subscription \"%s\" does not exist",
2581 (
errmsg(
"subscription \"%s\" does not exist, skipping",
2760 conninfo = subconninfo;
2863 (
errmsg(
"dropped replication slot \"%s\" on publisher",
2872 (
errmsg(
"could not drop replication slot \"%s\" on publisher: %s",
2873 slotname, res->
err)));
2880 errmsg(
"could not drop replication slot \"%s\" on publisher: %s",
2881 slotname, res->
err)));
2921 errmsg(
"password_required=false is superuser-only"),
2922 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
2953 errmsg(
"new subscription owner \"%s\" does not have permission on foreign server \"%s\"",
3002 errmsg(
"subscription \"%s\" does not exist",
name)));
3035 errmsg(
"subscription with OID %u does not exist", subid)));
3114 "SELECT DISTINCT P.pubname AS pubname\n"
3115 "FROM pg_publication P,\n"
3116 " LATERAL pg_get_publication_tables(P.pubname) GPT\n"
3117 " JOIN pg_subscription_rel PS ON (GPT.relid = PS.srrelid OR"
3118 " GPT.relid IN (SELECT relid FROM pg_partition_ancestors(PS.srrelid) UNION"
3119 " SELECT relid FROM pg_partition_tree(PS.srrelid))),\n"
3120 " pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace)\n"
3121 "WHERE C.oid = GPT.relid AND P.pubname IN (");
3158 errmsg(
"could not receive list of replicated tables from the publisher: %s",
3197 errmsg(
"subscription \"%s\" requested copy_data with origin = NONE but might copy data that had a different origin",
3199 errdetail_plural(
"The subscription subscribes to a publication (%s) that contains tables that are written to by other subscriptions.",
3200 "The subscription subscribes to publications (%s) that contain tables that are written to by other subscriptions.",
3202 errhint(
"Verify that initial data copied from the publisher tables did not come from other origins."));
3206 errmsg(
"subscription \"%s\" enabled retain_dead_tuples but might not reliably detect conflicts for changes from different origins",
3208 errdetail_plural(
"The subscription subscribes to a publication (%s) that contains tables that are written to by other subscriptions.",
3209 "The subscription subscribes to publications (%s) that contain tables that are written to by other subscriptions.",
3211 errhint(
"Consider using origin = NONE or disabling retain_dead_tuples."));
3247 "SELECT DISTINCT P.pubname AS pubname\n"
3248 "FROM pg_publication P,\n"
3249 " LATERAL pg_get_publication_sequences(P.pubname) GPS\n"
3250 " JOIN pg_subscription_rel PS ON (GPS.relid = PS.srrelid),\n"
3251 " pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace)\n"
3252 "WHERE C.oid = GPS.relid AND P.pubname IN (");
3272 "AND NOT (N.nspname = %s AND C.relname = %s)\n",
3285 errmsg(
"could not receive list of replicated sequences from the publisher: %s",
3317 errmsg(
"subscription \"%s\" requested copy_data with origin = NONE but might copy data that had a different origin",
3319 errdetail_plural(
"The subscription subscribes to a publication (%s) that contains sequences that are written to by other subscriptions.",
3320 "The subscription subscribes to publications (%s) that contain sequences that are written to by other subscriptions.",
3322 errhint(
"Verify that initial data copied from the publisher sequences did not come from other origins."));
3352 errmsg(
"cannot enable retain_dead_tuples if the publisher is running a version earlier than PostgreSQL 19"));
3359 errmsg(
"could not obtain recovery progress from the publisher: %s",
3364 elog(
ERROR,
"failed to fetch tuple for the recovery progress");
3371 errmsg(
"cannot enable retain_dead_tuples if the publisher is in recovery"));
3415 errmsg(
"\"wal_level\" is insufficient to create the replication slot required by retain_dead_tuples"),
3416 errhint(
"\"wal_level\" must be set to \"replica\" or \"logical\" at server start."));
3421 errmsg(
"commit timestamp and origin data required for detecting conflicts won't be retained"),
3422 errhint(
"Consider setting \"%s\" to true.",
3423 "track_commit_timestamp"));
3428 errmsg(
"deleted rows to detect conflicts would not be removed until the subscription is enabled"),
3430 ?
errhint(
"Consider setting %s to false.",
3431 "retain_dead_tuples") : 0);
3437 errmsg(
"max_retention_duration is ineffective when retain_dead_tuples is disabled"));
3502 appendStringInfo(&cmd,
"SELECT DISTINCT n.nspname, c.relname, c.relkind, gpt.attrs\n"
3503 " FROM pg_class c\n"
3504 " JOIN pg_namespace n ON n.oid = c.relnamespace\n"
3505 " JOIN ( SELECT (pg_get_publication_tables(VARIADIC array_agg(pubname::text))).*\n"
3506 " FROM pg_publication\n"
3507 " WHERE pubname IN ( %s )) AS gpt\n"
3508 " ON gpt.relid = c.oid\n",
3516 " FROM pg_catalog.pg_publication_sequences s\n"
3517 " WHERE s.pubname IN ( %s )",
3530 " WHERE t.pubname IN ( %s )",
3542 errmsg(
"could not receive list of replicated tables from the publisher: %s",
3570 errmsg(
"cannot use different column lists for table \"%s.%s\" in different publications",
3613 elog(
WARNING,
"could not drop tablesync replication slot \"%s\"",
3620 errmsg(
"could not connect to publisher when attempting to drop replication slot \"%s\": %s",
3623 errhint(
"Use %s to disable the subscription, and then use %s to disassociate it from the slot.",
3624 "ALTER SUBSCRIPTION ... DISABLE",
3625 "ALTER SUBSCRIPTION ... SET (slot_name = NONE)")));
3654 errmsg(
"publication name \"%s\" used more than once",
3698 errmsg(
"publication \"%s\" is already in subscription \"%s\"",
3709 else if (!
addpub && !found)
3712 errmsg(
"publication \"%s\" is not in subscription \"%s\"",
3723 errmsg(
"cannot drop all the publications from a subscription")));
3780 errmsg(
"%s requires a Boolean value or \"parallel\"",
void check_can_set_role(Oid member, Oid role)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
void LogicalRepWorkersWakeupAtCommit(Oid subid)
void ReplicationOriginNameForLogicalRep(Oid suboid, Oid relid, char *originname, Size szoriginname)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define TextDatumGetCString(d)
#define Assert(condition)
#define OidIsValid(objectId)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
bool track_commit_timestamp
const char *const ConflictLogDestNames[]
Oid create_conflict_log_table(Oid subid, char *subname, Oid subowner)
ConflictLogDest GetConflictLogDest(const char *dest)
#define CONFLICTS_LOGGED_TO_TABLE(dest)
int32 defGetInt32(DefElem *def)
char * defGetString(DefElem *def)
bool defGetBoolean(DefElem *def)
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
#define PERFORM_DELETION_SKIP_ORIGINAL
#define PERFORM_DELETION_INTERNAL
void load_file(const char *filename, bool restricted)
int errcode(int sqlerrcode)
int errhint(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ereport(elevel,...)
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
bool equal(const void *a, const void *b)
void err(int eval, const char *fmt,...)
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
void CheckSubscriptionRelkind(char localrelkind, char remoterelkind, const char *nspname, const char *relname)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsMinimalTuple
#define palloc_object(type)
#define DirectFunctionCall1(func, arg1)
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
char * ForeignServerConnectionString(Oid userid, ForeignServer *server)
UserMapping * GetUserMapping(Oid userid, Oid serverid)
ForeignServer * GetForeignServer(Oid serverid)
bool parse_int(const char *value, int *result, int flags, const char **hintmsg)
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
List * logicalrep_workers_find(Oid subid, bool only_running, bool acquire_lock)
void ApplyLauncherWakeupAtCommit(void)
void logicalrep_worker_stop(LogicalRepWorkerType wtype, Oid subid, Oid relid)
void ApplyLauncherForgetWorkerStartTime(Oid subid)
List * lappend(List *list, void *datum)
List * list_append_unique(List *list, void *datum)
List * list_copy(const List *oldlist)
void list_free(List *list)
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
#define AccessExclusiveLock
#define SET_LOCKTAG_OBJECT(locktag, dboid, classoid, objoid, objsubid)
char * get_rel_name(Oid relid)
char * get_database_name(Oid dbid)
char get_rel_relkind(Oid relid)
Oid get_rel_namespace(Oid relid)
char * get_qualified_objname(Oid nspid, char *objname)
char * get_namespace_name(Oid nspid)
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
char * pstrdup(const char *in)
void pfree(void *pointer)
char * GetUserNameFromId(Oid roleid, bool noerr)
Datum namein(PG_FUNCTION_ARGS)
#define RangeVarGetRelid(relation, lockmode, missing_ok)
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
#define InvokeObjectDropHook(classId, objectId, subId)
#define ObjectAddressSet(addr, class_id, object_id)
int oid_cmp(const void *p1, const void *p2)
ReplOriginId replorigin_create(const char *roname)
ReplOriginId replorigin_by_name(const char *roname, bool missing_ok)
XLogRecPtr replorigin_get_progress(ReplOriginId node, bool flush)
void replorigin_drop_by_name(const char *name, bool missing_ok, bool nowait)
@ ALTER_SUBSCRIPTION_REFRESH_PUBLICATION
@ ALTER_SUBSCRIPTION_ENABLED
@ ALTER_SUBSCRIPTION_DROP_PUBLICATION
@ ALTER_SUBSCRIPTION_SERVER
@ ALTER_SUBSCRIPTION_SET_PUBLICATION
@ ALTER_SUBSCRIPTION_REFRESH_SEQUENCES
@ ALTER_SUBSCRIPTION_SKIP
@ ALTER_SUBSCRIPTION_OPTIONS
@ ALTER_SUBSCRIPTION_CONNECTION
@ ALTER_SUBSCRIPTION_ADD_PUBLICATION
static AmcheckOptions opts
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, Oid refclassId, Oid refobjectId)
static int server_version
static int list_length(const List *l)
#define foreach_delete_current(lst, var_or_cell)
#define foreach_ptr(type, var, lst)
Datum pg_lsn_in(PG_FUNCTION_ARGS)
static Datum LSNGetDatum(XLogRecPtr X)
static XLogRecPtr DatumGetLSN(Datum X)
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
void UpdateSubscriptionRelState(Oid subid, Oid relid, char state, XLogRecPtr sublsn, bool already_locked)
Subscription * GetSubscription(Oid subid, bool missing_ok, bool conninfo_needed, bool conninfo_aclcheck)
void RemoveSubscriptionRel(Oid subid, Oid relid)
char GetSubscriptionRelState(Oid subid, Oid relid, XLogRecPtr *sublsn)
void GetPublicationsStr(List *publications, StringInfo dest, bool quote_literal)
void AddSubscriptionRelState(Oid subid, Oid relid, char state, XLogRecPtr sublsn, bool retain_lock)
List * GetSubscriptionRelations(Oid subid, bool tables, bool sequences, bool not_ready)
END_CATALOG_STRUCT typedef FormData_pg_subscription * Form_pg_subscription
static char buf[DEFAULT_XLOG_SEG_SIZE]
void pgstat_drop_subscription(Oid subid)
void pgstat_create_subscription(Oid subid)
int pg_strcasecmp(const char *s1, const char *s2)
#define qsort(a, b, c, d)
static bool DatumGetBool(Datum X)
static Name DatumGetName(Datum X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static char DatumGetChar(Datum X)
static Datum CStringGetDatum(const char *X)
static Datum Int32GetDatum(int32 X)
static Datum CharGetDatum(char X)
char * psprintf(const char *fmt,...)
char * quote_literal_cstr(const char *rawstr)
#define RelationGetDescr(relation)
bool ReplicationSlotValidateName(const char *name, bool allow_reserved_name, int elevel)
#define ERRCODE_DUPLICATE_OBJECT
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
LogicalRepWorkerType type
ConflictLogDest conflictlogdest
char * wal_receiver_timeout
char * synchronous_commit
Tuplestorestate * tuplestore
void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
char defGetStreamingMode(DefElem *def)
#define SUBOPT_CREATE_SLOT
#define SUBOPT_PASSWORD_REQUIRED
#define SUBOPT_SYNCHRONOUS_COMMIT
static void check_duplicates_in_publist(List *publist, Datum *datums)
static void CheckAlterSubOption(Subscription *sub, const char *option, bool slot_needs_update, bool isTopLevel)
#define SUBOPT_RETAIN_DEAD_TUPLES
static Datum publicationListToArray(List *publist)
static bool alter_sub_conflict_log_dest(Subscription *sub, ConflictLogDest oldlogdest, ConflictLogDest newlogdest, Oid *conflicttablerelid)
static void check_publications_origin_sequences(WalReceiverConn *wrconn, List *publications, bool copydata, char *origin, Oid *subrel_local_oids, int subrel_count, char *subname)
static void check_publications(WalReceiverConn *wrconn, List *publications)
#define SUBOPT_RUN_AS_OWNER
static void drop_sub_conflict_log_table(Oid subid, char *subname, Oid subconflictlogrelid)
static char * construct_subserver_conninfo(Oid subserver, Oid subowner, char **err)
static List * fetch_relation_list(WalReceiverConn *wrconn, List *publications)
#define SUBOPT_TWOPHASE_COMMIT
static void AlterSubscription_refresh(Subscription *sub, bool copy_data, List *validate_publications)
static void ReportSlotConnectionError(List *rstates, Oid subid, char *slotname, char *err)
#define SUBOPT_DISABLE_ON_ERR
#define SUBOPT_CONFLICT_LOG_DEST
static void parse_subscription_options(ParseState *pstate, List *stmt_options, uint32 supported_opts, SubOpts *opts)
void CheckSubDeadTupleRetention(bool check_guc, bool sub_disabled, int elevel_for_sub_disabled, bool retain_dead_tuples, bool retention_active, bool max_retention_set)
static void AlterSubscription_refresh_seq(Subscription *sub)
static void AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId)
void ReplicationSlotDropAtPubNode(WalReceiverConn *wrconn, char *slotname, bool missing_ok)
#define appendQuotedIdentifier(b, s)
void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId)
#define SUBOPT_MAX_RETENTION_DURATION
static List * merge_publications(List *oldpublist, List *newpublist, bool addpub, const char *subname)
#define SUBOPT_WAL_RECEIVER_TIMEOUT
static void check_publications_origin_tables(WalReceiverConn *wrconn, List *publications, bool copydata, bool retain_dead_tuples, char *origin, Oid *subrel_local_oids, int subrel_count, char *subname)
static bool list_member_rangevar(const List *list, RangeVar *rv)
static void appendQuotedString(StringInfo buf, const char *str, char quote)
static void check_pub_dead_tuple_retention(WalReceiverConn *wrconn)
ObjectAddress AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, bool isTopLevel)
bool superuser_arg(Oid roleid)
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
#define SearchSysCacheCopy1(cacheId, key1)
#define SearchSysCacheCopy2(cacheId, key1, key2)
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
void ReplicationSlotNameForTablesync(Oid suboid, Oid relid, char *syncslotname, Size szslot)
void UpdateTwoPhaseState(Oid suboid, char new_state)
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
bool LookupGXactBySubid(Oid subid)
String * makeString(char *str)
static WalReceiverConn * wrconn
#define walrcv_connect(conninfo, replication, logical, must_use_password, appname, err)
#define walrcv_create_slot(conn, slotname, temporary, two_phase, failover, snapshot_action, lsn)
static void walrcv_clear_result(WalRcvExecResult *walres)
#define walrcv_server_version(conn)
#define walrcv_check_conninfo(conninfo, must_use_password)
#define walrcv_alter_slot(conn, slotname, failover, two_phase)
#define walrcv_exec(conn, exec, nRetTypes, retTypes)
#define walrcv_disconnect(conn)
@ WORKERTYPE_SEQUENCESYNC
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
#define XLogRecPtrIsValid(r)
#define LSN_FORMAT_ARGS(lsn)
#define InvalidXLogRecPtr