| 9142 | */ |
| 9143 | |
| 9144 | static void |
| 9145 | ATPrepSetNotNull(List **wqueue, Relation rel, |
| 9146 | AlterTableCmd *cmd, bool recurse, bool recursing, |
| 9147 | LOCKMODE lockmode, AlterTableUtilityContext *context) |
| 9148 | { |
| 9149 | /* |
| 9150 | * If we're already recursing, there's nothing to do; the topmost |
| 9151 | * invocation of ATSimpleRecursion already visited all children. |
| 9152 | */ |
| 9153 | if (recursing) |
| 9154 | return; |
| 9155 | |
| 9156 | /* |
| 9157 | * If the target column is already marked NOT NULL, we can skip recursing |
| 9158 | * to children, because their columns should already be marked NOT NULL as |
| 9159 | * well. But there's no point in checking here unless the relation has |
| 9160 | * some children; else we can just wait till execution to check. (If it |
| 9161 | * does have children, however, this can save taking per-child locks |
| 9162 | * unnecessarily. This greatly improves concurrency in some parallel |
| 9163 | * restore scenarios.) |
| 9164 | * |
| 9165 | * Unfortunately, we can only apply this optimization to partitioned |
| 9166 | * tables, because traditional inheritance doesn't enforce that child |
| 9167 | * columns be NOT NULL when their parent is. (That's a bug that should |
| 9168 | * get fixed someday.) |
| 9169 | */ |
| 9170 | if (rel->rd_rel->relhassubclass && |
| 9171 | rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) |
| 9172 | { |
| 9173 | HeapTuple tuple; |
| 9174 | bool attnotnull; |
| 9175 | |
| 9176 | tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name); |
| 9177 | |
| 9178 | /* Might as well throw the error now, if name is bad */ |
| 9179 | if (!HeapTupleIsValid(tuple)) |
| 9180 | ereport(ERROR, |
| 9181 | (errcode(ERRCODE_UNDEFINED_COLUMN), |
| 9182 | errmsg("column \"%s\" of relation \"%s\" does not exist", |
| 9183 | cmd->name, RelationGetRelationName(rel)))); |
| 9184 | |
| 9185 | attnotnull = ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull; |
| 9186 | ReleaseSysCache(tuple); |
| 9187 | if (attnotnull) |
| 9188 | return; |
| 9189 | } |
| 9190 | |
| 9191 | /* |
| 9192 | * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table, |
| 9193 | * apply ALTER TABLE ... CHECK NOT NULL to every child. Otherwise, use |
| 9194 | * normal recursion logic. |
| 9195 | */ |
| 9196 | if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && |
| 9197 | !recurse) |
| 9198 | { |
| 9199 | AlterTableCmd *newcmd = makeNode(AlterTableCmd); |
| 9200 | |
| 9201 | newcmd->subtype = AT_CheckNotNull; |
no test coverage detected