PostgreSQL Source Code  git master
pg_attrdef.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_attrdef.h"
#include "executor/executor.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_attrdef.c:

Go to the source code of this file.

Functions

Oid StoreAttrDefault (Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
 
void RemoveAttrDefault (Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
 
void RemoveAttrDefaultById (Oid attrdefId)
 
Oid GetAttrDefaultOid (Oid relid, AttrNumber attnum)
 
ObjectAddress GetAttrDefaultColumnAddress (Oid attrdefoid)
 

Function Documentation

◆ GetAttrDefaultColumnAddress()

ObjectAddress GetAttrDefaultColumnAddress ( Oid  attrdefoid)

Definition at line 384 of file pg_attrdef.c.

385 {
387  Relation attrdef;
388  ScanKeyData skey[1];
389  SysScanDesc scan;
390  HeapTuple tup;
391 
392  attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
393  ScanKeyInit(&skey[0],
394  Anum_pg_attrdef_oid,
395  BTEqualStrategyNumber, F_OIDEQ,
396  ObjectIdGetDatum(attrdefoid));
397  scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true,
398  NULL, 1, skey);
399 
400  if (HeapTupleIsValid(tup = systable_getnext(scan)))
401  {
402  Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
403 
404  result.classId = RelationRelationId;
405  result.objectId = atdform->adrelid;
406  result.objectSubId = atdform->adnum;
407  }
408 
409  systable_endscan(scan);
410  table_close(attrdef, AccessShareLock);
411 
412  return result;
413 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
#define AccessShareLock
Definition: lockdefs.h:36
const ObjectAddress InvalidObjectAddress
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:49
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

References AccessShareLock, BTEqualStrategyNumber, ObjectAddress::classId, GETSTRUCT, HeapTupleIsValid, InvalidObjectAddress, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ATExecAlterColumnType(), getObjectDescription(), and getObjectIdentityParts().

◆ GetAttrDefaultOid()

Oid GetAttrDefaultOid ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 342 of file pg_attrdef.c.

343 {
344  Oid result = InvalidOid;
345  Relation attrdef;
346  ScanKeyData keys[2];
347  SysScanDesc scan;
348  HeapTuple tup;
349 
350  attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
351  ScanKeyInit(&keys[0],
352  Anum_pg_attrdef_adrelid,
354  F_OIDEQ,
355  ObjectIdGetDatum(relid));
356  ScanKeyInit(&keys[1],
357  Anum_pg_attrdef_adnum,
359  F_INT2EQ,
361  scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
362  NULL, 2, keys);
363 
364  if (HeapTupleIsValid(tup = systable_getnext(scan)))
365  {
366  Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup);
367 
368  result = atdform->oid;
369  }
370 
371  systable_endscan(scan);
372  table_close(attrdef, AccessShareLock);
373 
374  return result;
375 }
int16 attnum
Definition: pg_attribute.h:83
#define Int16GetDatum(X)
Definition: postgres.h:495
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31

References AccessShareLock, attnum, BTEqualStrategyNumber, GETSTRUCT, HeapTupleIsValid, Int16GetDatum, InvalidOid, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ATExecAlterColumnType(), ATExecDropExpression(), and get_object_address_attrdef().

◆ RemoveAttrDefault()

void RemoveAttrDefault ( Oid  relid,
AttrNumber  attnum,
DropBehavior  behavior,
bool  complain,
bool  internal 
)

Definition at line 216 of file pg_attrdef.c.

218 {
219  Relation attrdef_rel;
220  ScanKeyData scankeys[2];
221  SysScanDesc scan;
222  HeapTuple tuple;
223  bool found = false;
224 
225  attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
226 
227  ScanKeyInit(&scankeys[0],
228  Anum_pg_attrdef_adrelid,
229  BTEqualStrategyNumber, F_OIDEQ,
230  ObjectIdGetDatum(relid));
231  ScanKeyInit(&scankeys[1],
232  Anum_pg_attrdef_adnum,
233  BTEqualStrategyNumber, F_INT2EQ,
235 
236  scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
237  NULL, 2, scankeys);
238 
239  /* There should be at most one matching tuple, but we loop anyway */
240  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
241  {
242  ObjectAddress object;
243  Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
244 
245  object.classId = AttrDefaultRelationId;
246  object.objectId = attrtuple->oid;
247  object.objectSubId = 0;
248 
249  performDeletion(&object, behavior,
250  internal ? PERFORM_DELETION_INTERNAL : 0);
251 
252  found = true;
253  }
254 
255  systable_endscan(scan);
256  table_close(attrdef_rel, RowExclusiveLock);
257 
258  if (complain && !found)
259  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
260  relid, attnum);
261 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:317
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:135
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define RowExclusiveLock
Definition: lockdefs.h:38

References attnum, BTEqualStrategyNumber, elog, ERROR, GETSTRUCT, HeapTupleIsValid, Int16GetDatum, ObjectIdGetDatum, PERFORM_DELETION_INTERNAL, performDeletion(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ATExecAlterColumnType(), ATExecColumnDefault(), ATExecCookedColumnDefault(), and ATExecDropExpression().

◆ RemoveAttrDefaultById()

void RemoveAttrDefaultById ( Oid  attrdefId)

Definition at line 271 of file pg_attrdef.c.

272 {
273  Relation attrdef_rel;
274  Relation attr_rel;
275  Relation myrel;
276  ScanKeyData scankeys[1];
277  SysScanDesc scan;
278  HeapTuple tuple;
279  Oid myrelid;
280  AttrNumber myattnum;
281 
282  /* Grab an appropriate lock on the pg_attrdef relation */
283  attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
284 
285  /* Find the pg_attrdef tuple */
286  ScanKeyInit(&scankeys[0],
287  Anum_pg_attrdef_oid,
288  BTEqualStrategyNumber, F_OIDEQ,
289  ObjectIdGetDatum(attrdefId));
290 
291  scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
292  NULL, 1, scankeys);
293 
294  tuple = systable_getnext(scan);
295  if (!HeapTupleIsValid(tuple))
296  elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
297 
298  myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
299  myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
300 
301  /* Get an exclusive lock on the relation owning the attribute */
302  myrel = relation_open(myrelid, AccessExclusiveLock);
303 
304  /* Now we can delete the pg_attrdef row */
305  CatalogTupleDelete(attrdef_rel, &tuple->t_self);
306 
307  systable_endscan(scan);
308  table_close(attrdef_rel, RowExclusiveLock);
309 
310  /* Fix the pg_attribute row */
311  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
312 
313  tuple = SearchSysCacheCopy2(ATTNUM,
314  ObjectIdGetDatum(myrelid),
315  Int16GetDatum(myattnum));
316  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
317  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
318  myattnum, myrelid);
319 
320  ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
321 
322  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
323 
324  /*
325  * Our update of the pg_attribute row will force a relcache rebuild, so
326  * there's nothing else to do here.
327  */
328  table_close(attr_rel, RowExclusiveLock);
329 
330  /* Keep lock on attribute's rel until end of xact */
331  relation_close(myrel, NoLock);
332 }
int16 AttrNumber
Definition: attnum.h:21
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:181
@ ATTNUM
Definition: syscache.h:41

