PostgreSQL Source Code  git master
heap.h File Reference
Include dependency graph for heap.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  RawColumnDefault
 
struct  CookedConstraint
 

Macros

#define CHKATYPE_ANYARRAY   0x01 /* allow ANYARRAY */
 
#define CHKATYPE_ANYRECORD   0x02 /* allow RECORD and RECORD[] */
 
#define CHKATYPE_IS_PARTKEY   0x04 /* attname is part key # not column */
 

Typedefs

typedef struct RawColumnDefault RawColumnDefault
 
typedef struct CookedConstraint CookedConstraint
 

Functions

Relation heap_create (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, RelFileNumber relfilenumber, Oid accessmtd, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, bool create_storage)
 
Oid heap_create_with_catalog (const char *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)
 
void heap_drop_with_catalog (Oid relid)
 
void heap_truncate (List *relids)
 
void heap_truncate_one_rel (Relation rel)
 
void heap_truncate_check_FKs (List *relations, bool tempTables)
 
Listheap_truncate_find_FKs (List *relationIds)
 
void InsertPgAttributeTuples (Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
 
void InsertPgClassTuple (Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
 
ListAddRelationNewConstraints (Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
 
ListAddRelationNotNullConstraints (Relation rel, List *constraints, List *additional_notnulls)
 
void RelationClearMissing (Relation rel)
 
void SetAttrMissing (Oid relid, char *attname, char *value)
 
NodecookDefault (ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
 
void DeleteRelationTuple (Oid relid)
 
void DeleteAttributeTuples (Oid relid)
 
void DeleteSystemAttributeTuples (Oid relid)
 
void RemoveAttributeById (Oid relid, AttrNumber attnum)
 
void CopyStatistics (Oid fromrelid, Oid torelid)
 
void RemoveStatistics (Oid relid, AttrNumber attnum)
 
const FormData_pg_attributeSystemAttributeDefinition (AttrNumber attno)
 
const FormData_pg_attributeSystemAttributeByName (const char *attname)
 
void CheckAttributeNamesTypes (TupleDesc tupdesc, char relkind, int flags)
 
void CheckAttributeType (const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
 
void StorePartitionKey (Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
 
void RemovePartitionKeyByRelId (Oid relid)
 
void StorePartitionBound (Relation rel, Relation parent, PartitionBoundSpec *bound)
 

Macro Definition Documentation

◆ CHKATYPE_ANYARRAY

#define CHKATYPE_ANYARRAY   0x01 /* allow ANYARRAY */

Definition at line 23 of file heap.h.

◆ CHKATYPE_ANYRECORD

#define CHKATYPE_ANYRECORD   0x02 /* allow RECORD and RECORD[] */

Definition at line 24 of file heap.h.

◆ CHKATYPE_IS_PARTKEY

#define CHKATYPE_IS_PARTKEY   0x04 /* attname is part key # not column */

Definition at line 25 of file heap.h.

Typedef Documentation

◆ CookedConstraint

◆ RawColumnDefault

Function Documentation

◆ AddRelationNewConstraints()

List* AddRelationNewConstraints ( Relation  rel,
List newColDefaults,
List newConstraints,
bool  allow_merge,
bool  is_local,
bool  is_internal,
const char *  queryString 
)

Definition at line 2307 of file heap.c.

2314 {
2315  List *cookedConstraints = NIL;
2316  TupleDesc tupleDesc;
2317  TupleConstr *oldconstr;
2318  int numoldchecks;
2319  ParseState *pstate;
2320  ParseNamespaceItem *nsitem;
2321  int numchecks;
2322  List *checknames;
2323  List *nnnames;
2324  ListCell *cell;
2325  Node *expr;
2326  CookedConstraint *cooked;
2327 
2328  /*
2329  * Get info about existing constraints.
2330  */
2331  tupleDesc = RelationGetDescr(rel);
2332  oldconstr = tupleDesc->constr;
2333  if (oldconstr)
2334  numoldchecks = oldconstr->num_check;
2335  else
2336  numoldchecks = 0;
2337 
2338  /*
2339  * Create a dummy ParseState and insert the target relation as its sole
2340  * rangetable entry. We need a ParseState for transformExpr.
2341  */
2342  pstate = make_parsestate(NULL);
2343  pstate->p_sourcetext = queryString;
2344  nsitem = addRangeTableEntryForRelation(pstate,
2345  rel,
2347  NULL,
2348  false,
2349  true);
2350  addNSItemToQuery(pstate, nsitem, true, true, true);
2351 
2352  /*
2353  * Process column default expressions.
2354  */
2355  foreach(cell, newColDefaults)
2356  {
2357  RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
2358  Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
2359  Oid defOid;
2360 
2361  expr = cookDefault(pstate, colDef->raw_default,
2362  atp->atttypid, atp->atttypmod,
2363  NameStr(atp->attname),
2364  atp->attgenerated);
2365 
2366  /*
2367  * If the expression is just a NULL constant, we do not bother to make
2368  * an explicit pg_attrdef entry, since the default behavior is
2369  * equivalent. This applies to column defaults, but not for
2370  * generation expressions.
2371  *
2372  * Note a nonobvious property of this test: if the column is of a
2373  * domain type, what we'll get is not a bare null Const but a
2374  * CoerceToDomain expr, so we will not discard the default. This is
2375  * critical because the column default needs to be retained to
2376  * override any default that the domain might have.
2377  */
2378  if (expr == NULL ||
2379  (!colDef->generated &&
2380  IsA(expr, Const) &&
2381  castNode(Const, expr)->constisnull))
2382  continue;
2383 
2384  /* If the DEFAULT is volatile we cannot use a missing value */
2385  if (colDef->missingMode &&
2387  colDef->missingMode = false;
2388 
2389  defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal,
2390  colDef->missingMode);
2391 
2392  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2393  cooked->contype = CONSTR_DEFAULT;
2394  cooked->conoid = defOid;
2395  cooked->name = NULL;
2396  cooked->attnum = colDef->attnum;
2397  cooked->expr = expr;
2398  cooked->skip_validation = false;
2399  cooked->is_local = is_local;
2400  cooked->inhcount = is_local ? 0 : 1;
2401  cooked->is_no_inherit = false;
2402  cookedConstraints = lappend(cookedConstraints, cooked);
2403  }
2404 
2405  /*
2406  * Process constraint expressions.
2407  */
2408  numchecks = numoldchecks;
2409  checknames = NIL;
2410  nnnames = NIL;
2411  foreach(cell, newConstraints)
2412  {
2413  Constraint *cdef = (Constraint *) lfirst(cell);
2414  Oid constrOid;
2415 
2416  if (cdef->contype == CONSTR_CHECK)
2417  {
2418  char *ccname;
2419 
2420  if (cdef->raw_expr != NULL)
2421  {
2422  Assert(cdef->cooked_expr == NULL);
2423 
2424  /*
2425  * Transform raw parsetree to executable expression, and
2426  * verify it's valid as a CHECK constraint.
2427  */
2428  expr = cookConstraint(pstate, cdef->raw_expr,
2430  }
2431  else
2432  {
2433  Assert(cdef->cooked_expr != NULL);
2434 
2435  /*
2436  * Here, we assume the parser will only pass us valid CHECK
2437  * expressions, so we do no particular checking.
2438  */
2439  expr = stringToNode(cdef->cooked_expr);
2440  }
2441 
2442  /*
2443  * Check name uniqueness, or generate a name if none was given.
2444  */
2445  if (cdef->conname != NULL)
2446  {
2447  ListCell *cell2;
2448 
2449  ccname = cdef->conname;
2450  /* Check against other new constraints */
2451  /* Needed because we don't do CommandCounterIncrement in loop */
2452  foreach(cell2, checknames)
2453  {
2454  if (strcmp((char *) lfirst(cell2), ccname) == 0)
2455  ereport(ERROR,
2457  errmsg("check constraint \"%s\" already exists",
2458  ccname)));
2459  }
2460 
2461  /* save name for future checks */
2462  checknames = lappend(checknames, ccname);
2463 
2464  /*
2465  * Check against pre-existing constraints. If we are allowed
2466  * to merge with an existing constraint, there's no more to do
2467  * here. (We omit the duplicate constraint from the result,
2468  * which is what ATAddCheckConstraint wants.)
2469  */
2470  if (MergeWithExistingConstraint(rel, ccname, expr,
2471  allow_merge, is_local,
2472  cdef->initially_valid,
2473  cdef->is_no_inherit))
2474  continue;
2475  }
2476  else
2477  {
2478  /*
2479  * When generating a name, we want to create "tab_col_check"
2480  * for a column constraint and "tab_check" for a table
2481  * constraint. We no longer have any info about the syntactic
2482  * positioning of the constraint phrase, so we approximate
2483  * this by seeing whether the expression references more than
2484  * one column. (If the user played by the rules, the result
2485  * is the same...)
2486  *
2487  * Note: pull_var_clause() doesn't descend into sublinks, but
2488  * we eliminated those above; and anyway this only needs to be
2489  * an approximate answer.
2490  */
2491  List *vars;
2492  char *colname;
2493 
2494  vars = pull_var_clause(expr, 0);
2495 
2496  /* eliminate duplicates */
2497  vars = list_union(NIL, vars);
2498 
2499  if (list_length(vars) == 1)
2500  colname = get_attname(RelationGetRelid(rel),
2501  ((Var *) linitial(vars))->varattno,
2502  true);
2503  else
2504  colname = NULL;
2505 
2507  colname,
2508  "check",
2509  RelationGetNamespace(rel),
2510  checknames);
2511 
2512  /* save name for future checks */
2513  checknames = lappend(checknames, ccname);
2514  }
2515 
2516  /*
2517  * OK, store it.
2518  */
2519  constrOid =
2520  StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
2521  is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
2522 
2523  numchecks++;
2524 
2525  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2526  cooked->contype = CONSTR_CHECK;
2527  cooked->conoid = constrOid;
2528  cooked->name = ccname;
2529  cooked->attnum = 0;
2530  cooked->expr = expr;
2531  cooked->skip_validation = cdef->skip_validation;
2532  cooked->is_local = is_local;
2533  cooked->inhcount = is_local ? 0 : 1;
2534  cooked->is_no_inherit = cdef->is_no_inherit;
2535  cookedConstraints = lappend(cookedConstraints, cooked);
2536  }
2537  else if (cdef->contype == CONSTR_NOTNULL)
2538  {
2539  CookedConstraint *nncooked;
2540  AttrNumber colnum;
2541  char *nnname;
2542  int existing;
2543 
2544  /* Determine which column to modify */
2545  colnum = get_attnum(RelationGetRelid(rel), strVal(linitial(cdef->keys)));
2546  if (colnum == InvalidAttrNumber) /* shouldn't happen */
2547  elog(ERROR, "cache lookup failed for attribute \"%s\" of relation %u",
2548  strVal(linitial(cdef->keys)), RelationGetRelid(rel));
2549 
2550  /*
2551  * If the column already has an inheritable not-null constraint,
2552  * we need only adjust its inheritance status and we're done. If
2553  * the constraint is there but marked NO INHERIT, then it is
2554  * updated in the same way, but we also recurse to the children
2555  * (if any) to add the constraint there as well.
2556  */
2557  existing = AdjustNotNullInheritance1(RelationGetRelid(rel), colnum,
2558  cdef->inhcount, cdef->is_no_inherit);
2559  if (existing == 1)
2560  continue; /* all done! */
2561  else if (existing == -1)
2562  {
2563  List *children;
2564 
2566  foreach_oid(childoid, children)
2567  {
2568  Relation childrel = table_open(childoid, NoLock);
2569 
2570  AddRelationNewConstraints(childrel,
2571  NIL,
2572  list_make1(copyObject(cdef)),
2573  allow_merge,
2574  is_local,
2575  is_internal,
2576  queryString);
2577  /* these constraints are not in the return list -- good? */
2578 
2579  table_close(childrel, NoLock);
2580  }
2581 
2582  continue;
2583  }
2584 
2585  /*
2586  * If a constraint name is specified, check that it isn't already
2587  * used. Otherwise, choose a non-conflicting one ourselves.
2588  */
2589  if (cdef->conname)
2590  {
2592  RelationGetRelid(rel),
2593  cdef->conname))
2594  ereport(ERROR,
2596  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2597  cdef->conname, RelationGetRelationName(rel)));
2598  nnname = cdef->conname;
2599  }
2600  else
2602  strVal(linitial(cdef->keys)),
2603  "not_null",
2604  RelationGetNamespace(rel),
2605  nnnames);
2606  nnnames = lappend(nnnames, nnname);
2607 
2608  constrOid =
2609  StoreRelNotNull(rel, nnname, colnum,
2610  cdef->initially_valid,
2611  cdef->inhcount == 0,
2612  cdef->inhcount,
2613  cdef->is_no_inherit);
2614 
2615  nncooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2616  nncooked->contype = CONSTR_NOTNULL;
2617  nncooked->conoid = constrOid;
2618  nncooked->name = nnname;
2619  nncooked->attnum = colnum;
2620  nncooked->expr = NULL;
2621  nncooked->skip_validation = cdef->skip_validation;
2622  nncooked->is_local = is_local;
2623  nncooked->inhcount = cdef->inhcount;
2624  nncooked->is_no_inherit = cdef->is_no_inherit;
2625 
2626  cookedConstraints = lappend(cookedConstraints, nncooked);
2627  }
2628  }
2629 
2630  /*
2631  * Update the count of constraints in the relation's pg_class tuple. We do
2632  * this even if there was no change, in order to ensure that an SI update
2633  * message is sent out for the pg_class tuple, which will force other
2634  * backends to rebuild their relcache entries for the rel. (This is
2635  * critical if we added defaults but not constraints.)
2636  */
2637  SetRelationNumChecks(rel, numchecks);
2638 
2639  return cookedConstraints;
2640 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:746
#define Assert(condition)
Definition: c.h:858
bool contain_volatile_functions_after_planning(Expr *expr)
Definition: clauses.c:659
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr, bool is_validated, bool is_local, int inhcount, bool is_no_inherit, bool is_internal)
Definition: heap.c:2066
static bool MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, bool allow_merge, bool is_local, bool is_initially_valid, bool is_no_inherit)
Definition: heap.c:2653
static Oid StoreRelNotNull(Relation rel, const char *nnname, AttrNumber attnum, bool is_validated, bool is_local, int inhcount, bool is_no_inherit)
Definition: heap.c:2172
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3114
static void SetRelationNumChecks(Relation rel, int numchecks)
Definition: heap.c:3020
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2307
static Node * cookConstraint(ParseState *pstate, Node *raw_constraint, char *relname)
Definition: heap.c:3191
List * list_union(const List *list1, const List *list2)
Definition: list.c:1066
List * lappend(List *list, void *datum)
Definition: list.c:339
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
void * palloc(Size size)
Definition: mcxt.c:1316
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
@ CONSTR_DEFAULT
Definition: parsenodes.h:2710
@ CONSTR_NOTNULL
Definition: parsenodes.h:2709
@ CONSTR_CHECK
Definition: parsenodes.h:2713
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
Definition: pg_attrdef.c:46
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
int AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count, bool is_no_inherit)
@ CONSTRAINT_RELATION
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
#define foreach_oid(var, lst)
Definition: pg_list.h:471
unsigned int Oid
Definition: postgres_ext.h:31
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
List * keys
Definition: parsenodes.h:2754
ConstrType contype
Definition: parsenodes.h:2739
bool is_no_inherit
Definition: parsenodes.h:2745
char * cooked_expr
Definition: parsenodes.h:2748
bool initially_valid
Definition: parsenodes.h:2744
bool skip_validation
Definition: parsenodes.h:2743
Node * raw_expr
Definition: parsenodes.h:2746
char * conname
Definition: parsenodes.h:2740
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
int inhcount
Definition: heap.h:45
bool is_local
Definition: heap.h:44
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
Definition: pg_list.h:54
Definition: nodes.h:129
const char * p_sourcetext
Definition: parse_node.h:193
Node * raw_default
Definition: heap.h:30
AttrNumber attnum
Definition: heap.h:29
char generated
Definition: heap.h:32
bool missingMode
Definition: heap.h:31
TupleDesc rd_att
Definition: rel.h:112
uint16 num_check
Definition: tupdesc.h:43
TupleConstr * constr
Definition: tupdesc.h:85
Definition: primnodes.h:248
Definition: regcomp.c:281
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define strVal(v)
Definition: value.h:82
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), AdjustNotNullInheritance1(), Assert, RawColumnDefault::attnum, CookedConstraint::attnum, castNode, ChooseConstraintName(), Constraint::conname, CookedConstraint::conoid, TupleDescData::constr, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_NOTNULL, CONSTRAINT_RELATION, ConstraintNameIsUsed(), contain_volatile_functions_after_planning(), CookedConstraint::contype, Constraint::contype, cookConstraint(), cookDefault(), Constraint::cooked_expr, copyObject, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CookedConstraint::expr, find_inheritance_children(), foreach_oid, RawColumnDefault::generated, get_attname(), get_attnum(), CookedConstraint::inhcount, Constraint::inhcount, Constraint::initially_valid, InvalidAttrNumber, CookedConstraint::is_local, CookedConstraint::is_no_inherit, Constraint::is_no_inherit, IsA, Constraint::keys, lappend(), lfirst, linitial, list_length(), list_make1, list_union(), make_parsestate(), MergeWithExistingConstraint(), RawColumnDefault::missingMode, CookedConstraint::name, NameStr, NIL, NoLock, TupleConstr::num_check, ParseState::p_sourcetext, palloc(), pull_var_clause(), RawColumnDefault::raw_default, Constraint::raw_expr, RelationData::rd_att, RelationGetDescr, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, SetRelationNumChecks(), CookedConstraint::skip_validation, Constraint::skip_validation, StoreAttrDefault(), StoreRelCheck(), StoreRelNotNull(), stringToNode(), strVal, table_close(), table_open(), and TupleDescAttr.

Referenced by ATAddCheckNNConstraint(), ATExecAddColumn(), ATExecColumnDefault(), ATExecSetExpression(), ATExecSetNotNull(), and DefineRelation().

◆ AddRelationNotNullConstraints()

List* AddRelationNotNullConstraints ( Relation  rel,
List constraints,
List additional_notnulls 
)

Definition at line 2827 of file heap.c.

2829 {
2830  List *givennames;
2831  List *nnnames;
2832  List *nncols = NIL;
2833  ListCell *lc;
2834 
2835  /*
2836  * We track two lists of names: nnnames keeps all the constraint names,
2837  * givennames tracks user-generated names. The distinction is important,
2838  * because we must raise error for user-generated name conflicts, but for
2839  * system-generated name conflicts we just generate another.
2840  */
2841  nnnames = NIL;
2842  givennames = NIL;
2843 
2844  /*
2845  * First, create all not-null constraints that are directly specified by
2846  * the user. Note that inheritance might have given us another source for
2847  * each, so we must scan the old_notnulls list and increment inhcount for
2848  * each element with identical attnum. We delete from there any element
2849  * that we process.
2850  */
2851  foreach(lc, constraints)
2852  {
2853  Constraint *constr = lfirst_node(Constraint, lc);
2855  char *conname;
2856  bool is_local = true;
2857  int inhcount = 0;
2858  ListCell *lc2;
2859 
2860  Assert(constr->contype == CONSTR_NOTNULL);
2861 
2863  strVal(linitial(constr->keys)));
2864 
2865  /*
2866  * Search in the list of inherited constraints for any entries on the
2867  * same column.
2868  */
2869  foreach(lc2, old_notnulls)
2870  {
2871  CookedConstraint *old = (CookedConstraint *) lfirst(lc2);
2872 
2873  if (old->attnum == attnum)
2874  {
2875  /*
2876  * If we get a constraint from the parent, having a local NO
2877  * INHERIT one doesn't work.
2878  */
2879  if (constr->is_no_inherit)
2880  ereport(ERROR,
2881  (errcode(ERRCODE_DATATYPE_MISMATCH),
2882  errmsg("cannot define not-null constraint on column \"%s\" with NO INHERIT",
2883  strVal(linitial(constr->keys))),
2884  errdetail("The column has an inherited not-null constraint.")));
2885 
2886  inhcount++;
2887  old_notnulls = foreach_delete_current(old_notnulls, lc2);
2888  }
2889  }
2890 
2891  /*
2892  * Determine a constraint name, which may have been specified by the
2893  * user, or raise an error if a conflict exists with another
2894  * user-specified name.
2895  */
2896  if (constr->conname)
2897  {
2898  foreach(lc2, givennames)
2899  {
2900  if (strcmp(lfirst(lc2), constr->conname) == 0)
2901  ereport(ERROR,
2903  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2904  constr->conname,
2905  RelationGetRelationName(rel)));
2906  }
2907 
2908  conname = constr->conname;
2909  givennames = lappend(givennames, conname);
2910  }
2911  else
2914  attnum, false),
2915  "not_null",
2916  RelationGetNamespace(rel),
2917  nnnames);
2918  nnnames = lappend(nnnames, conname);
2919 
2920  StoreRelNotNull(rel, conname,
2921  attnum, true, is_local,
2922  inhcount, constr->is_no_inherit);
2923 
2924  nncols = lappend_int(nncols, attnum);
2925  }
2926 
2927  /*
2928  * If any column remains in the old_notnulls list, we must create a not-
2929  * null constraint marked not-local. Because multiple parents could
2930  * specify a not-null constraint for the same column, we must count how
2931  * many there are and add to the original inhcount accordingly, deleting
2932  * elements we've already processed. We sort the list to make it easy.
2933  *
2934  * We don't use foreach() here because we have two nested loops over the
2935  * constraint list, with possible element deletions in the inner one. If
2936  * we used foreach_delete_current() it could only fix up the state of one
2937  * of the loops, so it seems cleaner to use looping over list indexes for
2938  * both loops. Note that any deletion will happen beyond where the outer
2939  * loop is, so its index never needs adjustment.
2940  */
2941  list_sort(old_notnulls, list_cookedconstr_attnum_cmp);
2942  for (int outerpos = 0; outerpos < list_length(old_notnulls); outerpos++)
2943  {
2944  CookedConstraint *cooked;
2945  char *conname = NULL;
2946  int add_inhcount = 0;
2947  ListCell *lc2;
2948 
2949  cooked = (CookedConstraint *) list_nth(old_notnulls, outerpos);
2950  Assert(cooked->contype == CONSTR_NOTNULL);
2951 
2952  /*
2953  * Preserve the first non-conflicting constraint name we come across,
2954  * if any
2955  */
2956  if (conname == NULL && cooked->name)
2957  conname = cooked->name;
2958 
2959  for (int restpos = outerpos + 1; restpos < list_length(old_notnulls);)
2960  {
2961  CookedConstraint *other;
2962 
2963  other = (CookedConstraint *) list_nth(old_notnulls, restpos);
2964  if (other->attnum == cooked->attnum)
2965  {
2966  if (conname == NULL && other->name)
2967  conname = other->name;
2968 
2969  add_inhcount++;
2970  old_notnulls = list_delete_nth_cell(old_notnulls, restpos);
2971  }
2972  else
2973  restpos++;
2974  }
2975 
2976  /* If we got a name, make sure it isn't one we've already used */
2977  if (conname != NULL)
2978  {
2979  foreach(lc2, nnnames)
2980  {
2981  if (strcmp(lfirst(lc2), conname) == 0)
2982  {
2983  conname = NULL;
2984  break;
2985  }
2986  }
2987  }
2988 
2989  /* and choose a name, if needed */
2990  if (conname == NULL)
2993  cooked->attnum, false),
2994  "not_null",
2995  RelationGetNamespace(rel),
2996  nnnames);
2997  nnnames = lappend(nnnames, conname);
2998 
2999  StoreRelNotNull(rel, conname, cooked->attnum, true,
3000  cooked->is_local, cooked->inhcount + add_inhcount,
3001  cooked->is_no_inherit);
3002 
3003  nncols = lappend_int(nncols, cooked->attnum);
3004  }
3005 
3006  return nncols;
3007 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
static int list_cookedconstr_attnum_cmp(const ListCell *p1, const ListCell *p2)
Definition: heap.c:2799
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * list_delete_nth_cell(List *list, int n)
Definition: list.c:767
int16 attnum
Definition: pg_attribute.h:74
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299

References Assert, CookedConstraint::attnum, attnum, ChooseConstraintName(), Constraint::conname, CONSTR_NOTNULL, CookedConstraint::contype, Constraint::contype, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, foreach_delete_current, get_attname(), get_attnum(), CookedConstraint::inhcount, CookedConstraint::is_local, CookedConstraint::is_no_inherit, Constraint::is_no_inherit, Constraint::keys, lappend(), lappend_int(), lfirst, lfirst_node, linitial, list_cookedconstr_attnum_cmp(), list_delete_nth_cell(), list_length(), list_nth(), list_sort(), CookedConstraint::name, NIL, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, StoreRelNotNull(), and strVal.

Referenced by DefineRelation().

◆ CheckAttributeNamesTypes()

void CheckAttributeNamesTypes ( TupleDesc  tupdesc,
char  relkind,
int  flags 
)

Definition at line 456 of file heap.c.

