PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pg_attrdef.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_attrdef.c
4 * routines to support manipulation of the pg_attrdef relation
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_attrdef.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include "access/relation.h"
18#include "access/table.h"
19#include "catalog/dependency.h"
20#include "catalog/indexing.h"
22#include "catalog/pg_attrdef.h"
23#include "utils/builtins.h"
24#include "utils/fmgroids.h"
25#include "utils/rel.h"
26#include "utils/syscache.h"
27
28
29/*
30 * Store a default expression for column attnum of relation rel.
31 *
32 * Returns the OID of the new pg_attrdef tuple.
33 */
34Oid
36 Node *expr, bool is_internal)
37{
38 char *adbin;
39 Relation adrel;
40 HeapTuple tuple;
41 Datum values[Natts_pg_attrdef];
42 static bool nulls[Natts_pg_attrdef] = {false, false, false, false};
43 Relation attrrel;
44 HeapTuple atttup;
45 Form_pg_attribute attStruct;
46 Datum valuesAtt[Natts_pg_attribute] = {0};
47 bool nullsAtt[Natts_pg_attribute] = {0};
48 bool replacesAtt[Natts_pg_attribute] = {0};
49 char attgenerated;
50 Oid attrdefOid;
51 ObjectAddress colobject,
52 defobject;
53
54 adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
55
56 /*
57 * Flatten expression to string form for storage.
58 */
59 adbin = nodeToString(expr);
60
61 /*
62 * Make the pg_attrdef entry.
63 */
64 attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
65 Anum_pg_attrdef_oid);
66 values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
67 values[Anum_pg_attrdef_adrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
68 values[Anum_pg_attrdef_adnum - 1] = Int16GetDatum(attnum);
69 values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
70
71 tuple = heap_form_tuple(adrel->rd_att, values, nulls);
72 CatalogTupleInsert(adrel, tuple);
73
74 defobject.classId = AttrDefaultRelationId;
75 defobject.objectId = attrdefOid;
76 defobject.objectSubId = 0;
77
79
80 /* now can free some of the stuff allocated above */
81 pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
82 heap_freetuple(tuple);
83 pfree(adbin);
84
85 /*
86 * Update the pg_attribute entry for the column to show that a default
87 * exists.
88 */
89 attrrel = table_open(AttributeRelationId, RowExclusiveLock);
90 atttup = SearchSysCacheCopy2(ATTNUM,
93 if (!HeapTupleIsValid(atttup))
94 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
96 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
97 attgenerated = attStruct->attgenerated;
98
99 valuesAtt[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(true);
100 replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
101
102 atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
103 valuesAtt, nullsAtt, replacesAtt);
104
105 CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
106
108 heap_freetuple(atttup);
109
110 /*
111 * Make a dependency so that the pg_attrdef entry goes away if the column
112 * (or whole table) is deleted. In the case of a generated column, make
113 * it an internal dependency to prevent the default expression from being
114 * deleted separately.
115 */
116 colobject.classId = RelationRelationId;
117 colobject.objectId = RelationGetRelid(rel);
118 colobject.objectSubId = attnum;
119
120 recordDependencyOn(&defobject, &colobject,
121 attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
122
123 /*
124 * Record dependencies on objects used in the expression, too.
125 */
128 DEPENDENCY_NORMAL, false);
129
130 /*
131 * Post creation hook for attribute defaults.
132 *
133 * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
134 * couple of deletion/creation of the attribute's default entry, so the
135 * callee should check existence of an older version of this entry if it
136 * needs to distinguish.
137 */
138 InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
139 RelationGetRelid(rel), attnum, is_internal);
140
141 return attrdefOid;
142}
143
144
145/*
146 * RemoveAttrDefault
147 *
148 * If the specified relation/attribute has a default, remove it.
149 * (If no default, raise error if complain is true, else return quietly.)
150 */
151void
153 DropBehavior behavior, bool complain, bool internal)
154{
155 Relation attrdef_rel;
156 ScanKeyData scankeys[2];
157 SysScanDesc scan;
158 HeapTuple tuple;
159 bool found = false;
160
161 attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
162
163 ScanKeyInit(&scankeys[0],
164 Anum_pg_attrdef_adrelid,
165 BTEqualStrategyNumber, F_OIDEQ,
166 ObjectIdGetDatum(relid));
167 ScanKeyInit(&scankeys[1],
168 Anum_pg_attrdef_adnum,
169 BTEqualStrategyNumber, F_INT2EQ,
171
172 scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
173 NULL, 2, scankeys);
174
175 /* There should be at most one matching tuple, but we loop anyway */
176 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
177 {
178 ObjectAddress object;
179 Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
180
181 object.classId = AttrDefaultRelationId;
182 object.objectId = attrtuple->oid;
183 object.objectSubId = 0;
184
185 performDeletion(&object, behavior,
186 internal ? PERFORM_DELETION_INTERNAL : 0);
187
188 found = true;
189 }
190
191 systable_endscan(scan);
192 table_close(attrdef_rel, RowExclusiveLock);
193
194 if (complain && !found)
195 elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
196 relid, attnum);
197}
198
199/*
200 * RemoveAttrDefaultById
201 *
202 * Remove a pg_attrdef entry specified by OID. This is the guts of
203 * attribute-default removal. Note it should be called via performDeletion,
204 * not directly.
205 */
206void
208{
209 Relation attrdef_rel;
210 Relation attr_rel;
211 Relation myrel;
212 ScanKeyData scankeys[1];
213 SysScanDesc scan;
214 HeapTuple tuple;
215 Oid myrelid;
216 AttrNumber myattnum;
217
218 /* Grab an appropriate lock on the pg_attrdef relation */
219 attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
220
221 /* Find the pg_attrdef tuple */
222 ScanKeyInit(&scankeys[0],
223 Anum_pg_attrdef_oid,
224 BTEqualStrategyNumber, F_OIDEQ,
225 ObjectIdGetDatum(attrdefId));
226
227 scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
228 NULL, 1, scankeys);
229
230 tuple = systable_getnext(scan);
231 if (!HeapTupleIsValid(tuple))
232 elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
233
234 myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
235 myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
236
237 /* Get an exclusive lock on the relation owning the attribute */
238 myrel = relation_open(myrelid, AccessExclusiveLock);
239
240 /* Now we can delete the pg_attrdef row */
241 CatalogTupleDelete(attrdef_rel, &tuple->t_self);
242
243 systable_endscan(scan);
244 table_close(attrdef_rel, RowExclusiveLock);
245
246 /* Fix the pg_attribute row */
247 attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
248
249 tuple = SearchSysCacheCopy2(ATTNUM,
250 ObjectIdGetDatum(myrelid),
251 Int16GetDatum(myattnum));
252 if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
253 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
254 myattnum, myrelid);
255
256 ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
257
258 CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
259
260 /*
261 * Our update of the pg_attribute row will force a relcache rebuild, so
262 * there's nothing else to do here.
263 */
264 table_close(attr_rel, RowExclusiveLock);
265
266 /* Keep lock on attribute's rel until end of xact */
267 relation_close(myrel, NoLock);
268}
269
270
271/*
272 * Get the pg_attrdef OID of the default expression for a column
273 * identified by relation OID and column number.
274 *
275 * Returns InvalidOid if there is no such pg_attrdef entry.
276 */
277Oid
279{
280 Oid result = InvalidOid;
281 Relation attrdef;
282 ScanKeyData keys[2];
283 SysScanDesc scan;
284 HeapTuple tup;
285
286 attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
287 ScanKeyInit(&keys[0],
288 Anum_pg_attrdef_adrelid,
290 F_OIDEQ,
291 ObjectIdGetDatum(relid));
292 ScanKeyInit(&keys[1],
293 Anum_pg_attrdef_adnum,
295 F_INT2EQ,
297 scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
298 NULL, 2, keys);
299
300 if (HeapTupleIsValid(tup = systable_getnext(scan)))
301 {
303
304 result = atdform->oid;
305 }
306
307 systable_endscan(scan);
309
310 return result;
311}
312
313/*
314 * Given a pg_attrdef OID, return the relation OID and column number of
315 * the owning column (represented as an ObjectAddress for convenience).
316 *
317 * Returns InvalidObjectAddress if there is no such pg_attrdef entry.
318 */
321{
323 Relation attrdef;
324 ScanKeyData skey[1];
325 SysScanDesc scan;
326 HeapTuple tup;
327
328 attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
329 ScanKeyInit(&skey[0],
330 Anum_pg_attrdef_oid,
331 BTEqualStrategyNumber, F_OIDEQ,
332 ObjectIdGetDatum(attrdefoid));
333 scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true,
334 NULL, 1, skey);
335
336 if (HeapTupleIsValid(tup = systable_getnext(scan)))
337 {
339
340 result.classId = RelationRelationId;
341 result.objectId = atdform->adrelid;
342 result.objectSubId = atdform->adnum;
343 }
344
345 systable_endscan(scan);
347
348 return result;
349}
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:450
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:2150
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
const ObjectAddress InvalidObjectAddress
char * nodeToString(const void *obj)
Definition: outfuncs.c:797
DropBehavior
Definition: parsenodes.h:2389
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal)
Definition: pg_attrdef.c:35
void RemoveAttrDefaultById(Oid attrdefId)
Definition: pg_attrdef.c:207
Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum)
Definition: pg_attrdef.c:278
ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid)
Definition: pg_attrdef.c:320
void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
Definition: pg_attrdef.c:152
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
#define RelationGetRelid(relation)
Definition: rel.h:516
#define RelationGetDescr(relation)
Definition: rel.h:542
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
Definition: nodes.h:135
TupleDesc rd_att
Definition: rel.h:112
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:93
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40