about set_attnotnull. we can make set_attnotnull look less recursive. instead of calling find_inheritance_children, let's just one pass, directly call find_all_inheritors overall, I think it would be more intuitive.
please check the attached refactored set_attnotnull. regress test passed, i only test regress. I am also beginning to wonder if ATExecSetNotNull inside can also call find_all_inheritors.
static void set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, LOCKMODE lockmode) { HeapTuple tuple; Form_pg_attribute attForm; bool changed = false; tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, RelationGetRelid(rel)); attForm = (Form_pg_attribute) GETSTRUCT(tuple); if (!attForm->attnotnull) { Relation attr_rel; attr_rel = table_open(AttributeRelationId, RowExclusiveLock); attForm->attnotnull = true; CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); table_close(attr_rel, RowExclusiveLock); /* * And set up for existing values to be checked, unless another * constraint already proves this. */ if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm)) { AlteredTableInfo *tab; tab = ATGetQueueEntry(wqueue, rel); tab->verify_new_notnull = true; } changed = true; } if (recurse) { List *child_oids; Relation childrel; AttrNumber childattno; HeapTuple rel_tuple; Form_pg_attribute child_attForm; const char *attrname; attrname = get_attname(RelationGetRelid(rel), attnum, false); child_oids = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL); if (changed) CommandCounterIncrement(); foreach_oid(childrelid, child_oids) { /* we alerady dealt with parent rel in above */ if (childrelid == RelationGetRelid(rel)) continue; childrel = table_open(childrelid, NoLock); CheckAlterTableIsSafe(childrel); childattno = get_attnum(childrelid, attrname); rel_tuple = SearchSysCacheCopyAttNum(childrelid, childattno); if (!HeapTupleIsValid(rel_tuple)) elog(ERROR, "cache lookup failed for attribute %d of relation %s", attnum, RelationGetRelationName(childrel)); child_attForm = (Form_pg_attribute) GETSTRUCT(rel_tuple); if (!child_attForm->attnotnull) { Relation attr_rel; attr_rel = table_open(AttributeRelationId, RowExclusiveLock); child_attForm->attnotnull = true; CatalogTupleUpdate(attr_rel, &rel_tuple->t_self, rel_tuple); table_close(attr_rel, RowExclusiveLock); if (wqueue && !NotNullImpliedByRelConstraints(childrel, child_attForm)) { AlteredTableInfo *tab; tab = ATGetQueueEntry(wqueue, childrel); tab->verify_new_notnull = true; } changed = true; } changed = false; table_close(childrel, NoLock); } } }