/*-------------------------------------------------------------------------
*
* pg_attrdef . c
* routines to support manipulation of the pg_attrdef relation
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
*
* IDENTIFICATION
* src / backend / catalog / pg_attrdef . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_attrdef.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/syscache.h"
/*
* Store a default expression for column attnum of relation rel .
*
* Returns the OID of the new pg_attrdef tuple .
*/
Oid
StoreAttrDefault(Relation rel, AttrNumber attnum,
Node *expr, bool is_internal)
{
char *adbin;
Relation adrel;
HeapTuple tuple;
Datum values[Natts_pg_attrdef];
static bool nulls[Natts_pg_attrdef] = {false , false , false , false };
Relation attrrel;
HeapTuple atttup;
Form_pg_attribute attStruct;
Datum valuesAtt[Natts_pg_attribute] = {0 };
bool nullsAtt[Natts_pg_attribute] = {0 };
bool replacesAtt[Natts_pg_attribute] = {0 };
char attgenerated;
Oid attrdefOid;
ObjectAddress colobject,
defobject;
adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
/*
* Flatten expression to string form for storage .
*/
adbin = nodeToString(expr);
/*
* Make the pg_attrdef entry .
*/
attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
Anum_pg_attrdef_oid);
values[Anum_pg_attrdef_oid - 1 ] = ObjectIdGetDatum(attrdefOid);
values[Anum_pg_attrdef_adrelid - 1 ] = ObjectIdGetDatum(RelationGetRelid(rel));
values[Anum_pg_attrdef_adnum - 1 ] = Int16GetDatum(attnum);
values[Anum_pg_attrdef_adbin - 1 ] = CStringGetTextDatum(adbin);
tuple = heap_form_tuple(adrel->rd_att, values, nulls);
CatalogTupleInsert(adrel, tuple);
defobject.classId = AttrDefaultRelationId;
defobject.objectId = attrdefOid;
defobject.objectSubId = 0 ;
table_close(adrel, RowExclusiveLock);
/* now can free some of the stuff allocated above */
pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1 ]));
heap_freetuple(tuple);
pfree(adbin);
/*
* Update the pg_attribute entry for the column to show that a default
* exists .
*/
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
atttup = SearchSysCacheCopy2(ATTNUM,
ObjectIdGetDatum(RelationGetRelid(rel)),
Int16GetDatum(attnum));
if (!HeapTupleIsValid(atttup))
elog(ERROR, "cache lookup failed for attribute %d of relation %u" ,
attnum, RelationGetRelid(rel));
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
attgenerated = attStruct->attgenerated;
valuesAtt[Anum_pg_attribute_atthasdef - 1 ] = BoolGetDatum(true );
replacesAtt[Anum_pg_attribute_atthasdef - 1 ] = true ;
atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
valuesAtt, nullsAtt, replacesAtt);
CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
table_close(attrrel, RowExclusiveLock);
heap_freetuple(atttup);
/*
* Make a dependency so that the pg_attrdef entry goes away if the column
* ( or whole table ) is deleted . In the case of a generated column , make
* it an internal dependency to prevent the default expression from being
* deleted separately .
*/
colobject.classId = RelationRelationId;
colobject.objectId = RelationGetRelid(rel);
colobject.objectSubId = attnum;
recordDependencyOn(&defobject, &colobject,
attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
/*
* Record dependencies on objects used in the expression , too .
*/
recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
DEPENDENCY_NORMAL,
DEPENDENCY_NORMAL, false );
/*
* Post creation hook for attribute defaults .
*
* XXX . ALTER TABLE ALTER COLUMN SET / DROP DEFAULT is implemented with a
* couple of deletion / creation of the attribute ' s default entry , so the
* callee should check existence of an older version of this entry if it
* needs to distinguish .
*/
InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
RelationGetRelid(rel), attnum, is_internal);
return attrdefOid;
}
/*
* RemoveAttrDefault
*
* If the specified relation / attribute has a default , remove it .
* ( If no default , raise error if complain is true , else return quietly . )
*/
void
RemoveAttrDefault(Oid relid, AttrNumber attnum,
DropBehavior behavior, bool complain, bool internal)
{
Relation attrdef_rel;
ScanKeyData scankeys[2 ];
SysScanDesc scan;
HeapTuple tuple;
bool found = false ;
attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
ScanKeyInit(&scankeys[0 ],
Anum_pg_attrdef_adrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
ScanKeyInit(&scankeys[1 ],
Anum_pg_attrdef_adnum,
BTEqualStrategyNumber, F_INT2EQ,
Int16GetDatum(attnum));
scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true ,
NULL, 2 , scankeys);
/* There should be at most one matching tuple, but we loop anyway */
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
ObjectAddress object;
Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
object.classId = AttrDefaultRelationId;
object.objectId = attrtuple->oid;
object.objectSubId = 0 ;
performDeletion(&object, behavior,
internal ? PERFORM_DELETION_INTERNAL : 0 );
found = true ;
}
systable_endscan(scan);
table_close(attrdef_rel, RowExclusiveLock);
if (complain && !found)
elog(ERROR, "could not find attrdef tuple for relation %u attnum %d" ,
relid, attnum);
}
/*
* RemoveAttrDefaultById
*
* Remove a pg_attrdef entry specified by OID . This is the guts of
* attribute - default removal . Note it should be called via performDeletion ,
* not directly .
*/
void
RemoveAttrDefaultById(Oid attrdefId)
{
Relation attrdef_rel;
Relation attr_rel;
Relation myrel;
ScanKeyData scankeys[1 ];
SysScanDesc scan;
HeapTuple tuple;
Oid myrelid;
AttrNumber myattnum;
/* Grab an appropriate lock on the pg_attrdef relation */
attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
/* Find the pg_attrdef tuple */
ScanKeyInit(&scankeys[0 ],
Anum_pg_attrdef_oid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(attrdefId));
scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true ,
NULL, 1 , scankeys);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for attrdef %u" , attrdefId);
myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
/* Get an exclusive lock on the relation owning the attribute */
myrel = relation_open(myrelid, AccessExclusiveLock);
/* Now we can delete the pg_attrdef row */
CatalogTupleDelete(attrdef_rel, &tuple->t_self);
systable_endscan(scan);
table_close(attrdef_rel, RowExclusiveLock);
/* Fix the pg_attribute row */
attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
tuple = SearchSysCacheCopy2(ATTNUM,
ObjectIdGetDatum(myrelid),
Int16GetDatum(myattnum));
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for attribute %d of relation %u" ,
myattnum, myrelid);
((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false ;
CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
/*
* Our update of the pg_attribute row will force a relcache rebuild , so
* there ' s nothing else to do here .
*/
table_close(attr_rel, RowExclusiveLock);
/* Keep lock on attribute's rel until end of xact */
relation_close(myrel, NoLock);
}
/*
* Get the pg_attrdef OID of the default expression for a column
* identified by relation OID and column number .
*
* Returns InvalidOid if there is no such pg_attrdef entry .
*/
Oid
GetAttrDefaultOid(Oid relid, AttrNumber attnum)
{
Oid result = InvalidOid;
Relation attrdef;
ScanKeyData keys[2 ];
SysScanDesc scan;
HeapTuple tup;
attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
ScanKeyInit(&keys[0 ],
Anum_pg_attrdef_adrelid,
BTEqualStrategyNumber,
F_OIDEQ,
ObjectIdGetDatum(relid));
ScanKeyInit(&keys[1 ],
Anum_pg_attrdef_adnum,
BTEqualStrategyNumber,
F_INT2EQ,
Int16GetDatum(attnum));
scan = systable_beginscan(attrdef, AttrDefaultIndexId, true ,
NULL, 2 , keys);
if (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
result = atdform->oid;
}
systable_endscan(scan);
table_close(attrdef, AccessShareLock);
return result;
}
/*
* Given a pg_attrdef OID , return the relation OID and column number of
* the owning column ( represented as an ObjectAddress for convenience ) .
*
* Returns InvalidObjectAddress if there is no such pg_attrdef entry .
*/
ObjectAddress
GetAttrDefaultColumnAddress(Oid attrdefoid)
{
ObjectAddress result = InvalidObjectAddress;
Relation attrdef;
ScanKeyData skey[1 ];
SysScanDesc scan;
HeapTuple tup;
attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
ScanKeyInit(&skey[0 ],
Anum_pg_attrdef_oid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(attrdefoid));
scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true ,
NULL, 1 , skey);
if (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
result.classId = RelationRelationId;
result.objectId = atdform->adrelid;
result.objectSubId = atdform->adnum;
}
systable_endscan(scan);
table_close(attrdef, AccessShareLock);
return result;
}
Messung V0.5 in Prozent C=94 H=95 G=94
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland