* 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.
return topmost_relid;
}
+/*
+ * 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.
*/
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);
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));
/* 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;
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);
}
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));
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;
}
/*
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);
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
* 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))