References AccessExclusiveLock, ATTNUM, BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, Int16GetDatum, NoLock, ObjectIdGetDatum, relation_close(), relation_open(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy2, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ StoreAttrDefault()

Oid StoreAttrDefault ( Relation  rel,
AttrNumber  attnum,
Node expr,
bool  is_internal,
bool  add_column_mode 
)

Definition at line 46 of file pg_attrdef.c.

48 {
49  char *adbin;
50  Relation adrel;
51  HeapTuple tuple;
52  Datum values[4];
53  static bool nulls[4] = {false, false, false, false};
54  Relation attrrel;
55  HeapTuple atttup;
56  Form_pg_attribute attStruct;
57  char attgenerated;
58  Oid attrdefOid;
59  ObjectAddress colobject,
60  defobject;
61 
62  adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
63 
64  /*
65  * Flatten expression to string form for storage.
66  */
67  adbin = nodeToString(expr);
68 
69  /*
70  * Make the pg_attrdef entry.
71  */
72  attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
73  Anum_pg_attrdef_oid);
74  values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
75  values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
76  values[Anum_pg_attrdef_adnum - 1] = attnum;
77  values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
78 
79  tuple = heap_form_tuple(adrel->rd_att, values, nulls);
80  CatalogTupleInsert(adrel, tuple);
81 
82  defobject.classId = AttrDefaultRelationId;
83  defobject.objectId = attrdefOid;
84  defobject.objectSubId = 0;
85 
87 
88  /* now can free some of the stuff allocated above */
89  pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
90  heap_freetuple(tuple);
91  pfree(adbin);
92 
93  /*
94  * Update the pg_attribute entry for the column to show that a default
95  * exists.
96  */
97  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
98  atttup = SearchSysCacheCopy2(ATTNUM,
101  if (!HeapTupleIsValid(atttup))
102  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
103  attnum, RelationGetRelid(rel));
104  attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
105  attgenerated = attStruct->attgenerated;
106  if (!attStruct->atthasdef)
107  {
108  Form_pg_attribute defAttStruct;
109 
110  ExprState *exprState;
111  Expr *expr2 = (Expr *) expr;
112  EState *estate = NULL;
113  ExprContext *econtext;
114  Datum valuesAtt[Natts_pg_attribute];
115  bool nullsAtt[Natts_pg_attribute];
116  bool replacesAtt[Natts_pg_attribute];
117  Datum missingval = (Datum) 0;
118  bool missingIsNull = true;
119 
120  MemSet(valuesAtt, 0, sizeof(valuesAtt));
121  MemSet(nullsAtt, false, sizeof(nullsAtt));
122  MemSet(replacesAtt, false, sizeof(replacesAtt));
123  valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
124  replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
125 
126  if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
127  !attgenerated)
128  {
129  expr2 = expression_planner(expr2);
130  estate = CreateExecutorState();
131  exprState = ExecPrepareExpr(expr2, estate);
132  econtext = GetPerTupleExprContext(estate);
133 
134  missingval = ExecEvalExpr(exprState, econtext,
135  &missingIsNull);
136 
137  FreeExecutorState(estate);
138 
139  defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
140 
141  if (missingIsNull)
142  {
143  /* if the default evaluates to NULL, just store a NULL array */
144  missingval = (Datum) 0;
145  }
146  else
147  {
148  /* otherwise make a one-element array of the value */
149  missingval = PointerGetDatum(construct_array(&missingval,
150  1,
151  defAttStruct->atttypid,
152  defAttStruct->attlen,
153  defAttStruct->attbyval,
154  defAttStruct->attalign));
155  }
156 
157  valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
158  replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
159  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
160  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
161  nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
162  }
163  atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
164  valuesAtt, nullsAtt, replacesAtt);
165 
166  CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
167 
168  if (!missingIsNull)
169  pfree(DatumGetPointer(missingval));
170  }
171  table_close(attrrel, RowExclusiveLock);
172  heap_freetuple(atttup);
173 
174  /*
175  * Make a dependency so that the pg_attrdef entry goes away if the column
176  * (or whole table) is deleted. In the case of a generated column, make
177  * it an internal dependency to prevent the default expression from being
178  * deleted separately.
179  */
180  colobject.classId = RelationRelationId;
181  colobject.objectId = RelationGetRelid(rel);
182  colobject.objectSubId = attnum;
183 
184  recordDependencyOn(&defobject, &colobject,
185  attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
186 
187  /*
188  * Record dependencies on objects used in the expression, too.
189  */
190  recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
192  DEPENDENCY_NORMAL, false);
193 
194  /*
195  * Post creation hook for attribute defaults.
196  *
197  * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
198  * couple of deletion/creation of the attribute's default entry, so the
199  * callee should check existence of an older version of this entry if it
200  * needs to distinguish.
201  */
202  InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
203  RelationGetRelid(rel), attnum, is_internal);
204 
205  return attrdefOid;
206 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
#define MemSet(start, val, len)
Definition: c.h:1008
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1631
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
EState * CreateExecutorState(void)
Definition: execUtils.c:90
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define GetPerTupleExprContext(estate)
Definition: executor.h:537
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:320
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
void pfree(void *pointer)
Definition: mcxt.c:1175
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:173
char * nodeToString(const void *obj)
Definition: outfuncs.c:4785
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
Expr * expression_planner(Expr *expr)
Definition: planner.c:5882
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetPointer(X)
Definition: postgres.h:593
#define PointerGetDatum(X)
Definition: postgres.h:600
#define RelationGetRelid(relation)
Definition: rel.h:488
#define RelationGetDescr(relation)
Definition: rel.h:514
TupleDesc rd_att
Definition: rel.h:110
Form_pg_class rd_rel
Definition: rel.h:109
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References attnum, ATTNUM, CatalogTupleInsert(), CatalogTupleUpdate(), ObjectAddress::classId, construct_array(), CreateExecutorState(), CStringGetTextDatum, DatumGetPointer, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, elog, ERROR, ExecEvalExpr(), ExecPrepareExpr(), expression_planner(), FreeExecutorState(), GetNewOidWithIndex(), GetPerTupleExprContext, GETSTRUCT, heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum, InvokeObjectPostCreateHookArg, MemSet, nodeToString(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, pfree(), PointerGetDatum, RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnSingleRelExpr(), RelationGetDescr, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy2, HeapTupleData::t_self, table_close(), table_open(), TupleDescAttr, and values.

Referenced by AddRelationNewConstraints(), ATExecAlterColumnType(), ATExecCookedColumnDefault(), and StoreConstraints().