458 {
459  int i;
460  int j;
461  int natts = tupdesc->natts;
462 
463  /* Sanity check on column count */
464  if (natts < 0 || natts > MaxHeapAttributeNumber)
465  ereport(ERROR,
466  (errcode(ERRCODE_TOO_MANY_COLUMNS),
467  errmsg("tables can have at most %d columns",
469 
470  /*
471  * first check for collision with system attribute names
472  *
473  * Skip this for a view or type relation, since those don't have system
474  * attributes.
475  */
476  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
477  {
478  for (i = 0; i < natts; i++)
479  {
480  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
481 
482  if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
483  ereport(ERROR,
484  (errcode(ERRCODE_DUPLICATE_COLUMN),
485  errmsg("column name \"%s\" conflicts with a system column name",
486  NameStr(attr->attname))));
487  }
488  }
489 
490  /*
491  * next check for repeated attribute names
492  */
493  for (i = 1; i < natts; i++)
494  {
495  for (j = 0; j < i; j++)
496  {
497  if (strcmp(NameStr(TupleDescAttr(tupdesc, j)->attname),
498  NameStr(TupleDescAttr(tupdesc, i)->attname)) == 0)
499  ereport(ERROR,
500  (errcode(ERRCODE_DUPLICATE_COLUMN),
501  errmsg("column name \"%s\" specified more than once",
502  NameStr(TupleDescAttr(tupdesc, j)->attname))));
503  }
504  }
505 
506  /*
507  * next check the attribute types
508  */
509  for (i = 0; i < natts; i++)
510  {
512  TupleDescAttr(tupdesc, i)->atttypid,
513  TupleDescAttr(tupdesc, i)->attcollation,
514  NIL, /* assume we're creating a new rowtype */
515  flags);
516  }
517 }
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:548
const FormData_pg_attribute * SystemAttributeByName(const char *attname)
Definition: heap.c:252
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
int j
Definition: isn.c:74
int i
Definition: isn.c:73
NameData attname
Definition: pg_attribute.h:41

References attname, CheckAttributeType(), ereport, errcode(), errmsg(), ERROR, i, j, MaxHeapAttributeNumber, NameStr, TupleDescData::natts, NIL, SystemAttributeByName(), and TupleDescAttr.

Referenced by addRangeTableEntryForFunction(), and heap_create_with_catalog().

◆ CheckAttributeType()

void CheckAttributeType ( const char *  attname,
Oid  atttypid,
Oid  attcollation,
List containing_rowtypes,
int  flags 
)

Definition at line 548 of file heap.c.

552 {
553  char att_typtype = get_typtype(atttypid);
554  Oid att_typelem;
555 
556  /* since this function recurses, it could be driven to stack overflow */
558 
559  if (att_typtype == TYPTYPE_PSEUDO)
560  {
561  /*
562  * We disallow pseudo-type columns, with the exception of ANYARRAY,
563  * RECORD, and RECORD[] when the caller says that those are OK.
564  *
565  * We don't need to worry about recursive containment for RECORD and
566  * RECORD[] because (a) no named composite type should be allowed to
567  * contain those, and (b) two "anonymous" record types couldn't be
568  * considered to be the same type, so infinite recursion isn't
569  * possible.
570  */
571  if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
572  (atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
573  (atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
574  {
575  if (flags & CHKATYPE_IS_PARTKEY)
576  ereport(ERROR,
577  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
578  /* translator: first %s is an integer not a name */
579  errmsg("partition key column %s has pseudo-type %s",
580  attname, format_type_be(atttypid))));
581  else
582  ereport(ERROR,
583  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
584  errmsg("column \"%s\" has pseudo-type %s",
585  attname, format_type_be(atttypid))));
586  }
587  }
588  else if (att_typtype == TYPTYPE_DOMAIN)
589  {
590  /*
591  * If it's a domain, recurse to check its base type.
592  */
593  CheckAttributeType(attname, getBaseType(atttypid), attcollation,
594  containing_rowtypes,
595  flags);
596  }
597  else if (att_typtype == TYPTYPE_COMPOSITE)
598  {
599  /*
600  * For a composite type, recurse into its attributes.
601  */
602  Relation relation;
603  TupleDesc tupdesc;
604  int i;
605 
606  /*
607  * Check for self-containment. Eventually we might be able to allow
608  * this (just return without complaint, if so) but it's not clear how
609  * many other places would require anti-recursion defenses before it
610  * would be safe to allow tables to contain their own rowtype.
611  */
612  if (list_member_oid(containing_rowtypes, atttypid))
613  ereport(ERROR,
614  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
615  errmsg("composite type %s cannot be made a member of itself",
616  format_type_be(atttypid))));
617 
618  containing_rowtypes = lappend_oid(containing_rowtypes, atttypid);
619 
620  relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);
621 
622  tupdesc = RelationGetDescr(relation);
623 
624  for (i = 0; i < tupdesc->natts; i++)
625  {
626  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
627 
628  if (attr->attisdropped)
629  continue;
630  CheckAttributeType(NameStr(attr->attname),
631  attr->atttypid, attr->attcollation,
632  containing_rowtypes,
633  flags & ~CHKATYPE_IS_PARTKEY);
634  }
635 
636  relation_close(relation, AccessShareLock);
637 
638  containing_rowtypes = list_delete_last(containing_rowtypes);
639  }
640  else if (att_typtype == TYPTYPE_RANGE)
641  {
642  /*
643  * If it's a range, recurse to check its subtype.
644  */
646  get_range_collation(atttypid),
647  containing_rowtypes,
648  flags);
649  }
650  else if (OidIsValid((att_typelem = get_element_type(atttypid))))
651  {
652  /*
653  * Must recurse into array types, too, in case they are composite.
654  */
655  CheckAttributeType(attname, att_typelem, attcollation,
656  containing_rowtypes,
657  flags);
658  }
659 
660  /*
661  * This might not be strictly invalid per SQL standard, but it is pretty
662  * useless, and it cannot be dumped, so we must disallow it.
663  */
664  if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
665  {
666  if (flags & CHKATYPE_IS_PARTKEY)
667  ereport(ERROR,
668  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
669  /* translator: first %s is an integer not a name */
670  errmsg("no collation was derived for partition key column %s with collatable type %s",
671  attname, format_type_be(atttypid)),
672  errhint("Use the COLLATE clause to set the collation explicitly.")));
673  else
674  ereport(ERROR,
675  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
676  errmsg("no collation was derived for column \"%s\" with collatable type %s",
677  attname, format_type_be(atttypid)),
678  errhint("Use the COLLATE clause to set the collation explicitly.")));
679  }
680 }
#define OidIsValid(objectId)
Definition: c.h:775
int errhint(const char *fmt,...)
Definition: elog.c:1319
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
#define CHKATYPE_ANYRECORD
Definition: heap.h:24
#define CHKATYPE_ANYARRAY
Definition: heap.h:23
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * list_delete_last(List *list)
Definition: list.c:957
Oid get_range_subtype(Oid rangeOid)
Definition: lsyscache.c:3407
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
Oid get_range_collation(Oid rangeOid)
Definition: lsyscache.c:3433
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3081
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2731
char get_typtype(Oid typid)
Definition: lsyscache.c:2629
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
void check_stack_depth(void)
Definition: postgres.c:3531
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47

References AccessShareLock, attname, check_stack_depth(), CHKATYPE_ANYARRAY, CHKATYPE_ANYRECORD, CHKATYPE_IS_PARTKEY, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_element_type(), get_range_collation(), get_range_subtype(), get_typ_typrelid(), get_typtype(), getBaseType(), i, lappend_oid(), list_delete_last(), list_member_oid(), NameStr, TupleDescData::natts, OidIsValid, relation_close(), relation_open(), RelationGetDescr, TupleDescAttr, and type_is_collatable().

Referenced by ATExecAddColumn(), ATPrepAlterColumnType(), CheckAttributeNamesTypes(), ComputePartitionAttrs(), and ConstructTupleDescriptor().

◆ cookDefault()

Node* cookDefault ( ParseState pstate,
Node raw_default,
Oid  atttypid,
int32  atttypmod,
const char *  attname,
char  attgenerated 
)

Definition at line 3114 of file heap.c.

3120 {
3121  Node *expr;
3122 
3123  Assert(raw_default != NULL);
3124 
3125  /*
3126  * Transform raw parsetree to executable expression.
3127  */
3128  expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3129 
3130  if (attgenerated)
3131  {
3132  /* Disallow refs to other generated columns */
3133  check_nested_generated(pstate, expr);
3134 
3135  /* Disallow mutable functions */
3137  ereport(ERROR,
3138  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3139  errmsg("generation expression is not immutable")));
3140  }
3141  else
3142  {
3143  /*
3144  * For a default expression, transformExpr() should have rejected
3145  * column references.
3146  */
3147  Assert(!contain_var_clause(expr));
3148  }
3149 
3150  /*
3151  * Coerce the expression to the correct type and typmod, if given. This
3152  * should match the parser's processing of non-defaulted expressions ---
3153  * see transformAssignedExpr().
3154  */
3155  if (OidIsValid(atttypid))
3156  {
3157  Oid type_id = exprType(expr);
3158 
3159  expr = coerce_to_target_type(pstate, expr, type_id,
3160  atttypid, atttypmod,
3163  -1);
3164  if (expr == NULL)
3165  ereport(ERROR,
3166  (errcode(ERRCODE_DATATYPE_MISMATCH),
3167  errmsg("column \"%s\" is of type %s"
3168  " but default expression is of type %s",
3169  attname,
3170  format_type_be(atttypid),
3171  format_type_be(type_id)),
3172  errhint("You will need to rewrite or cast the expression.")));
3173  }
3174 
3175  /*
3176  * Finally, take care of collations in the finished expression.
3177  */
3178  assign_expr_collations(pstate, expr);
3179 
3180  return expr;
3181 }
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:490
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3096
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:121
@ EXPR_KIND_COLUMN_DEFAULT
Definition: parse_node.h:70
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:83
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:706
@ COERCION_ASSIGNMENT
Definition: primnodes.h:685
bool contain_var_clause(Node *node)
Definition: var.c:403

References Assert, assign_expr_collations(), attname, check_nested_generated(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, contain_mutable_functions_after_planning(), contain_var_clause(), ereport, errcode(), errhint(), errmsg(), ERROR, EXPR_KIND_COLUMN_DEFAULT, EXPR_KIND_GENERATED_COLUMN, exprType(), format_type_be(), OidIsValid, and transformExpr().

Referenced by AddRelationNewConstraints(), AlterDomainDefault(), and DefineDomain().

◆ CopyStatistics()

void CopyStatistics ( Oid  fromrelid,
Oid  torelid 
)

Definition at line 3229 of file heap.c.

3230 {
3231  HeapTuple tup;
3232  SysScanDesc scan;
3233  ScanKeyData key[1];
3234  Relation statrel;
3235  CatalogIndexState indstate = NULL;
3236 
3237  statrel = table_open(StatisticRelationId, RowExclusiveLock);
3238 
3239  /* Now search for stat records */
3240  ScanKeyInit(&key[0],
3241  Anum_pg_statistic_starelid,
3242  BTEqualStrategyNumber, F_OIDEQ,
3243  ObjectIdGetDatum(fromrelid));
3244 
3245  scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3246  true, NULL, 1, key);
3247 
3248  while (HeapTupleIsValid((tup = systable_getnext(scan))))
3249  {
3250  Form_pg_statistic statform;
3251 
3252  /* make a modifiable copy */
3253  tup = heap_copytuple(tup);
3254  statform = (Form_pg_statistic) GETSTRUCT(tup);
3255 
3256  /* update the copy of the tuple and insert it */
3257  statform->starelid = torelid;
3258 
3259  /* fetch index information when we know we need it */
3260  if (indstate == NULL)
3261  indstate = CatalogOpenIndexes(statrel);
3262 
3263  CatalogTupleInsertWithInfo(statrel, tup, indstate);
3264 
3265  heap_freetuple(tup);
3266  }
3267 
3268  systable_endscan(scan);
3269 
3270  if (indstate != NULL)
3271  CatalogCloseIndexes(indstate);
3272  table_close(statrel, RowExclusiveLock);
3273 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:256
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_statistic * Form_pg_statistic
Definition: pg_statistic.h:135
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References BTEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleInsertWithInfo(), GETSTRUCT, heap_copytuple(), heap_freetuple(), HeapTupleIsValid, sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by index_concurrently_swap().

◆ DeleteAttributeTuples()

void DeleteAttributeTuples ( Oid  relid)

Definition at line 1578 of file heap.c.

1579 {
1580  Relation attrel;
1581  SysScanDesc scan;
1582  ScanKeyData key[1];
1583  HeapTuple atttup;
1584 
1585  /* Grab an appropriate lock on the pg_attribute relation */
1586  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1587 
1588  /* Use the index to scan only attributes of the target relation */
1589  ScanKeyInit(&key[0],
1590  Anum_pg_attribute_attrelid,
1591  BTEqualStrategyNumber, F_OIDEQ,
1592  ObjectIdGetDatum(relid));
1593 
1594  scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1595  NULL, 1, key);
1596 
1597  /* Delete all the matching tuples */
1598  while ((atttup = systable_getnext(scan)) != NULL)
1599  CatalogTupleDelete(attrel, &atttup->t_self);
1600 
1601  /* Clean up after the scan */
1602  systable_endscan(scan);
1603  table_close(attrel, RowExclusiveLock);
1604 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
ItemPointerData t_self
Definition: htup.h:65

References BTEqualStrategyNumber, CatalogTupleDelete(), sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteRelationTuple()

void DeleteRelationTuple ( Oid  relid)

Definition at line 1549 of file heap.c.

1550 {
1551  Relation pg_class_desc;
1552  HeapTuple tup;
1553 
1554  /* Grab an appropriate lock on the pg_class relation */
1555  pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
1556 
1557  tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1558  if (!HeapTupleIsValid(tup))
1559  elog(ERROR, "cache lookup failed for relation %u", relid);
1560 
1561  /* delete the relation tuple from pg_class, and finish up */
1562  CatalogTupleDelete(pg_class_desc, &tup->t_self);
1563 
1564  ReleaseSysCache(tup);
1565 
1566  table_close(pg_class_desc, RowExclusiveLock);
1567 }
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteSystemAttributeTuples()

void DeleteSystemAttributeTuples ( Oid  relid)

Definition at line 1615 of file heap.c.

1616 {
1617  Relation attrel;
1618  SysScanDesc scan;
1619  ScanKeyData key[2];
1620  HeapTuple atttup;
1621 
1622  /* Grab an appropriate lock on the pg_attribute relation */
1623  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1624 
1625  /* Use the index to scan only system attributes of the target relation */
1626  ScanKeyInit(&key[0],
1627  Anum_pg_attribute_attrelid,
1628  BTEqualStrategyNumber, F_OIDEQ,
1629  ObjectIdGetDatum(relid));
1630  ScanKeyInit(&key[1],
1631  Anum_pg_attribute_attnum,
1632  BTLessEqualStrategyNumber, F_INT2LE,
1633  Int16GetDatum(0));
1634 
1635  scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1636  NULL, 2, key);
1637 
1638  /* Delete all the matching tuples */
1639  while ((atttup = systable_getnext(scan)) != NULL)
1640  CatalogTupleDelete(attrel, &atttup->t_self);
1641 
1642  /* Clean up after the scan */
1643  systable_endscan(scan);
1644  table_close(attrel, RowExclusiveLock);
1645 }
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30

