aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/func.sgml1
-rw-r--r--src/backend/catalog/catalog.c2
-rw-r--r--src/backend/replication/logical/origin.c23
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_replication_origin.h2
-rw-r--r--src/include/replication/origin.h7
-rw-r--r--src/test/regress/expected/misc_functions.out4
-rw-r--r--src/test/regress/expected/misc_sanity.out8
-rw-r--r--src/test/regress/sql/misc_functions.sql3
-rw-r--r--src/test/regress/sql/misc_sanity.sql5
10 files changed, 51 insertions, 6 deletions
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index bb6e5ab9ff7..27ec46105f4 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -29940,6 +29940,7 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
<para>
Creates a replication origin with the given external
name, and returns the internal ID assigned to it.
+ The name must be no longer than 512 bytes.
</para></entry>
</row>
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 60000bd0bc7..59caae8f1bc 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -346,8 +346,6 @@ IsSharedRelation(Oid relationId)
relationId == PgDbRoleSettingToastIndex ||
relationId == PgParameterAclToastTable ||
relationId == PgParameterAclToastIndex ||
- relationId == PgReplicationOriginToastTable ||
- relationId == PgReplicationOriginToastIndex ||
relationId == PgShdescriptionToastTable ||
relationId == PgShdescriptionToastIndex ||
relationId == PgShseclabelToastTable ||
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 6583dd497da..a17bacf88e7 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -264,6 +264,18 @@ replorigin_create(const char *roname)
SysScanDesc scan;
ScanKeyData key;
+ /*
+ * To avoid needing a TOAST table for pg_replication_origin, we limit
+ * replication origin names to 512 bytes. This should be more than enough
+ * for all practical use.
+ */
+ if (strlen(roname) > MAX_RONAME_LEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("replication origin name is too long"),
+ errdetail("Replication origin names must be no longer than %d bytes.",
+ MAX_RONAME_LEN)));
+
roname_d = CStringGetTextDatum(roname);
Assert(IsTransactionState());
@@ -287,6 +299,17 @@ replorigin_create(const char *roname)
rel = table_open(ReplicationOriginRelationId, ExclusiveLock);
+ /*
+ * We want to be able to access pg_replication_origin without setting up a
+ * snapshot. To make that safe, it needs to not have a TOAST table, since
+ * TOASTed data cannot be fetched without a snapshot. As of this writing,
+ * its only varlena column is roname, which we limit to 512 bytes to avoid
+ * needing out-of-line storage. If you add a TOAST table to this catalog,
+ * be sure to set up a snapshot everywhere it might be needed. For more
+ * information, see https://postgr.es/m/ZvMSUPOqUU-VNADN%40nathan.
+ */
+ Assert(!OidIsValid(rel->rd_rel->reltoastrelid));
+
for (roident = InvalidOid + 1; roident < PG_UINT16_MAX; roident++)
{
bool nulls[Natts_pg_replication_origin];
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3cb695d233c..82988d24433 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202504091
+#define CATALOG_VERSION_NO 202505071
#endif
diff --git a/src/include/catalog/pg_replication_origin.h b/src/include/catalog/pg_replication_origin.h
index deb43065fe9..7ade8bbda39 100644
--- a/src/include/catalog/pg_replication_origin.h
+++ b/src/include/catalog/pg_replication_origin.h
@@ -54,8 +54,6 @@ CATALOG(pg_replication_origin,6000,ReplicationOriginRelationId) BKI_SHARED_RELAT
typedef FormData_pg_replication_origin *Form_pg_replication_origin;
-DECLARE_TOAST_WITH_MACRO(pg_replication_origin, 4181, 4182, PgReplicationOriginToastTable, PgReplicationOriginToastIndex);
-
DECLARE_UNIQUE_INDEX_PKEY(pg_replication_origin_roiident_index, 6001, ReplicationOriginIdentIndex, pg_replication_origin, btree(roident oid_ops));
DECLARE_UNIQUE_INDEX(pg_replication_origin_roname_index, 6002, ReplicationOriginNameIndex, pg_replication_origin, btree(roname text_ops));
diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h
index 9cb2248fa9f..2a73f6aa492 100644
--- a/src/include/replication/origin.h
+++ b/src/include/replication/origin.h
@@ -33,6 +33,13 @@ typedef struct xl_replorigin_drop
#define InvalidRepOriginId 0
#define DoNotReplicateId PG_UINT16_MAX
+/*
+ * To avoid needing a TOAST table for pg_replication_origin, we limit
+ * replication origin names to 512 bytes. This should be more than enough for
+ * all practical use.
+ */
+#define MAX_RONAME_LEN 512
+
extern PGDLLIMPORT RepOriginId replorigin_session_origin;
extern PGDLLIMPORT XLogRecPtr replorigin_session_origin_lsn;
extern PGDLLIMPORT TimestampTz replorigin_session_origin_timestamp;
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index d3f5d16a672..cc517ed5e90 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -914,3 +914,7 @@ SELECT test_relpath();
(1 row)
+-- pg_replication_origin.roname limit
+SELECT pg_replication_origin_create('regress_' || repeat('a', 505));
+ERROR: replication origin name is too long
+DETAIL: Replication origin names must be no longer than 512 bytes.
diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out
index b032a3f4761..4ffc45a8018 100644
--- a/src/test/regress/expected/misc_sanity.out
+++ b/src/test/regress/expected/misc_sanity.out
@@ -42,6 +42,11 @@ WHERE refclassid = 0 OR refobjid = 0 OR
-- as user data by pg_upgrade, which would cause failures.
-- 3. pg_authid, since its toast table cannot be accessed when it would be
-- needed, i.e., during authentication before we've selected a database.
+-- 4. pg_replication_origin, since we want to be able to access that catalog
+-- without setting up a snapshot. To make that safe, it needs to not have a
+-- toast table, since toasted data cannot be fetched without a snapshot. As of
+-- this writing, its only varlena column is roname, which we limit to 512 bytes
+-- to avoid needing out-of-line storage.
SELECT relname, attname, atttypid::regtype
FROM pg_class c JOIN pg_attribute a ON c.oid = attrelid
WHERE c.oid < 16384 AND
@@ -61,7 +66,8 @@ ORDER BY 1, 2;
pg_class | relpartbound | pg_node_tree
pg_largeobject | data | bytea
pg_largeobject_metadata | lomacl | aclitem[]
-(10 rows)
+ pg_replication_origin | roname | text
+(11 rows)
-- system catalogs without primary keys
--
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index aaebb298330..5f9c77512d1 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -411,3 +411,6 @@ CREATE FUNCTION test_relpath()
AS :'regresslib'
LANGUAGE C;
SELECT test_relpath();
+
+-- pg_replication_origin.roname limit
+SELECT pg_replication_origin_create('regress_' || repeat('a', 505));
diff --git a/src/test/regress/sql/misc_sanity.sql b/src/test/regress/sql/misc_sanity.sql
index 135793871b4..e861614ea71 100644
--- a/src/test/regress/sql/misc_sanity.sql
+++ b/src/test/regress/sql/misc_sanity.sql
@@ -45,6 +45,11 @@ WHERE refclassid = 0 OR refobjid = 0 OR
-- as user data by pg_upgrade, which would cause failures.
-- 3. pg_authid, since its toast table cannot be accessed when it would be
-- needed, i.e., during authentication before we've selected a database.
+-- 4. pg_replication_origin, since we want to be able to access that catalog
+-- without setting up a snapshot. To make that safe, it needs to not have a
+-- toast table, since toasted data cannot be fetched without a snapshot. As of
+-- this writing, its only varlena column is roname, which we limit to 512 bytes
+-- to avoid needing out-of-line storage.
SELECT relname, attname, atttypid::regtype
FROM pg_class c JOIN pg_attribute a ON c.oid = attrelid