From 0c4d83efa4b2693db0b7c9125252f6bba95f30f5 Mon Sep 17 00:00:00 2001 From: Rushabh Lathia Date: Mon, 10 Feb 2025 15:39:16 +0530 Subject: [PATCH 1/3] Convert pg_attribut.attnotnull to char type. This commit change the pg_attribut.attnotnull to char type. Now attnotnull holds three values, where attnotnull can be either TRUE, FALSE and INVALID. INVALID is when name not null constrint is NOT VALIDATED. --- src/backend/access/common/tupdesc.c | 12 +++++----- src/backend/bootstrap/bootstrap.c | 13 ++++++----- src/backend/catalog/heap.c | 16 +++++++------- src/backend/catalog/index.c | 2 +- src/backend/catalog/indexing.c | 3 ++- src/backend/catalog/information_schema.sql | 4 ++-- src/backend/commands/tablecmds.c | 35 +++++++++++++++++------------- src/backend/executor/execMain.c | 3 ++- src/backend/jit/llvm/llvmjit_deform.c | 10 +++++---- src/backend/optimizer/util/plancat.c | 5 +++-- src/include/access/tupdesc.h | 2 +- src/include/catalog/pg_attribute.h | 5 ++++- 12 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index ed2195f..5869881 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -251,7 +251,7 @@ CreateTupleDescCopy(TupleDesc tupdesc) { Form_pg_attribute att = TupleDescAttr(desc, i); - att->attnotnull = false; + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->atthasdef = false; att->atthasmissing = false; att->attidentity = '\0'; @@ -297,7 +297,7 @@ CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts) { Form_pg_attribute att = TupleDescAttr(desc, i); - att->attnotnull = false; + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->atthasdef = false; att->atthasmissing = false; att->attidentity = '\0'; @@ -417,7 +417,7 @@ TupleDescCopy(TupleDesc dst, TupleDesc src) { Form_pg_attribute att = TupleDescAttr(dst, i); - att->attnotnull = false; + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->atthasdef = false; att->atthasmissing = false; att->attidentity = '\0'; @@ -463,7 +463,7 @@ TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, dstAtt->attnum = dstAttno; /* since we're not copying constraints or defaults, clear these */ - dstAtt->attnotnull = false; + dstAtt->attnotnull = ATTRIBUTE_NOTNULL_FALSE; dstAtt->atthasdef = false; dstAtt->atthasmissing = false; dstAtt->attidentity = '\0'; @@ -840,7 +840,7 @@ TupleDescInitEntry(TupleDesc desc, att->attnum = attributeNumber; att->attndims = attdim; - att->attnotnull = false; + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->atthasdef = false; att->atthasmissing = false; att->attidentity = '\0'; @@ -903,7 +903,7 @@ TupleDescInitBuiltinEntry(TupleDesc desc, att->attnum = attributeNumber; att->attndims = attdim; - att->attnotnull = false; + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->atthasdef = false; att->atthasmissing = false; att->attidentity = '\0'; diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 359f58a..8b952d8 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -582,14 +582,17 @@ DefineAttr(char *name, char *type, int attnum, int nullness) attrtypes[attnum]->atttypmod = -1; attrtypes[attnum]->attislocal = true; + /* set default to false */ + attrtypes[attnum]->attnotnull = ATTRIBUTE_NOTNULL_FALSE; + if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL) { - attrtypes[attnum]->attnotnull = true; + attrtypes[attnum]->attnotnull = ATTRIBUTE_NOTNULL_TRUE; } else if (nullness == BOOTCOL_NULL_FORCE_NULL) { - attrtypes[attnum]->attnotnull = false; + attrtypes[attnum]->attnotnull = ATTRIBUTE_NOTNULL_FALSE; } else { @@ -608,11 +611,11 @@ DefineAttr(char *name, char *type, int attnum, int nullness) for (i = 0; i < attnum; i++) { if (attrtypes[i]->attlen <= 0 || - !attrtypes[i]->attnotnull) + attrtypes[i]->attnotnull == ATTRIBUTE_NOTNULL_FALSE) break; } if (i == attnum) - attrtypes[attnum]->attnotnull = true; + attrtypes[attnum]->attnotnull = ATTRIBUTE_NOTNULL_TRUE; } } } @@ -696,7 +699,7 @@ InsertOneNull(int i) { elog(DEBUG4, "inserting column %d NULL", i); Assert(i >= 0 && i < MAXATTR); - if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull) + if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull == ATTRIBUTE_NOTNULL_TRUE) elog(ERROR, "NULL value specified for not-null column \"%s\" of relation \"%s\"", NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname), diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 956f196..6dc94e3 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -149,7 +149,7 @@ static const FormData_pg_attribute a1 = { .attbyval = false, .attalign = TYPALIGN_SHORT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -162,7 +162,7 @@ static const FormData_pg_attribute a2 = { .attbyval = true, .attalign = TYPALIGN_INT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -175,7 +175,7 @@ static const FormData_pg_attribute a3 = { .attbyval = true, .attalign = TYPALIGN_INT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -188,7 +188,7 @@ static const FormData_pg_attribute a4 = { .attbyval = true, .attalign = TYPALIGN_INT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -201,7 +201,7 @@ static const FormData_pg_attribute a5 = { .attbyval = true, .attalign = TYPALIGN_INT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -220,7 +220,7 @@ static const FormData_pg_attribute a6 = { .attbyval = true, .attalign = TYPALIGN_INT, .attstorage = TYPSTORAGE_PLAIN, - .attnotnull = true, + .attnotnull = ATTRIBUTE_NOTNULL_TRUE, .attislocal = true, }; @@ -751,7 +751,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign); slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage); slot[slotCount]->tts_values[Anum_pg_attribute_attcompression - 1] = CharGetDatum(attrs->attcompression); - slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull); + slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = CharGetDatum(attrs->attnotnull); slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef); slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing); slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity); @@ -1710,7 +1710,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) attStruct->atttypid = InvalidOid; /* Remove any not-null constraint the column may have */ - attStruct->attnotnull = false; + attStruct->attnotnull = ATTRIBUTE_NOTNULL_FALSE; /* Unset this so no one tries to look up the generation expression */ attStruct->attgenerated = '\0'; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index cdabf78..4417704 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -261,7 +261,7 @@ index_check_primary_key(Relation heapRel, attnum, RelationGetRelid(heapRel)); attform = (Form_pg_attribute) GETSTRUCT(atttuple); - if (!attform->attnotnull) + if (attform->attnotnull == ATTRIBUTE_NOTNULL_FALSE) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("primary key column \"%s\" is not marked NOT NULL", diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 25c4b6b..a2211d7 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -207,7 +207,8 @@ CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup) { Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum); - Assert(!(thisatt->attnotnull && att_isnull(attnum, bp))); + Assert(!(thisatt->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + att_isnull(attnum, bp))); } } } diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index a7bffca..4f59bc4 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -292,7 +292,7 @@ CREATE VIEW attributes AS CAST(a.attname AS sql_identifier) AS attribute_name, CAST(a.attnum AS cardinal_number) AS ordinal_position, CAST(pg_get_expr(ad.adbin, ad.adrelid) AS character_data) AS attribute_default, - CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + CAST(CASE WHEN a.attnotnull = 't' OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END AS yes_or_no) AS is_nullable, -- This column was apparently removed between SQL:2003 and SQL:2008. @@ -671,7 +671,7 @@ CREATE VIEW columns AS CAST(a.attname AS sql_identifier) AS column_name, CAST(a.attnum AS cardinal_number) AS ordinal_position, CAST(CASE WHEN a.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) END AS character_data) AS column_default, - CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + CAST(CASE WHEN a.attnotnull = 't' OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END AS yes_or_no) AS is_nullable, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 5823fce..8fa71ed 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1401,7 +1401,10 @@ BuildDescForRelation(const List *columns) TupleDescInitEntryCollation(desc, attnum, attcollation); /* Fill in additional stuff not handled by TupleDescInitEntry */ - att->attnotnull = entry->is_not_null; + if (entry->is_not_null) + att->attnotnull = ATTRIBUTE_NOTNULL_TRUE; + else + att->attnotnull = ATTRIBUTE_NOTNULL_FALSE; att->attislocal = entry->is_local; att->attinhcount = entry->inhcount; att->attidentity = entry->identity; @@ -6186,7 +6189,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) { Form_pg_attribute attr = TupleDescAttr(newTupDesc, i); - if (attr->attnotnull && !attr->attisdropped) + if (attr->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + !attr->attisdropped) notnull_attrs = lappend_int(notnull_attrs, i); } if (notnull_attrs) @@ -7636,7 +7640,7 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse, RelationGetRelid(rel), attnum); /* If the column is already nullable there's nothing to do. */ - if (!attTup->attnotnull) + if (attTup->attnotnull == ATTRIBUTE_NOTNULL_FALSE) { table_close(attr_rel, RowExclusiveLock); return InvalidObjectAddress; @@ -7666,7 +7670,7 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse, AttrNumber parent_attnum; parent_attnum = get_attnum(parentId, colName); - if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull) + if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull == ATTRIBUTE_NOTNULL_TRUE) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" is marked NOT NULL in parent table", @@ -7720,7 +7724,7 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, if (attr->attisdropped) return; - if (!attr->attnotnull) + if (attr->attnotnull == ATTRIBUTE_NOTNULL_FALSE) { Relation attr_rel; HeapTuple tuple; @@ -7733,8 +7737,8 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, attnum, RelationGetRelid(rel)); attr = (Form_pg_attribute) GETSTRUCT(tuple); - Assert(!attr->attnotnull); - attr->attnotnull = true; + Assert(attr->attnotnull == ATTRIBUTE_NOTNULL_FALSE); + attr->attnotnull = ATTRIBUTE_NOTNULL_TRUE; CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); /* @@ -8140,7 +8144,7 @@ ATExecAddIdentity(Relation rel, const char *colName, * to an existing column that is not NOT NULL would create a state that * cannot be reproduced without contortions. */ - if (!attTup->attnotnull) + if (attTup->attnotnull == ATTRIBUTE_NOTNULL_FALSE) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added", @@ -9342,7 +9346,7 @@ ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd, elog(ERROR, "cache lookup failed for attribute %s of relation %u", attname, childrelid); attrForm = (Form_pg_attribute) GETSTRUCT(tup); - if (!attrForm->attnotnull) + if (attrForm->attnotnull == ATTRIBUTE_NOTNULL_FALSE) ereport(ERROR, errmsg("column \"%s\" of table \"%s\" is not marked NOT NULL", attname, get_rel_name(childrelid))); @@ -13274,9 +13278,9 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha RelationGetRelationName(rel))); /* All good -- reset attnotnull if needed */ - if (attForm->attnotnull) + if (attForm->attnotnull == ATTRIBUTE_NOTNULL_TRUE) { - attForm->attnotnull = false; + attForm->attnotnull = ATTRIBUTE_NOTNULL_FALSE; CatalogTupleUpdate(attrel, &atttup->t_self, atttup); } @@ -16603,7 +16607,8 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispart * * Other constraints are checked elsewhere. */ - if (parent_att->attnotnull && !child_att->attnotnull) + if (parent_att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + child_att->attnotnull == ATTRIBUTE_NOTNULL_FALSE) { HeapTuple contup; @@ -17646,7 +17651,7 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode RelationGetRelationName(indexRel), attno))); attr = TupleDescAttr(rel->rd_att, attno - 1); - if (!attr->attnotnull) + if (attr->attnotnull == ATTRIBUTE_NOTNULL_FALSE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("index \"%s\" cannot be used as replica identity because column \"%s\" is nullable", @@ -19124,7 +19129,7 @@ PartConstraintImpliedByRelConstraint(Relation scanrel, { Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1); - if (att->attnotnull && !att->attisdropped) + if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && !att->attisdropped) { NullTest *ntest = makeNode(NullTest); @@ -20956,7 +20961,7 @@ verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partition) Form_pg_attribute att = TupleDescAttr(RelationGetDescr(partition), iinfo->ii_IndexAttrNumbers[i] - 1); - if (!att->attnotnull) + if (att->attnotnull == ATTRIBUTE_NOTNULL_FALSE) ereport(ERROR, errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("invalid primary key definition"), diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 39d80cc..06688ff 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1966,7 +1966,8 @@ ExecConstraints(ResultRelInfo *resultRelInfo, { Form_pg_attribute att = TupleDescAttr(tupdesc, attrChk - 1); - if (att->attnotnull && slot_attisnull(slot, attrChk)) + if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + slot_attisnull(slot, attrChk)) { char *val_desc; Relation orig_rel = rel; diff --git a/src/backend/jit/llvm/llvmjit_deform.c b/src/backend/jit/llvm/llvmjit_deform.c index 5d169c7..e6444bc 100644 --- a/src/backend/jit/llvm/llvmjit_deform.c +++ b/src/backend/jit/llvm/llvmjit_deform.c @@ -123,7 +123,7 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, * combination of attisdropped && attnotnull combination shouldn't * exist. */ - if (att->attnotnull && + if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && !att->atthasmissing && !att->attisdropped) guaranteed_column_number = attnum; @@ -438,7 +438,7 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, * into account, because if they're present the heaptuple's natts * would have indicated that a slot_getmissingattrs() is needed. */ - if (!att->attnotnull) + if (att->attnotnull == ATTRIBUTE_NOTNULL_FALSE) { LLVMBasicBlockRef b_ifnotnull; LLVMBasicBlockRef b_ifnull; @@ -604,7 +604,8 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, known_alignment = -1; attguaranteedalign = false; } - else if (att->attnotnull && attguaranteedalign && known_alignment >= 0) + else if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + attguaranteedalign && known_alignment >= 0) { /* * If the offset to the column was previously known, a NOT NULL & @@ -614,7 +615,8 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, Assert(att->attlen > 0); known_alignment += att->attlen; } - else if (att->attnotnull && (att->attlen % alignto) == 0) + else if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + (att->attlen % alignto) == 0) { /* * After a NOT NULL fixed-width column with a length that is a diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 71abb01..e322098 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -177,7 +177,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, { CompactAttribute *attr = TupleDescCompactAttr(relation->rd_att, i); - if (attr->attnotnull) + if (attr->attnotnull == ATTRIBUTE_NOTNULL_TRUE) { rel->notnullattnums = bms_add_member(rel->notnullattnums, i + 1); @@ -1355,7 +1355,8 @@ get_relation_constraints(PlannerInfo *root, { Form_pg_attribute att = TupleDescAttr(relation->rd_att, i - 1); - if (att->attnotnull && !att->attisdropped) + if (att->attnotnull == ATTRIBUTE_NOTNULL_TRUE && + !att->attisdropped) { NullTest *ntest = makeNode(NullTest); diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 396eeb7..1eba67c 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -76,7 +76,7 @@ typedef struct CompactAttribute bool atthasmissing; /* as FormData_pg_attribute.atthasmissing */ bool attisdropped; /* as FormData_pg_attribute.attisdropped */ bool attgenerated; /* FormData_pg_attribute.attgenerated != '\0' */ - bool attnotnull; /* as FormData_pg_attribute.attnotnull */ + char attnotnull; /* as FormData_pg_attribute.attnotnull */ uint8 attalignby; /* alignment requirement in bytes */ } CompactAttribute; diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index deaa515..b51a267 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -118,7 +118,7 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75, char attcompression BKI_DEFAULT('\0'); /* This flag represents the "NOT NULL" constraint */ - bool attnotnull; + char attnotnull; /* Has DEFAULT value or not */ bool atthasdef BKI_DEFAULT(f); @@ -227,6 +227,9 @@ MAKE_SYSCACHE(ATTNUM, pg_attribute_relid_attnum_index, 128); #define ATTRIBUTE_GENERATED_STORED 's' #define ATTRIBUTE_GENERATED_VIRTUAL 'v' +#define ATTRIBUTE_NOTNULL_TRUE 't' +#define ATTRIBUTE_NOTNULL_FALSE 'f' + #endif /* EXPOSE_TO_CLIENT_CODE */ #endif /* PG_ATTRIBUTE_H */ -- 1.8.3.1