References BTEqualStrategyNumber, BTLessEqualStrategyNumber, CatalogTupleDelete(), Int16GetDatum(), sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

◆ heap_create()

Relation heap_create ( const char *  relname,
Oid  relnamespace,
Oid  reltablespace,
Oid  relid,
RelFileNumber  relfilenumber,
Oid  accessmtd,
TupleDesc  tupDesc,
char  relkind,
char  relpersistence,
bool  shared_relation,
bool  mapped_relation,
bool  allow_system_table_mods,
TransactionId relfrozenxid,
MultiXactId relminmxid,
bool  create_storage 
)

Definition at line 289 of file heap.c.

304 {
305  Relation rel;
306 
307  /* The caller must have provided an OID for the relation. */
308  Assert(OidIsValid(relid));
309 
310  /*
311  * Don't allow creating relations in pg_catalog directly, even though it
312  * is allowed to move user defined relations there. Semantics with search
313  * paths including pg_catalog are too confusing for now.
314  *
315  * But allow creating indexes on relations in pg_catalog even if
316  * allow_system_table_mods = off, upper layers already guarantee it's on a
317  * user defined relation, not a system one.
318  */
319  if (!allow_system_table_mods &&
320  ((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
321  IsToastNamespace(relnamespace)) &&
323  ereport(ERROR,
324  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
325  errmsg("permission denied to create \"%s.%s\"",
326  get_namespace_name(relnamespace), relname),
327  errdetail("System catalog modifications are currently disallowed.")));
328 
329  *relfrozenxid = InvalidTransactionId;
330  *relminmxid = InvalidMultiXactId;
331 
332  /*
333  * Force reltablespace to zero if the relation kind does not support
334  * tablespaces. This is mainly just for cleanliness' sake.
335  */
336  if (!RELKIND_HAS_TABLESPACE(relkind))
337  reltablespace = InvalidOid;
338 
339  /* Don't create storage for relkinds without physical storage. */
340  if (!RELKIND_HAS_STORAGE(relkind))
341  create_storage = false;
342  else
343  {
344  /*
345  * If relfilenumber is unspecified by the caller then create storage
346  * with oid same as relid.
347  */
348  if (!RelFileNumberIsValid(relfilenumber))
349  relfilenumber = relid;
350  }
351 
352  /*
353  * Never allow a pg_class entry to explicitly specify the database's
354  * default tablespace in reltablespace; force it to zero instead. This
355  * ensures that if the database is cloned with a different default
356  * tablespace, the pg_class entry will still match where CREATE DATABASE
357  * will put the physically copied relation.
358  *
359  * Yes, this is a bit of a hack.
360  */
361  if (reltablespace == MyDatabaseTableSpace)
362  reltablespace = InvalidOid;
363 
364  /*
365  * build the relcache entry.
366  */
368  relnamespace,
369  tupDesc,
370  relid,
371  accessmtd,
372  relfilenumber,
373  reltablespace,
374  shared_relation,
375  mapped_relation,
376  relpersistence,
377  relkind);
378 
379  /*
380  * Have the storage manager create the relation's disk file, if needed.
381  *
382  * For tables, the AM callback creates both the main and the init fork.
383  * For others, only the main fork is created; the other forks will be
384  * created on demand.
385  */
386  if (create_storage)
387  {
388  if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
390  relpersistence,
391  relfrozenxid, relminmxid);
392  else if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
393  RelationCreateStorage(rel->rd_locator, relpersistence, true);
394  else
395  Assert(false);
396  }
397 
398  /*
399  * If a tablespace is specified, removal of that tablespace is normally
400  * protected by the existence of a physical file; but for relations with
401  * no files, add a pg_shdepend entry to account for that.
402  */
403  if (!create_storage && reltablespace != InvalidOid)
404  recordDependencyOnTablespace(RelationRelationId, relid,
405  reltablespace);
406 
407  /* ensure that stats are dropped if transaction aborts */
409 
410  return rel;
411 }
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:200
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
Oid MyDatabaseTableSpace
Definition: globals.c:93
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#define IsNormalProcessingMode()
Definition: miscadmin.h:456
#define InvalidMultiXactId
Definition: multixact.h:24
NameData relname
Definition: pg_class.h:38
void recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace)
Definition: pg_shdepend.c:356
void pgstat_create_relation(Relation rel)
#define InvalidOid
Definition: postgres_ext.h:36
Relation RelationBuildLocalRelation(const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid accessmtd, RelFileNumber relfilenumber, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
Definition: relcache.c:3483
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1631
#define InvalidTransactionId
Definition: transam.h:31

References Assert, ereport, errcode(), errdetail(), errmsg(), ERROR, get_namespace_name(), InvalidMultiXactId, InvalidOid, InvalidTransactionId, IsCatalogNamespace(), IsNormalProcessingMode, IsToastNamespace(), MyDatabaseTableSpace, OidIsValid, pgstat_create_relation(), RelationData::rd_locator, RelationData::rd_rel, recordDependencyOnTablespace(), RelationBuildLocalRelation(), RelationCreateStorage(), RelFileNumberIsValid, relname, and table_relation_set_new_filelocator().

Referenced by heap_create_with_catalog(), and index_create().

◆ heap_create_with_catalog()

Oid heap_create_with_catalog ( const char *  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 
)

Definition at line 1104 of file heap.c.

1125 {
1126  Relation pg_class_desc;
1127  Relation new_rel_desc;
1128  Acl *relacl;
1129  Oid existing_relid;
1130  Oid old_type_oid;
1131  Oid new_type_oid;
1132 
1133  /* By default set to InvalidOid unless overridden by binary-upgrade */
1134  RelFileNumber relfilenumber = InvalidRelFileNumber;
1135  TransactionId relfrozenxid;
1136  MultiXactId relminmxid;
1137 
1138  pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
1139 
1140  /*
1141  * sanity checks
1142  */
1144 
1145  /*
1146  * Validate proposed tupdesc for the desired relkind. If
1147  * allow_system_table_mods is on, allow ANYARRAY to be used; this is a
1148  * hack to allow creating pg_statistic and cloning it during VACUUM FULL.
1149  */
1150  CheckAttributeNamesTypes(tupdesc, relkind,
1151  allow_system_table_mods ? CHKATYPE_ANYARRAY : 0);
1152 
1153  /*
1154  * This would fail later on anyway, if the relation already exists. But
1155  * by catching it here we can emit a nicer error message.
1156  */
1157  existing_relid = get_relname_relid(relname, relnamespace);
1158  if (existing_relid != InvalidOid)
1159  ereport(ERROR,
1160  (errcode(ERRCODE_DUPLICATE_TABLE),
1161  errmsg("relation \"%s\" already exists", relname)));
1162 
1163  /*
1164  * Since we are going to create a rowtype as well, also check for
1165  * collision with an existing type name. If there is one and it's an
1166  * autogenerated array, we can rename it out of the way; otherwise we can
1167  * at least give a good error message.
1168  */
1169  old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1171  ObjectIdGetDatum(relnamespace));
1172  if (OidIsValid(old_type_oid))
1173  {
1174  if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
1175  ereport(ERROR,
1177  errmsg("type \"%s\" already exists", relname),
1178  errhint("A relation has an associated type of the same name, "
1179  "so you must use a name that doesn't conflict "
1180  "with any existing type.")));
1181  }
1182 
1183  /*
1184  * Shared relations must be in pg_global (last-ditch check)
1185  */
1186  if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
1187  elog(ERROR, "shared relations must be placed in pg_global tablespace");
1188 
1189  /*
1190  * Allocate an OID for the relation, unless we were told what to use.
1191  *
1192  * The OID will be the relfilenumber as well, so make sure it doesn't
1193  * collide with either pg_class OIDs or existing physical files.
1194  */
1195  if (!OidIsValid(relid))
1196  {
1197  /* Use binary-upgrade override for pg_class.oid and relfilenumber */
1198  if (IsBinaryUpgrade)
1199  {
1200  /*
1201  * Indexes are not supported here; they use
1202  * binary_upgrade_next_index_pg_class_oid.
1203  */
1204  Assert(relkind != RELKIND_INDEX);
1205  Assert(relkind != RELKIND_PARTITIONED_INDEX);
1206 
1207  if (relkind == RELKIND_TOASTVALUE)
1208  {
1209  /* There might be no TOAST table, so we have to test for it. */
1211  {
1214 
1216  ereport(ERROR,
1217  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1218  errmsg("toast relfilenumber value not set when in binary upgrade mode")));
1219 
1222  }
1223  }
1224  else
1225  {
1227  ereport(ERROR,
1228  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1229  errmsg("pg_class heap OID value not set when in binary upgrade mode")));
1230 
1233 
1234  if (RELKIND_HAS_STORAGE(relkind))
1235  {
1237  ereport(ERROR,
1238  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1239  errmsg("relfilenumber value not set when in binary upgrade mode")));
1240 
1243  }
1244  }
1245  }
1246 
1247  if (!OidIsValid(relid))
1248  relid = GetNewRelFileNumber(reltablespace, pg_class_desc,
1249  relpersistence);
1250  }
1251 
1252  /*
1253  * Determine the relation's initial permissions.
1254  */
1255  if (use_user_acl)
1256  {
1257  switch (relkind)
1258  {
1259  case RELKIND_RELATION:
1260  case RELKIND_VIEW:
1261  case RELKIND_MATVIEW:
1262  case RELKIND_FOREIGN_TABLE:
1263  case RELKIND_PARTITIONED_TABLE:
1264  relacl = get_user_default_acl(OBJECT_TABLE, ownerid,
1265  relnamespace);
1266  break;
1267  case RELKIND_SEQUENCE:
1268  relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid,
1269  relnamespace);
1270  break;
1271  default:
1272  relacl = NULL;
1273  break;
1274  }
1275  }
1276  else
1277  relacl = NULL;
1278 
1279  /*
1280  * Create the relcache entry (mostly dummy at this point) and the physical
1281  * disk file. (If we fail further down, it's the smgr's responsibility to
1282  * remove the disk file again.)
1283  *
1284  * NB: Note that passing create_storage = true is correct even for binary
1285  * upgrade. The storage we create here will be replaced later, but we
1286  * need to have something on disk in the meanwhile.
1287  */
1288  new_rel_desc = heap_create(relname,
1289  relnamespace,
1290  reltablespace,
1291  relid,
1292  relfilenumber,
1293  accessmtd,
1294  tupdesc,
1295  relkind,
1296  relpersistence,
1297  shared_relation,
1298  mapped_relation,
1299  allow_system_table_mods,
1300  &relfrozenxid,
1301  &relminmxid,
1302  true);
1303 
1304  Assert(relid == RelationGetRelid(new_rel_desc));
1305 
1306  new_rel_desc->rd_rel->relrewrite = relrewrite;
1307 
1308  /*
1309  * Decide whether to create a pg_type entry for the relation's rowtype.
1310  * These types are made except where the use of a relation as such is an
1311  * implementation detail: toast tables, sequences and indexes.
1312  */
1313  if (!(relkind == RELKIND_SEQUENCE ||
1314  relkind == RELKIND_TOASTVALUE ||
1315  relkind == RELKIND_INDEX ||
1316  relkind == RELKIND_PARTITIONED_INDEX))
1317  {
1318  Oid new_array_oid;
1319  ObjectAddress new_type_addr;
1320  char *relarrayname;
1321 
1322  /*
1323  * We'll make an array over the composite type, too. For largely
1324  * historical reasons, the array type's OID is assigned first.
1325  */
1326  new_array_oid = AssignTypeArrayOid();
1327 
1328  /*
1329  * Make the pg_type entry for the composite type. The OID of the
1330  * composite type can be preselected by the caller, but if reltypeid
1331  * is InvalidOid, we'll generate a new OID for it.
1332  *
1333  * NOTE: we could get a unique-index failure here, in case someone
1334  * else is creating the same type name in parallel but hadn't
1335  * committed yet when we checked for a duplicate name above.
1336  */
1337  new_type_addr = AddNewRelationType(relname,
1338  relnamespace,
1339  relid,
1340  relkind,
1341  ownerid,
1342  reltypeid,
1343  new_array_oid);
1344  new_type_oid = new_type_addr.objectId;
1345  if (typaddress)
1346  *typaddress = new_type_addr;
1347 
1348  /* Now create the array type. */
1349  relarrayname = makeArrayTypeName(relname, relnamespace);
1350 
1351  TypeCreate(new_array_oid, /* force the type's OID to this */
1352  relarrayname, /* Array type name */
1353  relnamespace, /* Same namespace as parent */
1354  InvalidOid, /* Not composite, no relationOid */
1355  0, /* relkind, also N/A here */
1356  ownerid, /* owner's ID */
1357  -1, /* Internal size (varlena) */
1358  TYPTYPE_BASE, /* Not composite - typelem is */
1359  TYPCATEGORY_ARRAY, /* type-category (array) */
1360  false, /* array types are never preferred */
1361  DEFAULT_TYPDELIM, /* default array delimiter */
1362  F_ARRAY_IN, /* array input proc */
1363  F_ARRAY_OUT, /* array output proc */
1364  F_ARRAY_RECV, /* array recv (bin) proc */
1365  F_ARRAY_SEND, /* array send (bin) proc */
1366  InvalidOid, /* typmodin procedure - none */
1367  InvalidOid, /* typmodout procedure - none */
1368  F_ARRAY_TYPANALYZE, /* array analyze procedure */
1369  F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1370  new_type_oid, /* array element type - the rowtype */
1371  true, /* yes, this is an array type */
1372  InvalidOid, /* this has no array type */
1373  InvalidOid, /* domain base type - irrelevant */
1374  NULL, /* default value - none */
1375  NULL, /* default binary representation */
1376  false, /* passed by reference */
1377  TYPALIGN_DOUBLE, /* alignment - must be the largest! */
1378  TYPSTORAGE_EXTENDED, /* fully TOASTable */
1379  -1, /* typmod */
1380  0, /* array dimensions for typBaseType */
1381  false, /* Type NOT NULL */
1382  InvalidOid); /* rowtypes never have a collation */
1383 
1384  pfree(relarrayname);
1385  }
1386  else
1387  {
1388  /* Caller should not be expecting a type to be created. */
1389  Assert(reltypeid == InvalidOid);
1390  Assert(typaddress == NULL);
1391 
1392  new_type_oid = InvalidOid;
1393  }
1394 
1395  /*
1396  * now create an entry in pg_class for the relation.
1397  *
1398  * NOTE: we could get a unique-index failure here, in case someone else is
1399  * creating the same relation name in parallel but hadn't committed yet
1400  * when we checked for a duplicate name above.
1401  */
1402  AddNewRelationTuple(pg_class_desc,
1403  new_rel_desc,
1404  relid,
1405  new_type_oid,
1406  reloftypeid,
1407  ownerid,
1408  relkind,
1409  relfrozenxid,
1410  relminmxid,
1411  PointerGetDatum(relacl),
1412  reloptions);
1413 
1414  /*
1415  * now add tuples to pg_attribute for the attributes in our new relation.
1416  */
1417  AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind);
1418 
1419  /*
1420  * Make a dependency link to force the relation to be deleted if its
1421  * namespace is. Also make a dependency link to its owner, as well as
1422  * dependencies for any roles mentioned in the default ACL.
1423  *
1424  * For composite types, these dependencies are tracked for the pg_type
1425  * entry, so we needn't record them here. Likewise, TOAST tables don't
1426  * need a namespace dependency (they live in a pinned namespace) nor an
1427  * owner dependency (they depend indirectly through the parent table), nor
1428  * should they have any ACL entries. The same applies for extension
1429  * dependencies.
1430  *
1431  * Also, skip this in bootstrap mode, since we don't make dependencies
1432  * while bootstrapping.
1433  */
1434  if (relkind != RELKIND_COMPOSITE_TYPE &&
1435  relkind != RELKIND_TOASTVALUE &&
1437  {
1438  ObjectAddress myself,
1439  referenced;
1440  ObjectAddresses *addrs;
1441 
1442  ObjectAddressSet(myself, RelationRelationId, relid);
1443 
1444  recordDependencyOnOwner(RelationRelationId, relid, ownerid);
1445 
1446  recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
1447 
1448  recordDependencyOnCurrentExtension(&myself, false);
1449 
1450  addrs = new_object_addresses();
1451 
1452  ObjectAddressSet(referenced, NamespaceRelationId, relnamespace);
1453  add_exact_object_address(&referenced, addrs);
1454 
1455  if (reloftypeid)
1456  {
1457  ObjectAddressSet(referenced, TypeRelationId, reloftypeid);
1458  add_exact_object_address(&referenced, addrs);
1459  }
1460 
1461  /*
1462  * Make a dependency link to force the relation to be deleted if its
1463  * access method is.
1464  *
1465  * No need to add an explicit dependency for the toast table, as the
1466  * main table depends on it.
1467  */
1468  if (RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE)
1469  {
1470  ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
1471  add_exact_object_address(&referenced, addrs);
1472  }
1473 
1475  free_object_addresses(addrs);
1476  }
1477 
1478  /* Post creation hook for new relation */
1479  InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
1480 
1481  /*
1482  * Store any supplied constraints and defaults.
1483  *
1484  * NB: this may do a CommandCounterIncrement and rebuild the relcache
1485  * entry, so the relation must be valid and self-consistent at this point.
1486  * In particular, there are not yet constraints and defaults anywhere.
1487  */
1488  StoreConstraints(new_rel_desc, cooked_constraints, is_internal);
1489 
1490  /*
1491  * If there's a special on-commit action, remember it
1492  */
1493  if (oncommit != ONCOMMIT_NOOP)
1494  register_on_commit_action(relid, oncommit);
1495 
1496  /*
1497  * ok, the relation has been cataloged, so close our relations and return
1498  * the OID of the newly created relation.
1499  */
1500  table_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
1501  table_close(pg_class_desc, RowExclusiveLock);
1502 
1503  return relid;
1504 }
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:4365
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:4289
TransactionId MultiXactId
Definition: c.h:662
uint32 TransactionId
Definition: c.h:652
RelFileNumber GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
Definition: catalog.c:500
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2740
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
bool IsBinaryUpgrade
Definition: globals.c:118
static void StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
Definition: heap.c:2225
static void AddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind)
Definition: heap.c:820
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber
Definition: heap.c:82
static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, Oid reloftype, Oid relowner, char relkind, TransactionId relfrozenxid, TransactionId relminmxid, Datum relacl, Datum reloptions)
Definition: heap.c:968
RelFileNumber binary_upgrade_next_toast_pg_class_relfilenumber
Definition: heap.c:83
static ObjectAddress AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid, Oid new_row_type, Oid new_array_type)
Definition: heap.c:1026
void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, int flags)
Definition: heap.c:456
Oid binary_upgrade_next_toast_pg_class_oid
Definition: heap.c:81
Oid binary_upgrade_next_heap_pg_class_oid
Definition: heap.c:80
Relation heap_create(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, RelFileNumber relfilenumber, Oid accessmtd, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, bool create_storage)
Definition: heap.c:289
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
void pfree(void *pointer)
Definition: mcxt.c:1520
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2300
@ OBJECT_TABLE
Definition: parsenodes.h:2304
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:160
ObjectAddress TypeCreate(Oid newTypeOid, const char *typeName, Oid typeNamespace, Oid relationOid, char relationKind, Oid ownerId, int16 internalSize, char typeType, char typeCategory, bool typePreferred, char typDelim, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid subscriptProcedure, Oid elementType, bool isImplicitArray, Oid arrayType, Oid baseType, const char *defaultTypeValue, char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull, Oid typeCollation)
Definition: pg_type.c:195
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:840
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:905
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
@ ONCOMMIT_NOOP
Definition: primnodes.h:57
Oid RelFileNumber
Definition: relpath.h:25
#define InvalidRelFileNumber
Definition: relpath.h:26
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:106
void register_on_commit_action(Oid relid, OnCommitAction action)
Definition: tablecmds.c:18181
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2410
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22

