/* -------------------------------- *CheckAttributeNamesTypes * *thisisusedtomakecertainthetupledescriptorcontainsa *validsetofattributenamesanddatatypes.aproblemsimply *generatesereport(ERROR)whichabortsthecurrenttransaction. * *relkindistherelkindoftherelationtobecreated. *flagscontrolswhichdatatypesareallowed,cfCheckAttributeType. *--------------------------------
*/ void
CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, int flags)
{ int i; int j; int natts = tupdesc->natts;
/* Sanity check on column count */ if (natts < 0 || natts > MaxHeapAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("tables can have at most %d columns",
MaxHeapAttributeNumber)));
/* *firstcheckforcollisionwithsystemattributenames * *Skipthisforaviewortyperelation,sincethosedon'thavesystem *attributes.
*/ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
{ for (i = 0; i < natts; i++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column name \"%s\" conflicts with a system column name",
NameStr(attr->attname))));
}
}
/* *nextcheckforrepeatedattributenames
*/ for (i = 1; i < natts; i++)
{ for (j = 0; j < i; j++)
{ if (strcmp(NameStr(TupleDescAttr(tupdesc, j)->attname),
NameStr(TupleDescAttr(tupdesc, i)->attname)) == 0)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column name \"%s\" specified more than once",
NameStr(TupleDescAttr(tupdesc, j)->attname))));
}
}
/* *nextchecktheattributetypes
*/ for (i = 0; i < natts; i++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
if (attr->attisdropped) continue;
CheckAttributeType(NameStr(attr->attname),
attr->atttypid,
attr->attcollation,
NIL, /* assume we're creating a new rowtype */
flags | (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL ? CHKATYPE_IS_VIRTUAL : 0));
}
}
/* -------------------------------- *CheckAttributeType * *Verifythattheproposeddatatypeofanattributeislegal. *Thisisneededmainlybecausetherearetypes(andpseudo-types) *inthecatalogsthatwedonotsupportaselementsofrealtuples. *Wealsochecksomeotherpropertiesrequiredofatablecolumn. * *Iftheattributeisbeingproposedforadditiontoanexistingtableor *compositetype,passaone-elementlistoftherowtypeOIDas *containing_rowtypes.Whencheckingato-be-createdrowtype,it's *sufficienttopassNIL,becausetherecouldnotbeanyrecursivereference *toanot-yet-existingrowtype. * *flagsisabitmaskcontrollingwhichdatatypesweallow.Forthemost *part,pseudo-typesaredisallowedasattributetypes,buttherearesome *exceptions:ANYARRAYOID,RECORDOID,andRECORDARRAYOIDcanbeallowed *insomecases.(Thisworksbecausevaluesofthosetypeclassesare *self-identifyingtosomeextent.However,RECORDOIDandRECORDARRAYOID *arereliablyidentifiableonlywithinasession,sincetheidentityinfo *mayuseatypmodthatisonlylocallyassigned.Thecallerisexpected *toknowwhetherthesecasesaresafe.) * *flagscanalsocontrolthephrasingoftheerrormessages.If *CHKATYPE_IS_PARTKEYisspecified,"attname"shouldbeapartitionkey *columnnumberastext,notarealcolumnname. *--------------------------------
*/ void
CheckAttributeType(constchar *attname,
Oid atttypid, Oid attcollation,
List *containing_rowtypes, int flags)
{ char att_typtype = get_typtype(atttypid);
Oid att_typelem;
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
if (att_typtype == TYPTYPE_PSEUDO)
{ /* *Wedisallowpseudo-typecolumns,withtheexceptionofANYARRAY, *RECORD,andRECORD[]whenthecallersaysthatthoseareOK. * *Wedon'tneedtoworryaboutrecursivecontainmentforRECORDand *RECORD[]because(a)nonamedcompositetypeshouldbeallowedto *containthose,and(b)two"anonymous"recordtypescouldn'tbe *consideredtobethesametype,soinfiniterecursionisn't *possible.
*/ if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
(atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
(atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
{ if (flags & CHKATYPE_IS_PARTKEY)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), /* translator: first %s is an integer not a name */
errmsg("partition key column %s has pseudo-type %s",
attname, format_type_be(atttypid)))); else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid))));
}
} elseif (att_typtype == TYPTYPE_DOMAIN)
{ /* *Preventvirtualgeneratedcolumnsfromhavingadomaintype.We *wouldhavetoenforcedomainconstraintswhencolumnsunderlying *thegeneratedcolumnchange.Thiscouldpossiblybeimplemented, *butit'snot.
*/ if (flags & CHKATYPE_IS_VIRTUAL)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("virtual generated column \"%s\" cannot have a domain type", attname));
/* *Checkforself-containment.Eventuallywemightbeabletoallow *this(justreturnwithoutcomplaint,ifso)butit'snotclearhow *manyotherplaceswouldrequireanti-recursiondefensesbeforeit *wouldbesafetoallowtablestocontaintheirownrowtype.
*/ if (list_member_oid(containing_rowtypes, atttypid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("composite type %s cannot be made a member of itself",
format_type_be(atttypid))));
/* *Forconsistencywithcheck_virtual_generated_security().
*/ if ((flags & CHKATYPE_IS_VIRTUAL) && atttypid >= FirstUnpinnedObjectId)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("virtual generated column \"%s\" cannot have a user-defined type", attname),
errdetail("Virtual generated columns that make use of user-defined types are not yet supported."));
/* *ThismightnotbestrictlyinvalidperSQLstandard,butitispretty *useless,anditcannotbedumped,sowemustdisallowit.
*/ if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
{ if (flags & CHKATYPE_IS_PARTKEY)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), /* translator: first %s is an integer not a name */
errmsg("no collation was derived for partition key column %s with collatable type %s",
attname, format_type_be(atttypid)),
errhint("Use the COLLATE clause to set the collation explicitly."))); else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("no collation was derived for column \"%s\" with collatable type %s",
attname, format_type_be(atttypid)),
errhint("Use the COLLATE clause to set the collation explicitly.")));
}
}
/* Initialize the number of slots to use */
nslots = Min(tupdesc->natts,
(MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_attribute)));
slot = palloc(sizeof(TupleTableSlot *) * nslots); for (int i = 0; i < nslots; i++)
slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple);
/* *Ifslotsarefullortheendofprocessinghasbeenreached,insert *abatchoftuples.
*/ if (slotCount == nslots || natts == tupdesc->natts - 1)
{ /* fetch index info only when we know we need it */ if (!indstate)
{
indstate = CatalogOpenIndexes(pg_attribute_rel);
close_index = true;
}
/* insert the new tuples and update the indexes */
CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount,
indstate);
slotCount = 0;
}
natts++;
}
if (close_index)
CatalogCloseIndexes(indstate); for (int i = 0; i < nslots; i++)
ExecDropSingleTupleTableSlot(slot[i]);
pfree(slot);
}
/* relispartition is always set by updating this tuple later */
new_rel_reltup->relispartition = false;
/* fill rd_att's type ID with something sane even if reltype is zero */
new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
new_rel_desc->rd_att->tdtypmod = -1;
/* Now build and insert the tuple */
InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
relacl, reloptions);
}
/* -------------------------------- *AddNewRelationType- * *defineacompositetypecorrespondingtothenewrelation *--------------------------------
*/ static ObjectAddress
AddNewRelationType(constchar *typeName,
Oid typeNamespace,
Oid new_rel_oid, char new_rel_kind,
Oid ownerid,
Oid new_row_type,
Oid new_array_type)
{ return
TypeCreate(new_row_type, /* optional predetermined OID */ typeName, /* type name */
typeNamespace, /* type namespace */
new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */
ownerid, /* owner's ID */
-1, /* internal size (varlena) */
TYPTYPE_COMPOSITE, /* type-type (composite) */
TYPCATEGORY_COMPOSITE, /* type-category (ditto) */ false, /* composite types are never preferred */
DEFAULT_TYPDELIM, /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */
F_RECORD_RECV, /* receive procedure */
F_RECORD_SEND, /* send procedure */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
InvalidOid, /* subscript procedure - none */
InvalidOid, /* array element type - irrelevant */ false, /* this is not an array type */
new_array_type, /* array type if any */
InvalidOid, /* domain base type - irrelevant */
NULL, /* default value - none */
NULL, /* default binary representation */ false, /* passed by reference */
TYPALIGN_DOUBLE, /* alignment - must be the largest! */
TYPSTORAGE_EXTENDED, /* fully TOASTable */
-1, /* typmod */ 0, /* array dimensions for typBaseType */ false, /* Type NOT NULL */
InvalidOid); /* rowtypes never have a collation */
}
/* -------------------------------- *heap_create_with_catalog * *createsanewcatalogedrelation.seecommentsabove. * *Arguments: *relname:nametogivetonewrel *relnamespace:OIDofnamespaceitgoesin *reltablespace:OIDoftablespaceitgoesin *relid:OIDtoassigntonewrel,orInvalidOidtoselectanewOID *reltypeid:OIDtoassigntorel'srowtype,orInvalidOidtoselectone *reloftypeid:ifatypedtable,OIDofunderlyingtype;elseInvalidOid *ownerid:OIDofnewrel'sowner *accessmtd:OIDofnewrel'saccessmethod *tupdesc:tupledescriptor(sourceofcolumndefinitions) *cooked_constraints:listofprecookedcheckconstraintsanddefaults *relkind:relkindfornewrel *relpersistence:rel'spersistencestatus(permanent,temp,orunlogged) *shared_relation:trueifit'stobeasharedrelation *mapped_relation:trueiftherelationwillusetherelfilenumbermap *oncommit:ONCOMMITmarking(onlyrelevantifit'satemptable) *reloptions:reloptionsinDatumform,or(Datum)0ifnone *use_user_acl:trueifshouldlookforuser-defineddefaultpermissions; *iffalse,relaclisalwayssetNULL *allow_system_table_mods:truetoallowcreationinsystemnamespaces *is_internal:isthisasystem-generatedcatalog? *relrewrite:linktooriginalrelationduringatablerewrite * *Outputparameters: *typaddress:ifnotnull,getstheobjectaddressofthenewpg_typeentry *(thismustbenulliftherelkindisonethatdoesn'tgetapg_typeentry) * *ReturnstheOIDofthenewrelation *--------------------------------
*/
Oid
heap_create_with_catalog(constchar *relname,
Oid relnamespace,
Oid reltablespace,
Oid relid,
Oid reltypeid,
Oid reloftypeid,
Oid ownerid,
Oid accessmtd,
TupleDesc tupdesc,
List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation,
OnCommitAction oncommit,
Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal,
Oid relrewrite,
ObjectAddress *typaddress)
{
Relation pg_class_desc;
Relation new_rel_desc;
Acl *relacl;
Oid existing_relid;
Oid old_type_oid;
Oid new_type_oid;
/* By default set to InvalidOid unless overridden by binary-upgrade */
RelFileNumber relfilenumber = InvalidRelFileNumber;
TransactionId relfrozenxid;
MultiXactId relminmxid;
/* *Sincewearegoingtocreatearowtypeaswell,alsocheckfor *collisionwithanexistingtypename.Ifthereisoneandit'san *autogeneratedarray,wecanrenameitoutoftheway;otherwisewecan *atleastgiveagooderrormessage.
*/
old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
CStringGetDatum(relname),
ObjectIdGetDatum(relnamespace)); if (OidIsValid(old_type_oid))
{ if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("type \"%s\" already exists", relname),
errhint("A relation has an associated type of the same name, " "so you must use a name that doesn't conflict " "with any existing type.")));
}
/* *Sharedrelationsmustbeinpg_global(last-ditchcheck)
*/ if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
elog(ERROR, "shared relations must be placed in pg_global tablespace");
/* *AllocateanOIDfortherelation,unlessweweretoldwhattouse. * *TheOIDwillbetherelfilenumberaswell,somakesureitdoesn't *collidewitheitherpg_classOIDsorexistingphysicalfiles.
*/ if (!OidIsValid(relid))
{ /* Use binary-upgrade override for pg_class.oid and relfilenumber */ if (IsBinaryUpgrade)
{ /* *Indexesarenotsupportedhere;theyuse *binary_upgrade_next_index_pg_class_oid.
*/
Assert(relkind != RELKIND_INDEX);
Assert(relkind != RELKIND_PARTITIONED_INDEX);
if (relkind == RELKIND_TOASTVALUE)
{ /* There might be no TOAST table, so we have to test for it. */ if (OidIsValid(binary_upgrade_next_toast_pg_class_oid))
{
relid = binary_upgrade_next_toast_pg_class_oid;
binary_upgrade_next_toast_pg_class_oid = InvalidOid;
if (!RelFileNumberIsValid(binary_upgrade_next_toast_pg_class_relfilenumber))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("toast relfilenumber value not set when in binary upgrade mode")));
relfilenumber = binary_upgrade_next_toast_pg_class_relfilenumber;
binary_upgrade_next_toast_pg_class_relfilenumber = InvalidRelFileNumber;
}
} else
{ if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("pg_class heap OID value not set when in binary upgrade mode")));
if (RELKIND_HAS_STORAGE(relkind))
{ if (!RelFileNumberIsValid(binary_upgrade_next_heap_pg_class_relfilenumber))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("relfilenumber value not set when in binary upgrade mode")));
/* *Ifthere'saspecialon-commitaction,rememberit
*/ if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
/* *ok,therelationhasbeencataloged,socloseourrelationsandreturn *theOIDofthenewlycreatedrelation.
*/
table_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
table_close(pg_class_desc, RowExclusiveLock);
/* Grab an appropriate lock on the pg_attribute relation */
attrel = table_open(AttributeRelationId, RowExclusiveLock);
/* Use the index to scan only attributes of the target relation */
ScanKeyInit(&key[0],
Anum_pg_attribute_attrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
/* Grab an appropriate lock on the pg_attribute relation */
attrel = table_open(AttributeRelationId, RowExclusiveLock);
/* Use the index to scan only system attributes of the target relation */
ScanKeyInit(&key[0],
Anum_pg_attribute_attrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
ScanKeyInit(&key[1],
Anum_pg_attribute_attnum,
BTLessEqualStrategyNumber, F_INT2LE,
Int16GetDatum(0));
/* Get a lock on pg_attribute */
attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
/* process each non-system attribute, including any dropped columns */ for (attnum = 1; attnum <= natts; attnum++)
{
tuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum)); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
/* ignore any where atthasmissing is not true */ if (attrtuple->atthasmissing)
{
newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
repl_val, repl_null, repl_repl);
/* This is only supported for plain tables */
Assert(rel->rd_rel->relkind == RELKIND_RELATION);
/* Fetch the pg_attribute row */
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
atttup = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(RelationGetRelid(rel)),
Int16GetDatum(attnum)); if (!HeapTupleIsValid(atttup)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, RelationGetRelid(rel));
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
/* Make a one-element array containing the value */
missingval = PointerGetDatum(construct_array(&missingval, 1,
attStruct->atttypid,
attStruct->attlen,
attStruct->attbyval,
attStruct->attalign));
/* lock the table the attribute belongs to */
tablerel = table_open(relid, AccessExclusiveLock);
/* Don't do anything unless it's a plain table */ if (tablerel->rd_rel->relkind != RELKIND_RELATION)
{
table_close(tablerel, AccessExclusiveLock); return;
}
/* Lock the attribute row and get the data */
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
atttup = SearchSysCacheAttName(relid, attname); if (!HeapTupleIsValid(atttup))
elog(ERROR, "cache lookup failed for attribute %s of relation %u",
attname, relid);
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
/* get an array value from the value string */
missingval = OidFunctionCall3(F_ARRAY_IN,
CStringGetDatum(value),
ObjectIdGetDatum(attStruct->atttypid),
Int32GetDatum(attStruct->atttypmod));
/* update the tuple - set atthasmissing and attmissingval */
valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
/* Determine which column to modify */
colnum = get_attnum(RelationGetRelid(rel), strVal(linitial(cdef->keys))); if (colnum == InvalidAttrNumber)
ereport(ERROR,
errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
strVal(linitial(cdef->keys)), RelationGetRelationName(rel))); if (colnum < InvalidAttrNumber)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot add not-null constraint on system column \"%s\"",
strVal(linitial(cdef->keys))));
/* There can be at most one matching row */ if (HeapTupleIsValid(tup = systable_getnext(conscan)))
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
/* Found it. Conflicts if not identical check constraint */ if (con->contype == CONSTRAINT_CHECK)
{
Datum val; bool isnull;
val = fastgetattr(tup,
Anum_pg_constraint_conbin,
conDesc->rd_att, &isnull); if (isnull)
elog(ERROR, "null conbin for rel %s",
RelationGetRelationName(rel)); if (equal(expr, stringToNode(TextDatumGetCString(val))))
found = true;
}
if (!found || !allow_merge)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("constraint \"%s\" for relation \"%s\" already exists",
ccname, RelationGetRelationName(rel))));
/* If the child constraint is "no inherit" then cannot merge */ if (con->connoinherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
ccname, RelationGetRelationName(rel))));
/* *Mustnotchangeanexistinginheritedconstraintto"noinherit" *status.That'sbecauseinheritedconstraintsshouldbeableto *propagatetolower-levelchildren.
*/ if (con->coninhcount > 0 && is_no_inherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
ccname, RelationGetRelationName(rel))));
/* *Ifthechildconstraintis"notvalid"thencannotmergewitha *validparentconstraint.
*/ if (is_initially_valid && con->conenforced && !con->convalidated)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
ccname, RelationGetRelationName(rel))));
/* *Anon-enforcedchildconstraintcannotbemergedwithanenforced *parentconstraint.However,thereverseisallowed,wherethechild *constraintisenforced.
*/ if ((!is_local && is_enforced && !con->conenforced) ||
(is_local && !is_enforced && con->conenforced))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with NOT ENFORCED constraint on relation \"%s\"",
ccname, RelationGetRelationName(rel))));
/* OK to update the tuple */
ereport(NOTICE,
(errmsg("merging constraint \"%s\" with inherited definition",
ccname)));
tup = heap_copytuple(tup);
con = (Form_pg_constraint) GETSTRUCT(tup);
/* *Createthenot-nullconstraintswhencreatinganewrelation * *Thesecomefromtwosources:the'constraints'list(ofConstraint)is *specifieddirectlybytheuser;the'old_notnulls'list(of *CookedConstraint)comesfrominheritance.Wecreateoneconstraint *foreachcolumn,givingprioritytouser-specifiedones,andsetting *inhcountaccordingtohowmanyparentscauseeachcolumntogeta *not-nullconstraint.Ifauser-specifiednameclasheswithanother *user-specifiedname,anerrorisraised.'existing_constraints' *isalistofalreadydefinedconstraintnames,whichshouldbeavoided *whengeneratingfurtherones. * *ReturnsalistofAttrNumberforcolumnsthatneedtohavetheattnotnull *flagset.
*/
List *
AddRelationNotNullConstraints(Relation rel, List *constraints,
List *old_notnulls, List *existing_constraints)
{
List *givennames;
List *nnnames;
List *nncols = NIL;
attnum = get_attnum(RelationGetRelid(rel),
strVal(linitial(constr->keys))); if (attnum == InvalidAttrNumber)
ereport(ERROR,
errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
strVal(linitial(constr->keys)),
RelationGetRelationName(rel))); if (attnum < InvalidAttrNumber)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot add not-null constraint on system column \"%s\"",
strVal(linitial(constr->keys))));
other = list_nth_node(Constraint, constraints, restpos); if (strcmp(strVal(linitial(constr->keys)),
strVal(linitial(other->keys))) == 0)
{ if (other->is_no_inherit != constr->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
strVal(linitial(constr->keys))));
/* *Preserveconstraintnameifoneisspecified,butraisean *errorifconflictingonesarespecified.
*/ if (other->conname)
{ if (!constr->conname)
constr->conname = pstrdup(other->conname); elseif (strcmp(constr->conname, other->conname) != 0)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting not-null constraint names \"%s\" and \"%s\"",
constr->conname, other->conname));
}
/* XXX do we need to verify any other fields? */
constraints = list_delete_nth_cell(constraints, restpos);
} else
restpos++;
}
/* *Searchinthelistofinheritedconstraintsforanyentriesonthe *samecolumn;determineaninheritancecountfromthat.Also,ifat *leastoneparenthasaconstraintforthiscolumn,thenwemustnot *acceptauserspecificationforaNOINHERITone.Anyconstraint *fromparentsthatweprocesshereisdeletedfromthelist:weno *longerneedtoprocessitintheloopbelow.
*/
foreach_ptr(CookedConstraint, old, old_notnulls)
{ if (old->attnum == attnum)
{ /* *Ifwegetaconstraintfromtheparent,havingalocalNO *INHERITonedoesn'twork.
*/ if (constr->is_no_inherit)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot define not-null constraint with NO INHERIT on column \"%s\"",
strVal(linitial(constr->keys))),
errdetail("The column has an inherited not-null constraint.")));
/* If we got a name, make sure it isn't one we've already used */ if (conname != NULL)
{
foreach_ptr(char, thisname, nnnames)
{ if (strcmp(thisname, conname) == 0)
{
conname = NULL; break;
}
}
}
/* and choose a name, if needed */ if (conname == NULL)
conname = ChooseConstraintName(RelationGetRelationName(rel),
get_attname(RelationGetRelid(rel),
cooked->attnum, false), "not_null",
RelationGetNamespace(rel),
nnnames);
nnnames = lappend(nnnames, conname);
/* ignore the origin constraint's is_local and inhcount */
StoreRelNotNull(rel, conname, cooked->attnum, true, false, inhcount, false);
if (relStruct->relchecks != numchecks)
{
relStruct->relchecks = numchecks;
CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
} else
{ /* Skip the disk update, but force relcache inval anyway */
CacheInvalidateRelcache(rel);
}
if (node == NULL) returnfalse; elseif (IsA(node, Var))
{
Var *var = (Var *) node;
Oid relid;
AttrNumber attnum;
relid = rt_fetch(var->varno, pstate->p_rtable)->relid; if (!OidIsValid(relid)) returnfalse; /* XXX shouldn't we raise an error? */
attnum = var->varattno;
if (attnum > 0 && get_attgenerated(relid, attnum))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use generated column \"%s\" in column generation expression",
get_attname(relid, attnum, false)),
errdetail("A generated column cannot reference another generated column."),
parser_errposition(pstate, var->location))); /* A whole-row Var is necessarily self-referential, so forbid it */ if (attnum == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use whole-row variable in column generation expression"),
errdetail("This would cause the generated column to depend on its own value."),
parser_errposition(pstate, var->location))); /* System columns were already checked in the parser */
if (!IsA(node, List))
{ if (check_functions_in_node(node, contains_user_functions_checker, NULL))
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("generation expression uses user-defined function"),
errdetail("Virtual generated columns that make use of user-defined functions are not yet supported."),
parser_errposition(pstate, exprLocation(node)));
/* *check_functions_in_node()doesn'tchecksomenodetypes(see *commentthere).WehandleCoerceToDomainandMinMaxExprby *checkingforbuilt-intypes.Theotherlistednodetypescannot *calluser-definableSQL-visiblefunctions. * *Wefurthermoreneedthistypechecktohandlebuilt-in,immutable *polymorphicfunctionssuchasarray_eq().
*/ if (exprType(node) >= FirstUnpinnedObjectId)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("generation expression uses user-defined type"),
errdetail("Virtual generated columns that make use of user-defined types are not yet supported."),
parser_errposition(pstate, exprLocation(node)));
}
if (attgenerated)
{ /* Disallow refs to other generated columns */
check_nested_generated(pstate, expr);
/* Disallow mutable functions */ if (contain_mutable_functions_after_planning((Expr *) expr))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("generation expression is not immutable")));
/* Check security of expressions for virtual generated column */ if (attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
check_virtual_generated_security(pstate, expr);
} else
{ /* *Foradefaultexpression,transformExpr()shouldhaverejected *columnreferences.
*/
Assert(!contain_var_clause(expr));
}
/* *Coercetheexpressiontothecorrecttypeandtypmod,ifgiven.This *shouldmatchtheparser'sprocessingofnon-defaultedexpressions--- *seetransformAssignedExpr().
*/ if (OidIsValid(atttypid))
{
Oid type_id = exprType(expr);
expr = coerce_to_target_type(pstate, expr, type_id,
atttypid, atttypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1); if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is of type %s" " but default expression is of type %s",
attname,
format_type_be(atttypid),
format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression.")));
}
/* *Makesurenooutsiderelationsarereferredto(thisisprobablydead *codenowthatadd_missing_fromishistory).
*/ if (list_length(pstate->p_rtable) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("only table \"%s\" can be referenced in check constraint",
relname)));
/* we must loop even when attnum != 0, in case of inherited stats */ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
CatalogTupleDelete(pgstatistic, &tuple->t_self);
/* Ask the relcache to produce a list of the indexes of the rel */
foreach(indlist, RelationGetIndexList(heapRelation))
{
Oid indexId = lfirst_oid(indlist);
Relation currentIndex;
IndexInfo *indexInfo;
/* Open the index relation; use exclusive lock, just to be sure */
currentIndex = index_open(indexId, AccessExclusiveLock);
/* Initialize the index and rebuild */ /* Note: we do not need to re-establish pkey setting */
index_build(heapRelation, currentIndex, indexInfo, true, false);
/* We're done with this index */
index_close(currentIndex, NoLock);
}
}
/* *Truncatetherelation.Partitionedtableshavenostorage,sothereis *nothingtodoforthemhere.
*/ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) return;
/* Truncate the underlying relation */
table_relation_nontransactional_truncate(rel);
/* If the relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rel);
/* If there is a toast table, truncate that too */
toastrelid = rel->rd_rel->reltoastrelid; if (OidIsValid(toastrelid))
{
Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
if (tempTables)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported ON COMMIT and foreign key combination"),
errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
relname2, relname))); else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot truncate a table referenced in a foreign key constraint"),
errdetail("Table \"%s\" references \"%s\".",
relname2, relname),
errhint("Truncate table \"%s\" at the same time, " "or use TRUNCATE ... CASCADE.",
relname2)));
}
}
}
}
/* *heap_truncate_find_FKs *Findrelationshavingforeignkeysreferencinganyofthegivenrels * *InputandresultarebothlistsofrelationOIDs.Theresultcontains *noduplicates,does*not*includeanyrelsthatwerealreadyintheinput *list,andissortedinOIDorder.(Thelastpropertyisenforcedmainly *toguaranteeconsistentbehaviorintheregressiontests;wedon'twant *behaviortochangedependingonchancelocationsofrowsinpg_constraint.) * *Note:callershouldalreadyhaveappropriatelockonallrelsmentioned *inrelationIds.SinceaddingordroppinganFKrequiresexclusivelock *onbothrels,thisensuresthattheanswerwillbestable.
*/
List *
heap_truncate_find_FKs(List *relationIds)
{
List *result = NIL;
List *oids;
List *parent_cons;
ListCell *cell;
ScanKeyData key;
Relation fkeyRel;
SysScanDesc fkeyScan;
HeapTuple tuple; bool restart;
/* Mark this relation as dependent on a few things as follows */
addrs = new_object_addresses();
ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
/* Operator class and collation per key column */ for (i = 0; i < partnatts; i++)
{
ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
add_exact_object_address(&referenced, addrs);
/* The default collation is pinned, so don't bother recording it */ if (OidIsValid(partcollation[i]) &&
partcollation[i] != DEFAULT_COLLATION_OID)
{
ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
add_exact_object_address(&referenced, addrs);
}
}
/* *Thepartitioningcolumnsaremadeinternallydependentonthetable, *becausewecannotdropanyofthemwithoutdroppingthewholetable. *(ATExecDropColumnindependentlyenforcesthat,butit'snotbulletproof *soweneedthedependenciestoo.)
*/ for (i = 0; i < partnatts; i++)
{ if (partattrs[i] == 0) continue; /* ignore expressions here */
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.279Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.