28#include "catalog/pg_authid_d.h"
29#include "catalog/pg_database_d.h"
60#define SUBOPT_CONNECT 0x00000001
61#define SUBOPT_ENABLED 0x00000002
62#define SUBOPT_CREATE_SLOT 0x00000004
63#define SUBOPT_SLOT_NAME 0x00000008
64#define SUBOPT_COPY_DATA 0x00000010
65#define SUBOPT_SYNCHRONOUS_COMMIT 0x00000020
66#define SUBOPT_REFRESH 0x00000040
67#define SUBOPT_BINARY 0x00000080
68#define SUBOPT_STREAMING 0x00000100
69#define SUBOPT_TWOPHASE_COMMIT 0x00000200
70#define SUBOPT_DISABLE_ON_ERR 0x00000400
71#define SUBOPT_PASSWORD_REQUIRED 0x00000800
72#define SUBOPT_RUN_AS_OWNER 0x00001000
73#define SUBOPT_FAILOVER 0x00002000
74#define SUBOPT_RETAIN_DEAD_TUPLES 0x00004000
75#define SUBOPT_MAX_RETENTION_DURATION 0x00008000
76#define SUBOPT_LSN 0x00010000
77#define SUBOPT_ORIGIN 0x00020000
80#define IsSet(val, bits) (((val) & (bits)) == (bits))
111 List *publications,
bool copydata,
112 bool retain_dead_tuples,
char *origin,
113 Oid *subrel_local_oids,
int subrel_count,
120 bool slot_needs_update,
bool isTopLevel);
139 Assert(supported_opts != 0);
148 opts->connect =
true;
150 opts->enabled =
true;
152 opts->create_slot =
true;
154 opts->copy_data =
true;
156 opts->refresh =
true;
158 opts->binary =
false;
160 opts->streaming = LOGICALREP_STREAM_PARALLEL;
162 opts->twophase =
false;
164 opts->disableonerr =
false;
166 opts->passwordrequired =
true;
168 opts->runasowner =
false;
170 opts->failover =
false;
172 opts->retaindeadtuples =
false;
174 opts->maxretention = 0;
179 foreach(lc, stmt_options)
184 strcmp(defel->
defname,
"connect") == 0)
193 strcmp(defel->
defname,
"enabled") == 0)
202 strcmp(defel->
defname,
"create_slot") == 0)
211 strcmp(defel->
defname,
"slot_name") == 0)
220 if (strcmp(
opts->slot_name,
"none") == 0)
221 opts->slot_name = NULL;
226 strcmp(defel->
defname,
"copy_data") == 0)
235 strcmp(defel->
defname,
"synchronous_commit") == 0)
249 strcmp(defel->
defname,
"refresh") == 0)
258 strcmp(defel->
defname,
"binary") == 0)
267 strcmp(defel->
defname,
"streaming") == 0)
276 strcmp(defel->
defname,
"two_phase") == 0)
285 strcmp(defel->
defname,
"disable_on_error") == 0)
294 strcmp(defel->
defname,
"password_required") == 0)
303 strcmp(defel->
defname,
"run_as_owner") == 0)
312 strcmp(defel->
defname,
"failover") == 0)
321 strcmp(defel->
defname,
"retain_dead_tuples") == 0)
330 strcmp(defel->
defname,
"max_retention_duration") == 0)
339 strcmp(defel->
defname,
"origin") == 0)
358 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
359 errmsg(
"unrecognized origin value: \"%s\"",
opts->origin));
362 strcmp(defel->
defname,
"lsn") == 0)
371 if (strcmp(lsn_str,
"none") == 0)
381 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
382 errmsg(
"invalid WAL location (LSN): %s", lsn_str)));
390 (
errcode(ERRCODE_SYNTAX_ERROR),
391 errmsg(
"unrecognized subscription parameter: \"%s\"", defel->
defname)));
404 (
errcode(ERRCODE_SYNTAX_ERROR),
406 errmsg(
"%s and %s are mutually exclusive options",
407 "connect = false",
"enabled = true")));
409 if (
opts->create_slot &&
412 (
errcode(ERRCODE_SYNTAX_ERROR),
413 errmsg(
"%s and %s are mutually exclusive options",
414 "connect = false",
"create_slot = true")));
416 if (
opts->copy_data &&
419 (
errcode(ERRCODE_SYNTAX_ERROR),
420 errmsg(
"%s and %s are mutually exclusive options",
421 "connect = false",
"copy_data = true")));
424 opts->enabled =
false;
425 opts->create_slot =
false;
426 opts->copy_data =
false;
433 if (!
opts->slot_name &&
440 (
errcode(ERRCODE_SYNTAX_ERROR),
442 errmsg(
"%s and %s are mutually exclusive options",
443 "slot_name = NONE",
"enabled = true")));
446 (
errcode(ERRCODE_SYNTAX_ERROR),
448 errmsg(
"subscription with %s must also set %s",
449 "slot_name = NONE",
"enabled = false")));
452 if (
opts->create_slot)
456 (
errcode(ERRCODE_SYNTAX_ERROR),
458 errmsg(
"%s and %s are mutually exclusive options",
459 "slot_name = NONE",
"create_slot = true")));
462 (
errcode(ERRCODE_SYNTAX_ERROR),
464 errmsg(
"subscription with %s must also set %s",
465 "slot_name = NONE",
"create_slot = false")));
480 Oid tableRow[1] = {TEXTOID};
484 " pg_catalog.pg_publication t WHERE\n"
494 errmsg(
"could not receive list of publications from the publisher: %s",
497 publicationsCopy =
list_copy(publications);
525 errcode(ERRCODE_UNDEFINED_OBJECT),
526 errmsg_plural(
"publication %s does not exist on the publisher",
527 "publications %s do not exist on the publisher",
546 "publicationListToArray to array",
573 bool nulls[Natts_pg_subscription];
605 if (
opts.create_slot)
615 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
616 errmsg(
"permission denied to create subscription"),
617 errdetail(
"Only roles with privileges of the \"%s\" role may create subscriptions.",
618 "pg_create_subscription")));
637 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
638 errmsg(
"password_required=false is superuser-only"),
639 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
645#ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
646 if (strncmp(
stmt->subname,
"regress_", 8) != 0)
647 elog(
WARNING,
"subscriptions created by regression test cases should have names starting with \"regress_\"");
659 errmsg(
"subscription \"%s\" already exists",
668 opts.retaindeadtuples,
opts.retaindeadtuples,
669 (
opts.maxretention > 0));
672 opts.slot_name == NULL)
676 if (
opts.synchronous_commit == NULL)
677 opts.synchronous_commit =
"off";
679 conninfo =
stmt->conninfo;
680 publications =
stmt->publication;
690 memset(nulls,
false,
sizeof(nulls));
693 Anum_pg_subscription_oid);
697 values[Anum_pg_subscription_subname - 1] =
703 values[Anum_pg_subscription_subtwophasestate - 1] =
705 LOGICALREP_TWOPHASE_STATE_PENDING :
706 LOGICALREP_TWOPHASE_STATE_DISABLED);
711 values[Anum_pg_subscription_subretaindeadtuples - 1] =
713 values[Anum_pg_subscription_submaxretention - 1] =
715 values[Anum_pg_subscription_subretentionactive - 1] =
717 values[Anum_pg_subscription_subconninfo - 1] =
720 values[Anum_pg_subscription_subslotname - 1] =
723 nulls[Anum_pg_subscription_subslotname - 1] =
true;
724 values[Anum_pg_subscription_subsynccommit - 1] =
726 values[Anum_pg_subscription_subpublications - 1] =
728 values[Anum_pg_subscription_suborigin - 1] =
753 bool must_use_password;
761 (
errcode(ERRCODE_CONNECTION_FAILURE),
762 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
770 NULL, 0,
stmt->subname);
772 if (
opts.retaindeadtuples)
779 table_state =
opts.copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY;
806 if (
opts.create_slot)
808 bool twophase_enabled =
false;
828 if (
opts.twophase && !
opts.copy_data && tables !=
NIL)
829 twophase_enabled =
true;
834 if (twophase_enabled)
838 (
errmsg(
"created replication slot \"%s\" on publisher",
850 (
errmsg(
"subscription was created, but is not connected"),
851 errhint(
"To initiate replication, you must manually create the replication slot, enable the subscription, and refresh the subscription.")));
867 if (
opts.enabled ||
opts.retaindeadtuples)
879 List *validate_publications)
884 Oid *subrel_local_oids;
885 Oid *pubrel_local_oids;
891 typedef struct SubRemoveRels
896 SubRemoveRels *sub_remove_rels;
898 bool must_use_password;
909 (
errcode(ERRCODE_CONNECTION_FAILURE),
910 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
915 if (validate_publications)
930 subrel_local_oids =
palloc(subrel_count *
sizeof(
Oid));
932 foreach(lc, subrel_states)
936 subrel_local_oids[off++] = relstate->
relid;
938 qsort(subrel_local_oids, subrel_count,
943 subrel_local_oids, subrel_count, sub->
name);
949 sub_remove_rels =
palloc(subrel_count *
sizeof(SubRemoveRels));
961 foreach(lc, pubrel_names)
972 pubrel_local_oids[off++] = relid;
974 if (!bsearch(&relid, subrel_local_oids,
978 copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY,
994 for (off = 0; off < subrel_count; off++)
996 Oid relid = subrel_local_oids[off];
998 if (!bsearch(&relid, pubrel_local_oids,
1024 sub_remove_rels[remove_rel_len].relid = relid;
1025 sub_remove_rels[remove_rel_len++].state =
state;
1035 if (
state != SUBREL_STATE_READY)
1050 sizeof(originname));
1067 for (off = 0; off < remove_rel_len; off++)
1069 if (sub_remove_rels[off].
state != SUBREL_STATE_READY &&
1070 sub_remove_rels[off].
state != SUBREL_STATE_SYNCDONE)
1085 syncslotname,
sizeof(syncslotname));
1106 bool slot_needs_update,
bool isTopLevel)
1109 strcmp(
option,
"two_phase") == 0 ||
1110 strcmp(
option,
"retain_dead_tuples") == 0);
1116 Assert(!slot_needs_update || strcmp(
option,
"retain_dead_tuples") != 0);
1164 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1165 errmsg(
"cannot set option \"%s\" for enabled subscription",
1168 if (slot_needs_update)
1178 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1179 errmsg(
"cannot set option \"%s\" for a subscription that does not have a slot name",
1200 bool nulls[Natts_pg_subscription];
1201 bool replaces[Natts_pg_subscription];
1205 bool update_tuple =
false;
1206 bool update_failover =
false;
1207 bool update_two_phase =
false;
1208 bool check_pub_rdt =
false;
1209 bool retain_dead_tuples;
1211 bool retention_active;
1226 (
errcode(ERRCODE_UNDEFINED_OBJECT),
1227 errmsg(
"subscription \"%s\" does not exist",
1251 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1252 errmsg(
"password_required=false is superuser-only"),
1253 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
1260 memset(nulls,
false,
sizeof(nulls));
1261 memset(replaces,
false,
sizeof(replaces));
1278 supported_opts, &
opts);
1291 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1292 errmsg(
"cannot set %s for enabled subscription",
1293 "slot_name = NONE")));
1296 values[Anum_pg_subscription_subslotname - 1] =
1299 nulls[Anum_pg_subscription_subslotname - 1] =
true;
1300 replaces[Anum_pg_subscription_subslotname - 1] =
true;
1303 if (
opts.synchronous_commit)
1305 values[Anum_pg_subscription_subsynccommit - 1] =
1307 replaces[Anum_pg_subscription_subsynccommit - 1] =
true;
1312 values[Anum_pg_subscription_subbinary - 1] =
1314 replaces[Anum_pg_subscription_subbinary - 1] =
true;
1319 values[Anum_pg_subscription_substream - 1] =
1321 replaces[Anum_pg_subscription_substream - 1] =
true;
1326 values[Anum_pg_subscription_subdisableonerr - 1]
1328 replaces[Anum_pg_subscription_subdisableonerr - 1]
1337 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1338 errmsg(
"password_required=false is superuser-only"),
1339 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
1341 values[Anum_pg_subscription_subpasswordrequired - 1]
1343 replaces[Anum_pg_subscription_subpasswordrequired - 1]
1349 values[Anum_pg_subscription_subrunasowner - 1] =
1351 replaces[Anum_pg_subscription_subrunasowner - 1] =
true;
1363 update_two_phase = !
opts.twophase;
1373 if (update_two_phase &&
1376 (
errcode(ERRCODE_SYNTAX_ERROR),
1377 errmsg(
"\"slot_name\" and \"two_phase\" cannot be altered at the same time")));
1392 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1393 errmsg(
"cannot alter \"two_phase\" when logical replication worker is still running"),
1394 errhint(
"Try again after some time.")));
1402 if (update_two_phase &&
1406 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1407 errmsg(
"cannot disable \"two_phase\" when prepared transactions exist"),
1408 errhint(
"Resolve these transactions and try again.")));
1411 values[Anum_pg_subscription_subtwophasestate - 1] =
1413 LOGICALREP_TWOPHASE_STATE_PENDING :
1414 LOGICALREP_TWOPHASE_STATE_DISABLED);
1415 replaces[Anum_pg_subscription_subtwophasestate - 1] =
true;
1425 update_failover =
true;
1430 values[Anum_pg_subscription_subfailover - 1] =
1432 replaces[Anum_pg_subscription_subfailover - 1] =
true;
1437 values[Anum_pg_subscription_subretaindeadtuples - 1] =
1439 replaces[Anum_pg_subscription_subretaindeadtuples - 1] =
true;
1457 values[Anum_pg_subscription_subretentionactive - 1] =
1459 replaces[Anum_pg_subscription_subretentionactive - 1] =
true;
1461 retention_active =
opts.retaindeadtuples;
1476 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1477 errmsg(
"cannot alter retain_dead_tuples when logical replication worker is still running"),
1478 errhint(
"Try again after some time.")));
1488 check_pub_rdt =
opts.retaindeadtuples;
1489 retain_dead_tuples =
opts.retaindeadtuples;
1494 values[Anum_pg_subscription_submaxretention - 1] =
1496 replaces[Anum_pg_subscription_submaxretention - 1] =
true;
1498 max_retention =
opts.maxretention;
1511 (max_retention > 0));
1515 values[Anum_pg_subscription_suborigin - 1] =
1517 replaces[Anum_pg_subscription_suborigin - 1] =
true;
1524 check_pub_rdt = retain_dead_tuples &&
1527 origin =
opts.origin;
1530 update_tuple =
true;
1542 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1543 errmsg(
"cannot enable subscription that does not have a slot name")));
1554 values[Anum_pg_subscription_subenabled - 1] =
1556 replaces[Anum_pg_subscription_subenabled - 1] =
true;
1561 update_tuple =
true;
1580 values[Anum_pg_subscription_subconninfo - 1] =
1582 replaces[Anum_pg_subscription_subconninfo - 1] =
true;
1583 update_tuple =
true;
1597 supported_opts, &
opts);
1599 values[Anum_pg_subscription_subpublications - 1] =
1601 replaces[Anum_pg_subscription_subpublications - 1] =
true;
1603 update_tuple =
true;
1610 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1611 errmsg(
"ALTER SUBSCRIPTION with refresh is not allowed for disabled subscriptions"),
1612 errhint(
"Use ALTER SUBSCRIPTION ... SET PUBLICATION ... WITH (refresh = false).")));
1620 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1621 errmsg(
"ALTER SUBSCRIPTION with refresh and copy_data is not allowed when two_phase is enabled"),
1622 errhint(
"Use ALTER SUBSCRIPTION ... SET PUBLICATION with refresh = false, or with copy_data = false, or use DROP/CREATE SUBSCRIPTION.")));
1644 supported_opts, &
opts);
1647 values[Anum_pg_subscription_subpublications - 1] =
1649 replaces[Anum_pg_subscription_subpublications - 1] =
true;
1651 update_tuple =
true;
1657 List *validate_publications = (isadd) ?
stmt->publication : NULL;
1661 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1662 errmsg(
"ALTER SUBSCRIPTION with refresh is not allowed for disabled subscriptions"),
1666 "ALTER SUBSCRIPTION ... ADD PUBLICATION ... WITH (refresh = false)" :
1667 "ALTER SUBSCRIPTION ... DROP PUBLICATION ... WITH (refresh = false)")));
1675 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1676 errmsg(
"ALTER SUBSCRIPTION with refresh and copy_data is not allowed when two_phase is enabled"),
1678 errhint(
"Use %s with refresh = false, or with copy_data = false, or use DROP/CREATE SUBSCRIPTION.",
1680 "ALTER SUBSCRIPTION ... ADD PUBLICATION" :
1681 "ALTER SUBSCRIPTION ... DROP PUBLICATION")));
1689 validate_publications);
1699 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1700 errmsg(
"ALTER SUBSCRIPTION ... REFRESH is not allowed for disabled subscriptions")));
1724 (
errcode(ERRCODE_SYNTAX_ERROR),
1725 errmsg(
"ALTER SUBSCRIPTION ... REFRESH with copy_data is not allowed when two_phase is enabled"),
1726 errhint(
"Use ALTER SUBSCRIPTION ... REFRESH with copy_data = false, or use DROP/CREATE SUBSCRIPTION.")));
1753 originname,
sizeof(originname));
1760 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1761 errmsg(
"skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
1767 replaces[Anum_pg_subscription_subskiplsn - 1] =
true;
1769 update_tuple =
true;
1774 elog(
ERROR,
"unrecognized ALTER SUBSCRIPTION kind %d",
1798 if (update_failover || update_two_phase || check_pub_rdt)
1800 bool must_use_password;
1813 true,
true, must_use_password, sub->
name,
1817 (
errcode(ERRCODE_CONNECTION_FAILURE),
1818 errmsg(
"subscription \"%s\" could not connect to the publisher: %s",
1823 if (retain_dead_tuples)
1827 retain_dead_tuples, origin, NULL, 0,
1830 if (update_failover || update_two_phase)
1832 update_failover ? &
opts.failover : NULL,
1833 update_two_phase ? &
opts.twophase : NULL);
1877 bool must_use_password;
1894 if (!
stmt->missing_ok)
1896 (
errcode(ERRCODE_UNDEFINED_OBJECT),
1897 errmsg(
"subscription \"%s\" does not exist",
1901 (
errmsg(
"subscription \"%s\" does not exist, skipping",
1909 subowner = form->subowner;
1910 must_use_password = !
superuser_arg(subowner) && form->subpasswordrequired;
1928 Anum_pg_subscription_subname);
1933 Anum_pg_subscription_subconninfo);
1938 Anum_pg_subscription_subslotname, &isnull);
1983 foreach(lc, subworkers)
2011 foreach(lc, rstates)
2028 sizeof(originname));
2052 if (!slotname && rstates ==
NIL)
2090 foreach(lc, rstates)
2111 if (rstate->
state != SUBREL_STATE_SYNCDONE)
2116 sizeof(syncslotname));
2168 (
errmsg(
"dropped replication slot \"%s\" on publisher",
2173 res->
sqlstate == ERRCODE_UNDEFINED_OBJECT)
2177 (
errmsg(
"could not drop replication slot \"%s\" on publisher: %s",
2178 slotname, res->
err)));
2184 (
errcode(ERRCODE_CONNECTION_FAILURE),
2185 errmsg(
"could not drop replication slot \"%s\" on publisher: %s",
2186 slotname, res->
err)));
2209 if (form->subowner == newOwnerId)
2220 if (!form->subpasswordrequired && !
superuser())
2222 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2223 errmsg(
"password_required=false is superuser-only"),
2224 errhint(
"Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
2242 form->subowner = newOwnerId;
2277 (
errcode(ERRCODE_UNDEFINED_OBJECT),
2278 errmsg(
"subscription \"%s\" does not exist",
name)));
2309 (
errcode(ERRCODE_UNDEFINED_OBJECT),
2310 errmsg(
"subscription with OID %u does not exist", subid)));
2344 bool copydata,
bool retain_dead_tuples,
2345 char *origin,
Oid *subrel_local_oids,
2346 int subrel_count,
char *
subname)
2351 Oid tableRow[1] = {TEXTOID};
2355 bool check_table_sync;
2356 bool origin_none = origin &&
2364 check_rdt = retain_dead_tuples && !origin_none;
2370 check_table_sync = copydata && origin_none;
2373 Assert(!(check_rdt && check_table_sync));
2376 if (!check_rdt && !check_table_sync)
2381 "SELECT DISTINCT P.pubname AS pubname\n"
2382 "FROM pg_publication P,\n"
2383 " LATERAL pg_get_publication_tables(P.pubname) GPT\n"
2384 " JOIN pg_subscription_rel PS ON (GPT.relid = PS.srrelid OR"
2385 " GPT.relid IN (SELECT relid FROM pg_partition_ancestors(PS.srrelid) UNION"
2386 " SELECT relid FROM pg_partition_tree(PS.srrelid))),\n"
2387 " pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace)\n"
2388 "WHERE C.oid = GPT.relid AND P.pubname IN (");
2401 if (check_table_sync)
2403 for (
i = 0;
i < subrel_count;
i++)
2405 Oid relid = subrel_local_oids[
i];
2409 appendStringInfo(&cmd,
"AND NOT (N.nspname = '%s' AND C.relname = '%s')\n",
2410 schemaname, tablename);
2419 (
errcode(ERRCODE_CONNECTION_FAILURE),
2420 errmsg(
"could not receive list of replicated tables from the publisher: %s",
2457 if (check_table_sync)
2459 appendStringInfo(err_msg,
_(
"subscription \"%s\" requested copy_data with origin = NONE but might copy data that had a different origin"),
2461 appendStringInfoString(err_hint,
_(
"Verify that initial data copied from the publisher tables did not come from other origins."));
2465 appendStringInfo(err_msg,
_(
"subscription \"%s\" enabled retain_dead_tuples but might not reliably detect conflicts for changes from different origins"),
2471 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2473 errdetail_plural(
"The subscription subscribes to a publication (%s) that contains tables that are written to by other subscriptions.",
2474 "The subscription subscribes to publications (%s) that contain tables that are written to by other subscriptions.",
2498 Oid RecoveryRow[1] = {BOOLOID};
2501 bool remote_in_recovery;
2505 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2506 errmsg(
"cannot enable retain_dead_tuples if the publisher is running a version earlier than PostgreSQL 19"));
2512 (
errcode(ERRCODE_CONNECTION_FAILURE),
2513 errmsg(
"could not obtain recovery progress from the publisher: %s",
2518 elog(
ERROR,
"failed to fetch tuple for the recovery progress");
2522 if (remote_in_recovery)
2524 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2525 errmsg(
"cannot enable retain_dead_tuples if the publisher is in recovery."));
2557 int elevel_for_sub_disabled,
2558 bool retain_dead_tuples,
bool retention_active,
2559 bool max_retention_set)
2562 elevel_for_sub_disabled ==
WARNING);
2564 if (retain_dead_tuples)
2568 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2569 errmsg(
"\"wal_level\" is insufficient to create the replication slot required by retain_dead_tuples"),
2570 errhint(
"\"wal_level\" must be set to \"replica\" or \"logical\" at server start."));
2574 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2575 errmsg(
"commit timestamp and origin data required for detecting conflicts won't be retained"),
2576 errhint(
"Consider setting \"%s\" to true.",
2577 "track_commit_timestamp"));
2579 if (sub_disabled && retention_active)
2580 ereport(elevel_for_sub_disabled,
2581 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2582 errmsg(
"deleted rows to detect conflicts would not be removed until the subscription is enabled"),
2583 (elevel_for_sub_disabled >
NOTICE)
2584 ?
errhint(
"Consider setting %s to false.",
2585 "retain_dead_tuples") : 0);
2587 else if (max_retention_set)
2590 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2591 errmsg(
"max_retention_duration is ineffective when retain_dead_tuples is disabled"));
2624 tableRow[2] = INT2VECTOROID;
2640 " FROM pg_class c\n"
2641 " JOIN pg_namespace n ON n.oid = c.relnamespace\n"
2642 " JOIN ( SELECT (pg_get_publication_tables(VARIADIC array_agg(pubname::text))).*\n"
2643 " FROM pg_publication\n"
2644 " WHERE pubname IN ( %s )) AS gpt\n"
2645 " ON gpt.relid = c.oid\n",
2650 tableRow[2] = NAMEARRAYOID;
2654 if (check_columnlist)
2658 " WHERE t.pubname IN ( %s )",
2669 (
errcode(ERRCODE_CONNECTION_FAILURE),
2670 errmsg(
"could not receive list of replicated tables from the publisher: %s",
2689 if (check_columnlist &&
list_member(tablelist, rv))
2691 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2692 errmsg(
"cannot use different column lists for table \"%s.%s\" in different publications",
2695 tablelist =
lappend(tablelist, rv);
2716 foreach(lc, rstates)
2729 if (rstate->
state != SUBREL_STATE_SYNCDONE)
2734 sizeof(syncslotname));
2735 elog(
WARNING,
"could not drop tablesync replication slot \"%s\"",
2741 (
errcode(ERRCODE_CONNECTION_FAILURE),
2742 errmsg(
"could not connect to publisher when attempting to drop replication slot \"%s\": %s",
2745 errhint(
"Use %s to disable the subscription, and then use %s to disassociate it from the slot.",
2746 "ALTER SUBSCRIPTION ... DISABLE",
2747 "ALTER SUBSCRIPTION ... SET (slot_name = NONE)")));
2761 foreach(cell, publist)
2766 foreach(pcell, publist)
2773 if (strcmp(
name, pname) == 0)
2776 errmsg(
"publication name \"%s\" used more than once",
2804 foreach(lc, newpublist)
2810 foreach(lc2, oldpublist)
2814 if (strcmp(
name, pubname) == 0)
2820 errmsg(
"publication \"%s\" is already in subscription \"%s\"",
2829 if (addpub && !found)
2831 else if (!addpub && !found)
2833 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2834 errmsg(
"publication \"%s\" is not in subscription \"%s\"",
2844 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2845 errmsg(
"cannot drop all the publications from a subscription")));
2861 return LOGICALREP_STREAM_ON;
2872 return LOGICALREP_STREAM_OFF;
2874 return LOGICALREP_STREAM_ON;
2890 return LOGICALREP_STREAM_OFF;
2893 return LOGICALREP_STREAM_ON;
2895 return LOGICALREP_STREAM_PARALLEL;
2901 (
errcode(ERRCODE_SYNTAX_ERROR),
2902 errmsg(
"%s requires a Boolean value or \"parallel\"",
2904 return LOGICALREP_STREAM_OFF;
bool has_privs_of_role(Oid member, Oid role)
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)
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
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 OidIsValid(objectId)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
bool track_commit_timestamp
int32 defGetInt32(DefElem *def)
char * defGetString(DefElem *def)
bool defGetBoolean(DefElem *def)
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
void load_file(const char *filename, bool restricted)
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
int errmsg_internal(const char *fmt,...)
int errdetail(const char *fmt,...)
int errhint_internal(const char *fmt,...)
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void err(int eval, const char *fmt,...)
void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
void CheckSubscriptionRelkind(char relkind, const char *nspname, const char *relname)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsMinimalTuple
#define DirectFunctionCall1(func, arg1)
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Assert(PointerIsAligned(start, uint64))
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, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
if(TABLE==NULL||TABLE_index==NULL)
List * logicalrep_workers_find(Oid subid, bool only_running, bool acquire_lock)
void logicalrep_worker_stop(Oid subid, Oid relid)
void ApplyLauncherWakeupAtCommit(void)
void ApplyLauncherForgetWorkerStartTime(Oid subid)
List * lappend(List *list, void *datum)
List * list_delete(List *list, void *datum)
List * list_append_unique(List *list, void *datum)
List * list_copy(const List *oldlist)
void list_free(List *list)
bool list_member(const List *list, const void *datum)
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
#define AccessExclusiveLock
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_namespace_name(Oid nspid)
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
char * pstrdup(const char *in)
void pfree(void *pointer)
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
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)
RepOriginId replorigin_by_name(const char *roname, bool missing_ok)
RepOriginId replorigin_create(const char *roname)
XLogRecPtr replorigin_get_progress(RepOriginId node, bool flush)
void replorigin_drop_by_name(const char *name, bool missing_ok, bool nowait)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
@ ALTER_SUBSCRIPTION_ENABLED
@ ALTER_SUBSCRIPTION_DROP_PUBLICATION
@ ALTER_SUBSCRIPTION_SET_PUBLICATION
@ ALTER_SUBSCRIPTION_REFRESH
@ ALTER_SUBSCRIPTION_SKIP
@ ALTER_SUBSCRIPTION_OPTIONS
@ ALTER_SUBSCRIPTION_CONNECTION
@ ALTER_SUBSCRIPTION_ADD_PUBLICATION
static AmcheckOptions opts
static int server_version
static int list_length(const List *l)
#define foreach_delete_current(lst, var_or_cell)
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)
List * GetSubscriptionRelations(Oid subid, bool not_ready)
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)
Subscription * GetSubscription(Oid subid, bool missing_ok)
FormData_pg_subscription * Form_pg_subscription
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 Datum PointerGetDatum(const void *X)
static Name DatumGetName(Datum X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static Datum CStringGetDatum(const char *X)
static Datum Int32GetDatum(int32 X)
static Datum CharGetDatum(char X)
#define RelationGetDescr(relation)
const char * quote_identifier(const char *ident)
bool ReplicationSlotValidateName(const char *name, bool allow_reserved_name, int elevel)
#define ERRCODE_DUPLICATE_OBJECT
void destroyStringInfo(StringInfo str)
StringInfo makeStringInfo(void)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
char * synchronous_commit
Tuplestorestate * tuplestore
void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
char defGetStreamingMode(DefElem *def)
#define SUBOPT_CREATE_SLOT
#define SUBOPT_PASSWORD_REQUIRED
ObjectAddress CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, bool isTopLevel)
#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 void parse_subscription_options(ParseState *pstate, List *stmt_options, bits32 supported_opts, SubOpts *opts)
static void check_publications(WalReceiverConn *wrconn, List *publications)
#define SUBOPT_RUN_AS_OWNER
static void check_publications_origin(WalReceiverConn *wrconn, List *publications, bool copydata, bool retain_dead_tuples, char *origin, Oid *subrel_local_oids, int subrel_count, char *subname)
#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
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 AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId)
void ReplicationSlotDropAtPubNode(WalReceiverConn *wrconn, char *slotname, bool missing_ok)
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)
static List * fetch_table_list(WalReceiverConn *wrconn, List *publications)
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)
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
#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 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)
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
#define LSN_FORMAT_ARGS(lsn)
#define XLogRecPtrIsInvalid(r)
#define InvalidXLogRecPtr