References add_exact_object_address(), AddNewAttributeTuples(), AddNewRelationTuple(), AddNewRelationType(), Assert, AssignTypeArrayOid(), binary_upgrade_next_heap_pg_class_oid, binary_upgrade_next_heap_pg_class_relfilenumber, binary_upgrade_next_toast_pg_class_oid, binary_upgrade_next_toast_pg_class_relfilenumber, CheckAttributeNamesTypes(), CHKATYPE_ANYARRAY, CStringGetDatum(), DEFAULT_TYPDELIM, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, free_object_addresses(), get_relname_relid(), get_user_default_acl(), GetNewRelFileNumber(), GetSysCacheOid2, heap_create(), InvalidOid, InvalidRelFileNumber, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsNormalProcessingMode, makeArrayTypeName(), moveArrayTypeName(), new_object_addresses(), NoLock, OBJECT_SEQUENCE, OBJECT_TABLE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, ONCOMMIT_NOOP, pfree(), PointerGetDatum(), RelationData::rd_att, RelationData::rd_rel, record_object_address_dependencies(), recordDependencyOnCurrentExtension(), recordDependencyOnNewAcl(), recordDependencyOnOwner(), register_on_commit_action(), RelationGetRelid, RelFileNumberIsValid, relname, RowExclusiveLock, StoreConstraints(), table_close(), table_open(), and TypeCreate().

Referenced by create_toast_table(), DefineRelation(), and make_new_heap().

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)

Definition at line 1757 of file heap.c.

