AlterTableCmd *cmd, LOCKMODE lockmode);
static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype,
Relation rel, AttrNumber attnum, const char *colName);
+static void RememberWholeRowDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel);
static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
*/
RememberAllDependentForRebuilding(tab, AT_SetExpression, rel, attnum, colName);
+ /*
+ * Find whole-row referenced objects that depend on the column
+ * (constraints, indexes, etc.), and record enough information to let us
+ * recreate the objects.
+ */
+ RememberWholeRowDependentForRebuilding(tab, AT_SetExpression, rel);
+
/*
* Drop the dependency records of the GENERATED expression, in particular
* its INTERNAL dependency on the column, which would otherwise cause
table_close(depRel, NoLock);
}
+/*
+ * Record information about dependencies between objects with whole-row Var
+ * references (indexes, check constraints, etc.) and the relation.
+ *
+ * See also RememberAllDependentForRebuilding, which handles non-whole-row Var
+ * references.
+ *
+ * This function currently applies only to ALTER COLUMN SET EXPRESSION.
+ */
+static void
+RememberWholeRowDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel)
+{
+ ScanKeyData skey;
+ Relation pg_constraint;
+ Relation pg_index;
+ SysScanDesc conscan;
+ SysScanDesc indscan;
+ HeapTuple constrTuple;
+ HeapTuple indexTuple;
+ bool isnull;
+
+ Assert(subtype == AT_SetExpression);
+
+ /*
+ * Check CHECK constraints with whole-row references first.
+ */
+ if (RelationGetDescr(rel)->constr &&
+ RelationGetDescr(rel)->constr->num_check > 0)
+ {
+ pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_constraint_conrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+
+ conscan = systable_beginscan(pg_constraint,
+ ConstraintRelidTypidNameIndexId,
+ true,
+ NULL,
+ 1,
+ &skey);
+
+ while (HeapTupleIsValid(constrTuple = systable_getnext(conscan)))
+ {
+ Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(constrTuple);
+ Datum exprDatum;
+
+ if (conform->contype != CONSTRAINT_CHECK)
+ continue;
+
+ exprDatum = heap_getattr(constrTuple,
+ Anum_pg_constraint_conbin,
+ RelationGetDescr(pg_constraint),
+ &isnull);
+ if (isnull)
+ elog(ERROR, "null conbin for relation \"%s\"",
+ RelationGetRelationName(rel));
+ else
+ {
+ char *exprString;
+ Node *expr;
+ Bitmapset *expr_attrs = NULL;
+
+ exprString = TextDatumGetCString(exprDatum);
+ expr = stringToNode(exprString);
+ pfree(exprString);
+
+ /* Find all attributes referenced */
+ pull_varattnos(expr, 1, &expr_attrs);
+
+ /*
+ * If the CHECK constraint contains whole-row reference then
+ * remember it.
+ */
+ if (bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber, expr_attrs))
+ {
+ RememberConstraintForRebuilding(conform->oid, tab);
+ }
+ }
+ }
+ systable_endscan(conscan);
+ table_close(pg_constraint, AccessShareLock);
+ }
+
+ /*
+ * Now check indexes with whole-row references. Prepare to scan pg_index
+ * for entries having indrelid matching this relation.
+ */
+ ScanKeyInit(&skey,
+ Anum_pg_index_indrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+
+ pg_index = table_open(IndexRelationId, AccessShareLock);
+
+ indscan = systable_beginscan(pg_index,
+ IndexIndrelidIndexId,
+ true,
+ NULL,
+ 1,
+ &skey);
+
+ while (HeapTupleIsValid(indexTuple = systable_getnext(indscan)))
+ {
+ Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
+ Datum exprDatum;
+
+ exprDatum = heap_getattr(indexTuple,
+ Anum_pg_index_indexprs,
+ RelationGetDescr(pg_index),
+ &isnull);
+ if (!isnull)
+ {
+ char *exprString;
+ Node *expr;
+ Bitmapset *expr_attrs = NULL;
+
+ exprString = TextDatumGetCString(exprDatum);
+ expr = stringToNode(exprString);
+ pfree(exprString);
+
+ /* Find all attributes referenced */
+ pull_varattnos(expr, 1, &expr_attrs);
+
+ /*
+ * If the index expression contains a whole-row reference then
+ * remember it.
+ */
+ if (bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber, expr_attrs))
+ {
+ RememberIndexForRebuilding(index->indexrelid, tab);
+ continue;
+ }
+ }
+
+ exprDatum = heap_getattr(indexTuple,
+ Anum_pg_index_indpred,
+ RelationGetDescr(pg_index),
+ &isnull);
+ if (!isnull)
+ {
+ char *exprString;
+ Node *expr;
+ Bitmapset *expr_attrs = NULL;
+
+ exprString = TextDatumGetCString(exprDatum);
+ expr = stringToNode(exprString);
+ pfree(exprString);
+
+ /* Find all attributes referenced */
+ pull_varattnos(expr, 1, &expr_attrs);
+
+ /*
+ * If the index predicate expression contains a whole-row
+ * reference then remember it.
+ */
+ if (bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber, expr_attrs))
+ {
+ RememberIndexForRebuilding(index->indexrelid, tab);
+ }
+ }
+ }
+
+ systable_endscan(indscan);
+ table_close(pg_index, AccessShareLock);
+}
+
/*
* Subroutine for ATExecAlterColumnType: remember that a replica identity
* needs to be reset.