aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_publication.c110
-rw-r--r--src/backend/commands/publicationcmds.c22
-rw-r--r--src/backend/commands/subscriptioncmds.c2
-rw-r--r--src/include/catalog/pg_publication.h1
-rw-r--r--src/test/regress/expected/publication.out7
-rw-r--r--src/test/regress/sql/publication.sql4
6 files changed, 66 insertions, 80 deletions
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 0602398a545..7fe5fe2b86c 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -48,9 +48,6 @@ typedef struct
* table. */
} published_rel;
-static void publication_translate_columns(Relation targetrel, List *columns,
- int *natts, AttrNumber **attrs);
-
/*
* Check if relation can be in given publication and throws appropriate
* error if not.
@@ -352,6 +349,33 @@ GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level
}
/*
+ * attnumstoint2vector
+ * Convert a Bitmapset of AttrNumbers into an int2vector.
+ *
+ * AttrNumber numbers are 0-based, i.e., not offset by
+ * FirstLowInvalidHeapAttributeNumber.
+ */
+static int2vector *
+attnumstoint2vector(Bitmapset *attrs)
+{
+ int2vector *result;
+ int n = bms_num_members(attrs);
+ int i = -1;
+ int j = 0;
+
+ result = buildint2vector(NULL, n);
+
+ while ((i = bms_next_member(attrs, i)) >= 0)
+ {
+ Assert(i <= PG_INT16_MAX);
+
+ result->values[j++] = (int16) i;
+ }
+
+ return result;
+}
+
+/*
* Insert new publication / relation mapping.
*/
ObjectAddress
@@ -365,12 +389,12 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
Relation targetrel = pri->relation;
Oid relid = RelationGetRelid(targetrel);
Oid pubreloid;
+ Bitmapset *attnums;
Publication *pub = GetPublication(pubid);
- AttrNumber *attarray = NULL;
- int natts = 0;
ObjectAddress myself,
referenced;
List *relids = NIL;
+ int i;
rel = table_open(PublicationRelRelationId, RowExclusiveLock);
@@ -395,13 +419,8 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
check_publication_add_relation(targetrel);
- /*
- * Translate column names to attnums and make sure the column list
- * contains only allowed elements (no system or generated columns etc.).
- * Also build an array of attnums, for storing in the catalog.
- */
- publication_translate_columns(pri->relation, pri->columns,
- &natts, &attarray);
+ /* Validate and translate column names into a Bitmapset of attnums. */
+ attnums = pub_collist_validate(pri->relation, pri->columns);
/* Form a tuple. */
memset(values, 0, sizeof(values));
@@ -423,7 +442,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
/* Add column list, if available */
if (pri->columns)
- values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(buildint2vector(attarray, natts));
+ values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(attnumstoint2vector(attnums));
else
nulls[Anum_pg_publication_rel_prattrs - 1] = true;
@@ -451,9 +470,10 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
false);
/* Add dependency on the columns, if any are listed */
- for (int i = 0; i < natts; i++)
+ i = -1;
+ while ((i = bms_next_member(attnums, i)) >= 0)
{
- ObjectAddressSubSet(referenced, RelationRelationId, relid, attarray[i]);
+ ObjectAddressSubSet(referenced, RelationRelationId, relid, i);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -476,47 +496,23 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
return myself;
}
-/* qsort comparator for attnums */
-static int
-compare_int16(const void *a, const void *b)
-{
- int av = *(const int16 *) a;
- int bv = *(const int16 *) b;
-
- /* this can't overflow if int is wider than int16 */
- return (av - bv);
-}
-
/*
- * Translate a list of column names to an array of attribute numbers
- * and a Bitmapset with them; verify that each attribute is appropriate
- * to have in a publication column list (no system or generated attributes,
- * no duplicates). Additional checks with replica identity are done later;
- * see pub_collist_contains_invalid_column.
+ * pub_collist_validate
+ * Process and validate the 'columns' list and ensure the columns are all
+ * valid to use for a publication. Checks for and raises an ERROR for
+ * any; unknown columns, system columns, duplicate columns or generated
+ * columns.
*
- * Note that the attribute numbers are *not* offset by
- * FirstLowInvalidHeapAttributeNumber; system columns are forbidden so this
- * is okay.
+ * Looks up each column's attnum and returns a 0-based Bitmapset of the
+ * corresponding attnums.
*/
-static void
-publication_translate_columns(Relation targetrel, List *columns,
- int *natts, AttrNumber **attrs)
+Bitmapset *
+pub_collist_validate(Relation targetrel, List *columns)
{
- AttrNumber *attarray = NULL;
Bitmapset *set = NULL;
ListCell *lc;
- int n = 0;
TupleDesc tupdesc = RelationGetDescr(targetrel);
- /* Bail out when no column list defined. */
- if (!columns)
- return;
-
- /*
- * Translate list of columns to attnums. We prohibit system attributes and
- * make sure there are no duplicate columns.
- */
- attarray = palloc(sizeof(AttrNumber) * list_length(columns));
foreach(lc, columns)
{
char *colname = strVal(lfirst(lc));
@@ -547,16 +543,9 @@ publication_translate_columns(Relation targetrel, List *columns,
colname));
set = bms_add_member(set, attnum);
- attarray[n++] = attnum;
}
- /* Be tidy, so that the catalog representation is always sorted */
- qsort(attarray, n, sizeof(AttrNumber), compare_int16);
-
- *natts = n;
- *attrs = attarray;
-
- bms_free(set);
+ return set;
}
/*
@@ -569,19 +558,12 @@ publication_translate_columns(Relation targetrel, List *columns,
Bitmapset *
pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
{
- Bitmapset *result = NULL;
+ Bitmapset *result = columns;
ArrayType *arr;
int nelems;
int16 *elems;
MemoryContext oldcxt = NULL;
- /*
- * If an existing bitmap was provided, use it. Otherwise just use NULL and
- * build a new bitmap.
- */
- if (columns)
- result = columns;
-
arr = DatumGetArrayTypeP(pubcols);
nelems = ARR_DIMS(arr)[0];
elems = (int16 *) ARR_DATA_PTR(arr);
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 6ea709988ee..d6ffef374ea 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -1176,21 +1176,13 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
newrelid = RelationGetRelid(newpubrel->relation);
/*
- * If the new publication has column list, transform it to a
- * bitmap too.
+ * Validate the column list. If the column list or WHERE
+ * clause changes, then the validation done here will be
+ * duplicated inside PublicationAddTables(). The validation
+ * is cheap enough that that seems harmless.
*/
- if (newpubrel->columns)
- {
- ListCell *lc;
-
- foreach(lc, newpubrel->columns)
- {
- char *colname = strVal(lfirst(lc));
- AttrNumber attnum = get_attnum(newrelid, colname);
-
- newcolumns = bms_add_member(newcolumns, attnum);
- }
- }
+ newcolumns = pub_collist_validate(newpubrel->relation,
+ newpubrel->columns);
/*
* Check if any of the new set of relations matches with the
@@ -1199,7 +1191,7 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
* expressions also match. Same for the column list. Drop the
* rest.
*/
- if (RelationGetRelid(newpubrel->relation) == oldrelid)
+ if (newrelid == oldrelid)
{
if (equal(oldrelwhereclause, newpubrel->whereClause) &&
bms_equal(oldcolumns, newcolumns))
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index d124bfe55ca..b925c464ae6 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -2266,7 +2266,7 @@ fetch_table_list(WalReceiverConn *wrconn, List *publications)
*
* Note that attrs are always stored in sorted order so we don't need
* to worry if different publications have specified them in a
- * different order. See publication_translate_columns.
+ * different order. See pub_collist_validate.
*/
appendStringInfo(&cmd, "SELECT DISTINCT n.nspname, c.relname, gpt.attrs\n"
" FROM pg_class c\n"
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index 2f1b6abbfa7..d9518a58b00 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -152,6 +152,7 @@ extern bool is_publishable_relation(Relation rel);
extern bool is_schema_publication(Oid pubid);
extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri,
bool if_not_exists);
+extern Bitmapset *pub_collist_validate(Relation targetrel, List *columns);
extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid,
bool if_not_exists);
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 30b63711340..660245ed0c4 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -693,6 +693,13 @@ ERROR: cannot use generated column "d" in publication column list
-- error: system attributes "ctid" not allowed in column list
ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, ctid);
ERROR: cannot use system column "ctid" in publication column list
+ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl1 (id, ctid);
+ERROR: cannot use system column "ctid" in publication column list
+-- error: duplicates not allowed in column list
+ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, a);
+ERROR: duplicate column "a" in publication column list
+ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl5 (a, a);
+ERROR: duplicate column "a" in publication column list
-- ok
ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, c);
ALTER TABLE testpub_tbl5 DROP COLUMN c; -- no dice
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 479d4f32644..f68a5b59862 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -417,6 +417,10 @@ ALTER PUBLICATION testpub_fortable DROP TABLE testpub_tbl5;
ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, d);
-- error: system attributes "ctid" not allowed in column list
ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, ctid);
+ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl1 (id, ctid);
+-- error: duplicates not allowed in column list
+ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, a);
+ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl5 (a, a);
-- ok
ALTER PUBLICATION testpub_fortable ADD TABLE testpub_tbl5 (a, c);
ALTER TABLE testpub_tbl5 DROP COLUMN c; -- no dice