1758 {
1759  Relation rel;
1760  HeapTuple tuple;
1761  Oid parentOid = InvalidOid,
1762  defaultPartOid = InvalidOid;
1763 
1764  /*
1765  * To drop a partition safely, we must grab exclusive lock on its parent,
1766  * because another backend might be about to execute a query on the parent
1767  * table. If it relies on previously cached partition descriptor, then it
1768  * could attempt to access the just-dropped relation as its partition. We
1769  * must therefore take a table lock strong enough to prevent all queries
1770  * on the table from proceeding until we commit and send out a
1771  * shared-cache-inval notice that will make them update their partition
1772  * descriptors.
1773  */
1774  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1775  if (!HeapTupleIsValid(tuple))
1776  elog(ERROR, "cache lookup failed for relation %u", relid);
1777  if (((Form_pg_class) GETSTRUCT(tuple))->relispartition)
1778  {
1779  /*
1780  * We have to lock the parent if the partition is being detached,
1781  * because it's possible that some query still has a partition
1782  * descriptor that includes this partition.
1783  */
1784  parentOid = get_partition_parent(relid, true);
1786 
1787  /*
1788  * If this is not the default partition, dropping it will change the
1789  * default partition's partition constraint, so we must lock it.
1790  */
1791  defaultPartOid = get_default_partition_oid(parentOid);
1792  if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
1793  LockRelationOid(defaultPartOid, AccessExclusiveLock);
1794  }
1795 
1796  ReleaseSysCache(tuple);
1797 
1798  /*
1799  * Open and lock the relation.
1800  */
1801  rel = relation_open(relid, AccessExclusiveLock);
1802 
1803  /*
1804  * There can no longer be anyone *else* touching the relation, but we
1805  * might still have open queries or cursors, or pending trigger events, in
1806  * our own session.
1807  */
1808  CheckTableNotInUse(rel, "DROP TABLE");
1809 
1810  /*
1811  * This effectively deletes all rows in the table, and may be done in a
1812  * serializable transaction. In that case we must record a rw-conflict in
1813  * to this transaction from each transaction holding a predicate lock on
1814  * the table.
1815  */
1817 
1818  /*
1819  * Delete pg_foreign_table tuple first.
1820  */
1821  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1822  {
1823  Relation ftrel;
1824  HeapTuple fttuple;
1825 
1826  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
1827 
1828  fttuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
1829  if (!HeapTupleIsValid(fttuple))
1830  elog(ERROR, "cache lookup failed for foreign table %u", relid);
1831 
1832  CatalogTupleDelete(ftrel, &fttuple->t_self);
1833 
1834  ReleaseSysCache(fttuple);
1835  table_close(ftrel, RowExclusiveLock);
1836  }
1837 
1838  /*
1839  * If a partitioned table, delete the pg_partitioned_table tuple.
1840  */
1841  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1843 
1844  /*
1845  * If the relation being dropped is the default partition itself,
1846  * invalidate its entry in pg_partitioned_table.
1847  */
1848  if (relid == defaultPartOid)
1850 
1851  /*
1852  * Schedule unlinking of the relation's physical files at commit.
1853  */
1854  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
1855  RelationDropStorage(rel);
1856 
1857  /* ensure that stats are dropped if transaction commits */
1858  pgstat_drop_relation(rel);
1859 
1860  /*
1861  * Close relcache entry, but *keep* AccessExclusiveLock on the relation
1862  * until transaction commit. This ensures no one else will try to do
1863  * something with the doomed relation.
1864  */
1865  relation_close(rel, NoLock);
1866 
1867  /*
1868  * Remove any associated relation synchronization states.
1869  */
1871 
1872  /*
1873  * Forget any ON COMMIT action for the rel
1874  */
1875  remove_on_commit_action(relid);
1876 
1877  /*
1878  * Flush the relation from the relcache. We want to do this before
1879  * starting to remove catalog entries, just to be certain that no relcache
1880  * entry rebuild will happen partway through. (That should not really
1881  * matter, since we don't do CommandCounterIncrement here, but let's be
1882  * safe.)
1883  */
1884  RelationForgetRelation(relid);
1885 
1886  /*
1887  * remove inheritance information
1888  */
1890 
1891  /*
1892  * delete statistics
1893  */
1894  RemoveStatistics(relid, 0);
1895 
1896  /*
1897  * delete attribute tuples
1898  */
1899  DeleteAttributeTuples(relid);
1900 
1901  /*
1902  * delete relation tuple
1903  */
1904  DeleteRelationTuple(relid);
1905 
1906  if (OidIsValid(parentOid))
1907  {
1908  /*
1909  * If this is not the default partition, the partition constraint of
1910  * the default partition has changed to include the portion of the key
1911  * space previously covered by the dropped partition.
1912  */
1913  if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
1914  CacheInvalidateRelcacheByRelid(defaultPartOid);
1915 
1916  /*
1917  * Invalidate the parent's relcache so that the partition is no longer
1918  * included in its partition descriptor.
1919  */
1920  CacheInvalidateRelcacheByRelid(parentOid);
1921  /* keep the lock */
1922  }
1923 }
void DeleteRelationTuple(Oid relid)
Definition: heap.c:1549
void DeleteAttributeTuples(Oid relid)
Definition: heap.c:1578
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:3282
static void RelationRemoveInheritance(Oid relid)
Definition: heap.c:1516
void RemovePartitionKeyByRelId(Oid relid)
Definition: heap.c:3809
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#define AccessExclusiveLock
Definition: lockdefs.h:43
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:340
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:315
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition: partition.c:53
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void RemoveSubscriptionRel(Oid subid, Oid relid)
void pgstat_drop_relation(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4404
void RelationForgetRelation(Oid rid)
Definition: relcache.c:2873
void RelationDropStorage(Relation rel)
Definition: storage.c:206
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4346
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:18217

References AccessExclusiveLock, CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), CheckTableForSerializableConflictIn(), CheckTableNotInUse(), DeleteAttributeTuples(), DeleteRelationTuple(), elog, ERROR, get_default_partition_oid(), get_partition_parent(), GETSTRUCT, HeapTupleIsValid, InvalidOid, LockRelationOid(), NoLock, ObjectIdGetDatum(), OidIsValid, pgstat_drop_relation(), RelationData::rd_rel, relation_close(), relation_open(), RelationDropStorage(), RelationForgetRelation(), RelationRemoveInheritance(), ReleaseSysCache(), remove_on_commit_action(), RemovePartitionKeyByRelId(), RemoveStatistics(), RemoveSubscriptionRel(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), table_open(), and update_default_partition_oid().

Referenced by doDeletion().

◆ heap_truncate()

void heap_truncate ( List relids)

Definition at line 3377 of file heap.c.

3378 {
3379  List *relations = NIL;
3380  ListCell *cell;
3381 
3382  /* Open relations for processing, and grab exclusive access on each */
3383  foreach(cell, relids)
3384  {
3385  Oid rid = lfirst_oid(cell);
3386  Relation rel;
3387 
3388  rel = table_open(rid, AccessExclusiveLock);
3389  relations = lappend(relations, rel);
3390  }
3391 
3392  /* Don't allow truncate on tables that are referenced by foreign keys */
3393  heap_truncate_check_FKs(relations, true);
3394 
3395  /* OK to do it */
3396  foreach(cell, relations)
3397  {
3398  Relation rel = lfirst(cell);
3399 
3400  /* Truncate the relation */
3401  heap_truncate_one_rel(rel);
3402 
3403  /* Close the relation, but keep exclusive lock on it until commit */
3404  table_close(rel, NoLock);
3405  }
3406 }
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3462
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3418
#define lfirst_oid(lc)
Definition: pg_list.h:174

References AccessExclusiveLock, heap_truncate_check_FKs(), heap_truncate_one_rel(), lappend(), lfirst, lfirst_oid, NIL, NoLock, table_close(), and table_open().

Referenced by PreCommit_on_commit_actions().

◆ heap_truncate_check_FKs()

void heap_truncate_check_FKs ( List relations,
bool  tempTables 
)

Definition at line 3462 of file heap.c.

3463 {
3464  List *oids = NIL;
3465  List *dependents;
3466  ListCell *cell;
3467 
3468  /*
3469  * Build a list of OIDs of the interesting relations.
3470  *
3471  * If a relation has no triggers, then it can neither have FKs nor be
3472  * referenced by a FK from another table, so we can ignore it. For
3473  * partitioned tables, FKs have no triggers, so we must include them
3474  * anyway.
3475  */
3476  foreach(cell, relations)
3477  {
3478  Relation rel = lfirst(cell);
3479 
3480  if (rel->rd_rel->relhastriggers ||
3481  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3482  oids = lappend_oid(oids, RelationGetRelid(rel));
3483  }
3484 
3485  /*
3486  * Fast path: if no relation has triggers, none has FKs either.
3487  */
3488  if (oids == NIL)
3489  return;
3490 
3491  /*
3492  * Otherwise, must scan pg_constraint. We make one pass with all the
3493  * relations considered; if this finds nothing, then all is well.
3494  */
3495  dependents = heap_truncate_find_FKs(oids);
3496  if (dependents == NIL)
3497  return;
3498 
3499  /*
3500  * Otherwise we repeat the scan once per relation to identify a particular
3501  * pair of relations to complain about. This is pretty slow, but
3502  * performance shouldn't matter much in a failure path. The reason for
3503  * doing things this way is to ensure that the message produced is not
3504  * dependent on chance row locations within pg_constraint.
3505  */
3506  foreach(cell, oids)
3507  {
3508  Oid relid = lfirst_oid(cell);
3509  ListCell *cell2;
3510 
3511  dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3512 
3513  foreach(cell2, dependents)
3514  {
3515  Oid relid2 = lfirst_oid(cell2);
3516 
3517  if (!list_member_oid(oids, relid2))
3518  {
3519  char *relname = get_rel_name(relid);
3520  char *relname2 = get_rel_name(relid2);
3521 
3522  if (tempTables)
3523  ereport(ERROR,
3524  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3525  errmsg("unsupported ON COMMIT and foreign key combination"),
3526  errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3527  relname2, relname)));
3528  else
3529  ereport(ERROR,
3530  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3531  errmsg("cannot truncate a table referenced in a foreign key constraint"),
3532  errdetail("Table \"%s\" references \"%s\".",
3533  relname2, relname),
3534  errhint("Truncate table \"%s\" at the same time, "
3535  "or use TRUNCATE ... CASCADE.",
3536  relname2)));
3537  }
3538  }
3539  }
3540 }
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3557
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
#define list_make1_oid(x1)
Definition: pg_list.h:242

References ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, get_rel_name(), heap_truncate_find_FKs(), lappend_oid(), lfirst, lfirst_oid, list_make1_oid, list_member_oid(), NIL, RelationData::rd_rel, RelationGetRelid, and relname.

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ heap_truncate_find_FKs()

List* heap_truncate_find_FKs ( List relationIds)

Definition at line 3557 of file heap.c.

3558 {
3559  List *result = NIL;
3560  List *oids;
3561  List *parent_cons;
3562  ListCell *cell;
3563  ScanKeyData key;
3564  Relation fkeyRel;
3565  SysScanDesc fkeyScan;
3566  HeapTuple tuple;
3567  bool restart;
3568 
3569  oids = list_copy(relationIds);
3570 
3571  /*
3572  * Must scan pg_constraint. Right now, it is a seqscan because there is
3573  * no available index on confrelid.
3574  */
3575  fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3576 
3577 restart:
3578  restart = false;
3579  parent_cons = NIL;
3580 
3581  fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3582  NULL, 0, NULL);
3583 
3584  while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3585  {
3587 
3588  /* Not a foreign key */
3589  if (con->contype != CONSTRAINT_FOREIGN)
3590  continue;
3591 
3592  /* Not referencing one of our list of tables */
3593  if (!list_member_oid(oids, con->confrelid))
3594  continue;
3595 
3596  /*
3597  * If this constraint has a parent constraint which we have not seen
3598  * yet, keep track of it for the second loop, below. Tracking parent
3599  * constraints allows us to climb up to the top-level constraint and
3600  * look for all possible relations referencing the partitioned table.
3601  */
3602  if (OidIsValid(con->conparentid) &&
3603  !list_member_oid(parent_cons, con->conparentid))
3604  parent_cons = lappend_oid(parent_cons, con->conparentid);
3605 
3606  /*
3607  * Add referencer to result, unless present in input list. (Don't
3608  * worry about dupes: we'll fix that below).
3609  */
3610  if (!list_member_oid(relationIds, con->conrelid))
3611  result = lappend_oid(result, con->conrelid);
3612  }
3613 
3614  systable_endscan(fkeyScan);
3615 
3616  /*
3617  * Process each parent constraint we found to add the list of referenced
3618  * relations by them to the oids list. If we do add any new such
3619  * relations, redo the first loop above. Also, if we see that the parent
3620  * constraint in turn has a parent, add that so that we process all
3621  * relations in a single additional pass.
3622  */
3623  foreach(cell, parent_cons)
3624  {
3625  Oid parent = lfirst_oid(cell);
3626 
3627  ScanKeyInit(&key,
3628  Anum_pg_constraint_oid,
3629  BTEqualStrategyNumber, F_OIDEQ,
3630  ObjectIdGetDatum(parent));
3631 
3632  fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3633  true, NULL, 1, &key);
3634 
3635  tuple = systable_getnext(fkeyScan);
3636  if (HeapTupleIsValid(tuple))
3637  {
3639 
3640  /*
3641  * pg_constraint rows always appear for partitioned hierarchies
3642  * this way: on the each side of the constraint, one row appears
3643  * for each partition that points to the top-most table on the
3644  * other side.
3645  *
3646  * Because of this arrangement, we can correctly catch all
3647  * relevant relations by adding to 'parent_cons' all rows with
3648  * valid conparentid, and to the 'oids' list all rows with a zero
3649  * conparentid. If any oids are added to 'oids', redo the first
3650  * loop above by setting 'restart'.
3651  */
3652  if (OidIsValid(con->conparentid))
3653  parent_cons = list_append_unique_oid(parent_cons,
3654  con->conparentid);
3655  else if (!list_member_oid(oids, con->confrelid))
3656  {
3657  oids = lappend_oid(oids, con->confrelid);
3658  restart = true;
3659  }
3660  }
3661 
3662  systable_endscan(fkeyScan);
3663  }
3664 
3665  list_free(parent_cons);
3666  if (restart)
3667  goto restart;
3668 
3669  table_close(fkeyRel, AccessShareLock);
3670  list_free(oids);
3671 
3672  /* Now sort and de-duplicate the result list */
3673  list_sort(result, list_oid_cmp);
3674  list_deduplicate_oid(result);
3675 
3676  return result;
3677 }
List * list_copy(const List *oldlist)
Definition: list.c:1573
void list_deduplicate_oid(List *list)
Definition: list.c:1495
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
void list_free(List *list)
Definition: list.c:1546
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
FormData_pg_constraint * Form_pg_constraint

References AccessShareLock, BTEqualStrategyNumber, GETSTRUCT, HeapTupleIsValid, InvalidOid, sort-test::key, lappend_oid(), lfirst_oid, list_append_unique_oid(), list_copy(), list_deduplicate_oid(), list_free(), list_member_oid(), list_oid_cmp(), list_sort(), NIL, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ExecuteTruncateGuts(), and heap_truncate_check_FKs().

◆ heap_truncate_one_rel()

void heap_truncate_one_rel ( Relation  rel)

Definition at line 3418 of file heap.c.

3419 {
3420  Oid toastrelid;
3421 
3422  /*
3423  * Truncate the relation. Partitioned tables have no storage, so there is
3424  * nothing to do for them here.
3425  */
3426  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3427  return;
3428 
3429  /* Truncate the underlying relation */
3431 
3432  /* If the relation has indexes, truncate the indexes too */
3434 
3435  /* If there is a toast table, truncate that too */
3436  toastrelid = rel->rd_rel->reltoastrelid;
3437  if (OidIsValid(toastrelid))
3438  {
3439  Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3440 
3442  RelationTruncateIndexes(toastrel);
3443  /* keep the lock... */
3444  table_close(toastrel, NoLock);
3445  }
3446 }
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3329
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1649

References AccessExclusiveLock, NoLock, OidIsValid, RelationData::rd_rel, RelationTruncateIndexes(), table_close(), table_open(), and table_relation_nontransactional_truncate().

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ InsertPgAttributeTuples()

void InsertPgAttributeTuples ( Relation  pg_attribute_rel,
TupleDesc  tupdesc,
Oid  new_rel_oid,
const FormExtraData_pg_attribute  tupdesc_extra[],
CatalogIndexState  indstate 
)

Definition at line 702 of file heap.c.

707 {
708  TupleTableSlot **slot;
709  TupleDesc td;
710  int nslots;
711  int natts = 0;
712  int slotCount = 0;
713  bool close_index = false;
714 
715  td = RelationGetDescr(pg_attribute_rel);
716 
717  /* Initialize the number of slots to use */
718  nslots = Min(tupdesc->natts,
720  slot = palloc(sizeof(TupleTableSlot *) * nslots);
721  for (int i = 0; i < nslots; i++)
723 
724  while (natts < tupdesc->natts)
725  {
726  Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts);
727  const FormExtraData_pg_attribute *attrs_extra = tupdesc_extra ? &tupdesc_extra[natts] : NULL;
728 
729  ExecClearTuple(slot[slotCount]);
730 
731  memset(slot[slotCount]->tts_isnull, false,
732  slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
733 
734  if (new_rel_oid != InvalidOid)
735  slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid);
736  else
737  slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid);
738 
739  slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname);
740  slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid);
741  slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen);
742  slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum);
743  slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
744  slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod);
745  slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int16GetDatum(attrs->attndims);
746  slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval);
747  slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign);
748  slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage);
749  slot[slotCount]->tts_values[Anum_pg_attribute_attcompression - 1] = CharGetDatum(attrs->attcompression);
750  slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull);
751  slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef);
752  slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing);
753  slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity);
754  slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated);
755  slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped);
756  slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal);
757  slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int16GetDatum(attrs->attinhcount);
758  slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation);
759  if (attrs_extra)
760  {
761  slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.value;
762  slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.isnull;
763 
764  slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.value;
765  slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull;
766  }
767  else
768  {
769  slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true;
770  slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
771  }
772 
773  /*
774  * The remaining fields are not set for new columns.
775  */
776  slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true;
777  slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true;
778  slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true;
779 
780  ExecStoreVirtualTuple(slot[slotCount]);
781  slotCount++;
782 
783  /*
784  * If slots are full or the end of processing has been reached, insert
785  * a batch of tuples.
786  */
787  if (slotCount == nslots || natts == tupdesc->natts - 1)
788  {
789  /* fetch index info only when we know we need it */
790  if (!indstate)
791  {
792  indstate = CatalogOpenIndexes(pg_attribute_rel);
793  close_index = true;
794  }
795 
796  /* insert the new tuples and update the indexes */
797  CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount,
798  indstate);
799  slotCount = 0;
800  }
801 
802  natts++;
803  }
804 
805  if (close_index)
806  CatalogCloseIndexes(indstate);
807  for (int i = 0; i < nslots; i++)
809  pfree(slot);
810 }
#define Min(x, y)
Definition: c.h:1004
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
FormData_pg_attribute
Definition: pg_attribute.h:193
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References FormExtraData_pg_attribute::attoptions, FormExtraData_pg_attribute::attstattarget, BoolGetDatum(), CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTuplesMultiInsertWithInfo(), CharGetDatum(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), FormData_pg_attribute, i, Int16GetDatum(), Int32GetDatum(), InvalidOid, NullableDatum::isnull, MakeSingleTupleTableSlot(), MAX_CATALOG_MULTI_INSERT_BYTES, Min, NameGetDatum(), TupleDescData::natts, ObjectIdGetDatum(), palloc(), pfree(), RelationGetDescr, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TTSOpsHeapTuple, TupleDescAttr, and NullableDatum::value.

Referenced by AddNewAttributeTuples(), AppendAttributeTuples(), and ATExecAddColumn().

◆ InsertPgClassTuple()

void InsertPgClassTuple ( Relation  pg_class_desc,
Relation  new_rel_desc,
Oid  new_rel_oid,
Datum  relacl,
Datum  reloptions 
)

Definition at line 895 of file heap.c.

900 {
901  Form_pg_class rd_rel = new_rel_desc->rd_rel;
902  Datum values[Natts_pg_class];
903  bool nulls[Natts_pg_class];
904  HeapTuple tup;
905 
906  /* This is a tad tedious, but way cleaner than what we used to do... */
907  memset(values, 0, sizeof(values));
908  memset(nulls, false, sizeof(nulls));
909 
910  values[Anum_pg_class_oid - 1] = ObjectIdGetDatum(new_rel_oid);
911  values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
912  values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
913  values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
914  values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
915  values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
916  values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
917  values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
918  values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
919  values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
920  values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
921  values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
922  values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
923  values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
924  values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
925  values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
926  values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
927  values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
928  values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
929  values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
930  values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
931  values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity);
932  values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity);
933  values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
934  values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
935  values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident);
936  values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition);
937  values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
938  values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
939  values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
940  if (relacl != (Datum) 0)
941  values[Anum_pg_class_relacl - 1] = relacl;
942  else
943  nulls[Anum_pg_class_relacl - 1] = true;
944  if (reloptions != (Datum) 0)
945  values[Anum_pg_class_reloptions - 1] = reloptions;
946  else
947  nulls[Anum_pg_class_reloptions - 1] = true;
948 
949  /* relpartbound is set by updating this tuple, if necessary */
950  nulls[Anum_pg_class_relpartbound - 1] = true;
951 
952  tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls);
953 
954  /* finally insert the new tuple, update the indexes, and clean up */
955  CatalogTupleInsert(pg_class_desc, tup);
956 
957  heap_freetuple(tup);
958 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:475
static Datum TransactionIdGetDatum(TransactionId X)
Definition: postgres.h:272
uintptr_t Datum
Definition: postgres.h:64
static Datum MultiXactIdGetDatum(MultiXactId X)
Definition: postgres.h:282

References BoolGetDatum(), CatalogTupleInsert(), CharGetDatum(), Float4GetDatum(), heap_form_tuple(), heap_freetuple(), Int16GetDatum(), Int32GetDatum(), MultiXactIdGetDatum(), NameGetDatum(), ObjectIdGetDatum(), RelationData::rd_rel, RelationGetDescr, TransactionIdGetDatum(), and values.

Referenced by AddNewRelationTuple(), and index_create().

◆ RelationClearMissing()

void RelationClearMissing ( Relation  rel)

Definition at line 1937 of file heap.c.

1938 {
1939  Relation attr_rel;
1940  Oid relid = RelationGetRelid(rel);
1941  int natts = RelationGetNumberOfAttributes(rel);
1942  int attnum;
1943  Datum repl_val[Natts_pg_attribute];
1944  bool repl_null[Natts_pg_attribute];
1945  bool repl_repl[Natts_pg_attribute];
1946  Form_pg_attribute attrtuple;
1947  HeapTuple tuple,
1948  newtuple;
1949 
1950  memset(repl_val, 0, sizeof(repl_val));
1951  memset(repl_null, false, sizeof(repl_null));
1952  memset(repl_repl, false, sizeof(repl_repl));
1953 
1954  repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false);
1955  repl_null[Anum_pg_attribute_attmissingval - 1] = true;
1956 
1957  repl_repl[Anum_pg_attribute_atthasmissing - 1] = true;
1958  repl_repl[Anum_pg_attribute_attmissingval - 1] = true;
1959 
1960 
1961  /* Get a lock on pg_attribute */
1962  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
1963 
1964  /* process each non-system attribute, including any dropped columns */
1965  for (attnum = 1; attnum <= natts; attnum++)
1966  {
1967  tuple = SearchSysCache2(ATTNUM,
1968  ObjectIdGetDatum(relid),
1970  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1971  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1972  attnum, relid);
1973 
1974  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
1975 
1976  /* ignore any where atthasmissing is not true */
1977  if (attrtuple->atthasmissing)
1978  {
1979  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
1980  repl_val, repl_null, repl_repl);
1981 
1982  CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
1983 
1984  heap_freetuple(newtuple);
1985  }
1986 
1987  ReleaseSysCache(tuple);
1988  }
1989 
1990  /*
1991  * Our update of the pg_attribute rows will force a relcache rebuild, so
1992  * there's nothing else to do here.
1993  */
1994  table_close(attr_rel, RowExclusiveLock);
1995 }
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:229

References attnum, BoolGetDatum(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), ObjectIdGetDatum(), RelationGetDescr, RelationGetNumberOfAttributes, RelationGetRelid, ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecAlterColumnType(), ATExecSetExpression(), and finish_heap_swap().

◆ RemoveAttributeById()

void RemoveAttributeById ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 1656 of file heap.c.

1657 {
1658  Relation rel;
1659  Relation attr_rel;
1660  HeapTuple tuple;
1661  Form_pg_attribute attStruct;
1662  char newattname[NAMEDATALEN];
1663  Datum valuesAtt[Natts_pg_attribute] = {0};
1664  bool nullsAtt[Natts_pg_attribute] = {0};
1665  bool replacesAtt[Natts_pg_attribute] = {0};
1666 
1667  /*
1668  * Grab an exclusive lock on the target table, which we will NOT release
1669  * until end of transaction. (In the simple case where we are directly
1670  * dropping this column, ATExecDropColumn already did this ... but when
1671  * cascading from a drop of some other object, we may not have any lock.)
1672  */
1673  rel = relation_open(relid, AccessExclusiveLock);
1674 
1675  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
1676 
1677  tuple = SearchSysCacheCopy2(ATTNUM,
1678  ObjectIdGetDatum(relid),
1680  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1681  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1682  attnum, relid);
1683  attStruct = (Form_pg_attribute) GETSTRUCT(tuple);
1684 
1685  /* Mark the attribute as dropped */
1686  attStruct->attisdropped = true;
1687 
1688  /*
1689  * Set the type OID to invalid. A dropped attribute's type link cannot be
1690  * relied on (once the attribute is dropped, the type might be too).
1691  * Fortunately we do not need the type row --- the only really essential
1692  * information is the type's typlen and typalign, which are preserved in
1693  * the attribute's attlen and attalign. We set atttypid to zero here as a
1694  * means of catching code that incorrectly expects it to be valid.
1695  */
1696  attStruct->atttypid = InvalidOid;
1697 
1698  /* Remove any not-null constraint the column may have */
1699  attStruct->attnotnull = false;
1700 
1701  /* Unset this so no one tries to look up the generation expression */
1702  attStruct->attgenerated = '\0';
1703 
1704  /*
1705  * Change the column name to something that isn't likely to conflict
1706  */
1707  snprintf(newattname, sizeof(newattname),
1708  "........pg.dropped.%d........", attnum);
1709  namestrcpy(&(attStruct->attname), newattname);
1710 
1711  /* Clear the missing value */
1712  attStruct->atthasmissing = false;
1713  nullsAtt[Anum_pg_attribute_attmissingval - 1] = true;
1714  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
1715 
1716  /*
1717  * Clear the other nullable fields. This saves some space in pg_attribute
1718  * and removes no longer useful information.
1719  */
1720  nullsAtt[Anum_pg_attribute_attstattarget - 1] = true;
1721  replacesAtt[Anum_pg_attribute_attstattarget - 1] = true;
1722  nullsAtt[Anum_pg_attribute_attacl - 1] = true;
1723  replacesAtt[Anum_pg_attribute_attacl - 1] = true;
1724  nullsAtt[Anum_pg_attribute_attoptions - 1] = true;
1725  replacesAtt[Anum_pg_attribute_attoptions - 1] = true;
1726  nullsAtt[Anum_pg_attribute_attfdwoptions - 1] = true;
1727  replacesAtt[Anum_pg_attribute_attfdwoptions - 1] = true;
1728 
1729  tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
1730  valuesAtt, nullsAtt, replacesAtt);
1731 
1732  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
1733 
1734  /*
1735  * Because updating the pg_attribute row will trigger a relcache flush for
1736  * the target relation, we need not do anything else to notify other
1737  * backends of the change.
1738  */
1739 
1740  table_close(attr_rel, RowExclusiveLock);
1741 
1742  RemoveStatistics(relid, attnum);
1743 
1744  relation_close(rel, NoLock);
1745 }
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define NAMEDATALEN
#define snprintf
Definition: port.h:238
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:88

References AccessExclusiveLock, attnum, CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), InvalidOid, NAMEDATALEN, namestrcpy(), NoLock, ObjectIdGetDatum(), relation_close(), relation_open(), RelationGetDescr, RemoveStatistics(), RowExclusiveLock, SearchSysCacheCopy2, snprintf, HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemovePartitionKeyByRelId()

void RemovePartitionKeyByRelId ( Oid  relid)

Definition at line 3809 of file heap.c.

3810 {
3811  Relation rel;
3812  HeapTuple tuple;
3813 
3814  rel = table_open(PartitionedRelationId, RowExclusiveLock);
3815 
3816  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3817  if (!HeapTupleIsValid(tuple))
3818  elog(ERROR, "cache lookup failed for partition key of relation %u",
3819  relid);
3820 
3821  CatalogTupleDelete(rel, &tuple->t_self);
3822 
3823  ReleaseSysCache(tuple);
3825 }

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by heap_drop_with_catalog().

◆ RemoveStatistics()

void RemoveStatistics ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 3282 of file heap.c.

3283 {
3284  Relation pgstatistic;
3285  SysScanDesc scan;
3286  ScanKeyData key[2];
3287  int nkeys;
3288  HeapTuple tuple;
3289 
3290  pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3291 
3292  ScanKeyInit(&key[0],
3293  Anum_pg_statistic_starelid,
3294  BTEqualStrategyNumber, F_OIDEQ,
3295  ObjectIdGetDatum(relid));
3296 
3297  if (attnum == 0)
3298  nkeys = 1;
3299  else
3300  {
3301  ScanKeyInit(&key[1],
3302  Anum_pg_statistic_staattnum,
3303  BTEqualStrategyNumber, F_INT2EQ,
3305  nkeys = 2;
3306  }
3307 
3308  scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3309  NULL, nkeys, key);
3310 
3311  /* we must loop even when attnum != 0, in case of inherited stats */
3312  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3313  CatalogTupleDelete(pgstatistic, &tuple->t_self);
3314 
3315  systable_endscan(scan);
3316 
3317  table_close(pgstatistic, RowExclusiveLock);
3318 }

References attnum, BTEqualStrategyNumber, CatalogTupleDelete(), HeapTupleIsValid, Int16GetDatum(), sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecAlterColumnType(), ATExecSetExpression(), heap_drop_with_catalog(), index_drop(), and RemoveAttributeById().

◆ SetAttrMissing()

void SetAttrMissing ( Oid  relid,
char *  attname,
char *  value 
)

Definition at line 2005 of file heap.c.

2006 {
2007  Datum valuesAtt[Natts_pg_attribute] = {0};
2008  bool nullsAtt[Natts_pg_attribute] = {0};
2009  bool replacesAtt[Natts_pg_attribute] = {0};
2010  Datum missingval;
2011  Form_pg_attribute attStruct;
2012  Relation attrrel,
2013  tablerel;
2014  HeapTuple atttup,
2015  newtup;
2016 
2017  /* lock the table the attribute belongs to */
2018  tablerel = table_open(relid, AccessExclusiveLock);
2019 
2020  /* Don't do anything unless it's a plain table */
2021  if (tablerel->rd_rel->relkind != RELKIND_RELATION)
2022  {
2023  table_close(tablerel, AccessExclusiveLock);
2024  return;
2025  }
2026 
2027  /* Lock the attribute row and get the data */
2028  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2029  atttup = SearchSysCacheAttName(relid, attname);
2030  if (!HeapTupleIsValid(atttup))
2031  elog(ERROR, "cache lookup failed for attribute %s of relation %u",
2032  attname, relid);
2033  attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2034 
2035  /* get an array value from the value string */
2036  missingval = OidFunctionCall3(F_ARRAY_IN,
2038  ObjectIdGetDatum(attStruct->atttypid),
2039  Int32GetDatum(attStruct->atttypmod));
2040 
2041  /* update the tuple - set atthasmissing and attmissingval */
2042  valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
2043  replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2044  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2045  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2046 
2047  newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2048  valuesAtt, nullsAtt, replacesAtt);
2049  CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
2050 
2051  /* clean up */
2052  ReleaseSysCache(atttup);
2053  table_close(attrrel, RowExclusiveLock);
2054  table_close(tablerel, AccessExclusiveLock);
2055 }
#define OidFunctionCall3(functionId, arg1, arg2, arg3)
Definition: fmgr.h:684
static struct @155 value
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:359

References AccessExclusiveLock, attname, BoolGetDatum(), CatalogTupleUpdate(), CStringGetDatum(), elog, ERROR, GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, Int32GetDatum(), ObjectIdGetDatum(), OidFunctionCall3, RelationData::rd_rel, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCacheAttName(), HeapTupleData::t_self, table_close(), table_open(), and value.

Referenced by binary_upgrade_set_missing_value().

◆ StorePartitionBound()

void StorePartitionBound ( Relation  rel,
Relation  parent,
PartitionBoundSpec bound 
)

Definition at line 3840 of file heap.c.

3841 {
3842  Relation classRel;
3843  HeapTuple tuple,
3844  newtuple;
3845  Datum new_val[Natts_pg_class];
3846  bool new_null[Natts_pg_class],
3847  new_repl[Natts_pg_class];
3848  Oid defaultPartOid;
3849 
3850  /* Update pg_class tuple */
3851  classRel = table_open(RelationRelationId, RowExclusiveLock);
3852  tuple = SearchSysCacheCopy1(RELOID,
3854  if (!HeapTupleIsValid(tuple))
3855  elog(ERROR, "cache lookup failed for relation %u",
3856  RelationGetRelid(rel));
3857 
3858 #ifdef USE_ASSERT_CHECKING
3859  {
3860  Form_pg_class classForm;
3861  bool isnull;
3862 
3863  classForm = (Form_pg_class) GETSTRUCT(tuple);
3864  Assert(!classForm->relispartition);
3865  (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
3866  &isnull);
3867  Assert(isnull);
3868  }
3869 #endif
3870 
3871  /* Fill in relpartbound value */
3872  memset(new_val, 0, sizeof(new_val));
3873  memset(new_null, false, sizeof(new_null));
3874  memset(new_repl, false, sizeof(new_repl));
3875  new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
3876  new_null[Anum_pg_class_relpartbound - 1] = false;
3877  new_repl[Anum_pg_class_relpartbound - 1] = true;
3878  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
3879  new_val, new_null, new_repl);
3880  /* Also set the flag */
3881  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
3882  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
3883  heap_freetuple(newtuple);
3884  table_close(classRel, RowExclusiveLock);
3885 
3886  /*
3887  * If we're storing bounds for the default partition, update
3888  * pg_partitioned_table too.
3889  */
3890  if (bound->is_default)
3892  RelationGetRelid(rel));
3893 
3894  /* Make these updates visible */
3896 
3897  /*
3898  * The partition constraint for the default partition depends on the
3899  * partition bounds of every other partition, so we must invalidate the
3900  * relcache entry for that partition every time a partition is added or
3901  * removed.
3902  */
3903  defaultPartOid =
3905  if (OidIsValid(defaultPartOid))
3906  CacheInvalidateRelcacheByRelid(defaultPartOid);
3907 
3908  CacheInvalidateRelcache(parent);
3909 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
char * nodeToString(const void *obj)
Definition: outfuncs.c:791
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:70
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:459
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
void CommandCounterIncrement(void)
Definition: xact.c:1097

References Assert, CacheInvalidateRelcache(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CommandCounterIncrement(), CStringGetTextDatum, elog, ERROR, get_default_oid_from_partdesc(), GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, PartitionBoundSpec::is_default, nodeToString(), ObjectIdGetDatum(), OidIsValid, RelationGetDescr, RelationGetPartitionDesc(), RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy1, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and update_default_partition_oid().

Referenced by attachPartitionTable(), and DefineRelation().

◆ StorePartitionKey()

void StorePartitionKey ( Relation  rel,
char  strategy,
int16  partnatts,
AttrNumber partattrs,
List partexprs,
Oid partopclass,
Oid partcollation 
)

Definition at line 3684 of file heap.c.

3691 {
3692  int i;
3693  int2vector *partattrs_vec;
3694  oidvector *partopclass_vec;
3695  oidvector *partcollation_vec;
3696  Datum partexprDatum;
3697  Relation pg_partitioned_table;
3698  HeapTuple tuple;
3699  Datum values[Natts_pg_partitioned_table];
3700  bool nulls[Natts_pg_partitioned_table] = {0};
3701  ObjectAddress myself;
3702  ObjectAddress referenced;
3703  ObjectAddresses *addrs;
3704 
3705  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3706 
3707  /* Copy the partition attribute numbers, opclass OIDs into arrays */
3708  partattrs_vec = buildint2vector(partattrs, partnatts);
3709  partopclass_vec = buildoidvector(partopclass, partnatts);
3710  partcollation_vec = buildoidvector(partcollation, partnatts);
3711 
3712  /* Convert the expressions (if any) to a text datum */
3713  if (partexprs)
3714  {
3715  char *exprString;
3716 
3717  exprString = nodeToString(partexprs);
3718  partexprDatum = CStringGetTextDatum(exprString);
3719  pfree(exprString);
3720  }
3721  else
3722  partexprDatum = (Datum) 0;
3723 
3724  pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3725 
3726  /* Only this can ever be NULL */
3727  if (!partexprDatum)
3728  nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3729 
3730  values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3731  values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3732  values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3733  values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3734  values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3735  values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3736  values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3737  values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3738 
3739  tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3740 
3741  CatalogTupleInsert(pg_partitioned_table, tuple);
3742  table_close(pg_partitioned_table, RowExclusiveLock);
3743 
3744  /* Mark this relation as dependent on a few things as follows */
3745  addrs = new_object_addresses();
3746  ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3747 
3748  /* Operator class and collation per key column */
3749  for (i = 0; i < partnatts; i++)
3750  {
3751  ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3752  add_exact_object_address(&referenced, addrs);
3753 
3754  /* The default collation is pinned, so don't bother recording it */
3755  if (OidIsValid(partcollation[i]) &&
3756  partcollation[i] != DEFAULT_COLLATION_OID)
3757  {
3758  ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3759  add_exact_object_address(&referenced, addrs);
3760  }
3761  }
3762 
3764  free_object_addresses(addrs);
3765 
3766  /*
3767  * The partitioning columns are made internally dependent on the table,
3768  * because we cannot drop any of them without dropping the whole table.
3769  * (ATExecDropColumn independently enforces that, but it's not bulletproof
3770  * so we need the dependencies too.)
3771  */
3772  for (i = 0; i < partnatts; i++)
3773  {
3774  if (partattrs[i] == 0)
3775  continue; /* ignore expressions here */
3776 
3777  ObjectAddressSubSet(referenced, RelationRelationId,
3778  RelationGetRelid(rel), partattrs[i]);
3779  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3780  }
3781 
3782  /*
3783  * Also consider anything mentioned in partition expressions. External
3784  * references (e.g. functions) get NORMAL dependencies. Table columns
3785  * mentioned in the expressions are handled the same as plain partitioning
3786  * columns, i.e. they become internally dependent on the whole table.
3787  */
3788  if (partexprs)
3790  (Node *) partexprs,
3791  RelationGetRelid(rel),
3794  true /* reverse the self-deps */ );
3795 
3796  /*
3797  * We must invalidate the relcache so that the next
3798  * CommandCounterIncrement() will cause the same to be rebuilt using the
3799  * information in just created catalog entry.
3800  */
3802 }
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1594
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
Definition: c.h:715
Definition: c.h:726

References add_exact_object_address(), Assert, buildint2vector(), buildoidvector(), CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), CStringGetTextDatum, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, free_object_addresses(), heap_form_tuple(), i, Int16GetDatum(), InvalidOid, new_object_addresses(), nodeToString(), ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), OidIsValid, pfree(), PointerGetDatum(), RelationData::rd_rel, record_object_address_dependencies(), recordDependencyOn(), recordDependencyOnSingleRelExpr(), RelationGetDescr, RelationGetRelid, RowExclusiveLock, table_close(), table_open(), and values.

Referenced by DefineRelation().

◆ SystemAttributeByName()

const FormData_pg_attribute* SystemAttributeByName ( const char *  attname)

Definition at line 252 of file heap.c.

253 {
254  int j;
255 
256  for (j = 0; j < (int) lengthof(SysAtt); j++)
257  {
258  const FormData_pg_attribute *att = SysAtt[j];
259 
260  if (strcmp(NameStr(att->attname), attname) == 0)
261  return att;
262  }
263 
264  return NULL;
265 }
#define lengthof(array)
Definition: c.h:788
static const FormData_pg_attribute *const SysAtt[]
Definition: heap.c:232

References attname, FormData_pg_attribute, j, lengthof, NameStr, and SysAtt.

Referenced by CheckAttributeNamesTypes(), expanded_record_lookup_field(), specialAttNum(), SPI_fnumber(), and transformIndexConstraint().

◆ SystemAttributeDefinition()

const FormData_pg_attribute* SystemAttributeDefinition ( AttrNumber  attno)

Definition at line 240 of file heap.c.

241 {
242  if (attno >= 0 || attno < -(int) lengthof(SysAtt))
243  elog(ERROR, "invalid system attribute number %d", attno);
244  return SysAtt[-attno - 1];
245 }

References elog, ERROR, lengthof, and SysAtt.

Referenced by attnumAttName(), attnumTypeId(), build_index_tlist(), scanNSItemForColumn(), SPI_fname(), SPI_gettype(), SPI_gettypeid(), SPI_getvalue(), and transformIndexConstraint().