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 *old_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 2319 of file heap.c.

2326 {
2327  List *cookedConstraints = NIL;
2328  TupleDesc tupleDesc;
2329  TupleConstr *oldconstr;
2330  int numoldchecks;
2331  ParseState *pstate;
2332  ParseNamespaceItem *nsitem;
2333  int numchecks;
2334  List *checknames;
2335  List *nnnames;
2336  Node *expr;
2337  CookedConstraint *cooked;
2338 
2339  /*
2340  * Get info about existing constraints.
2341  */
2342  tupleDesc = RelationGetDescr(rel);
2343  oldconstr = tupleDesc->constr;
2344  if (oldconstr)
2345  numoldchecks = oldconstr->num_check;
2346  else
2347  numoldchecks = 0;
2348 
2349  /*
2350  * Create a dummy ParseState and insert the target relation as its sole
2351  * rangetable entry. We need a ParseState for transformExpr.
2352  */
2353  pstate = make_parsestate(NULL);
2354  pstate->p_sourcetext = queryString;
2355  nsitem = addRangeTableEntryForRelation(pstate,
2356  rel,
2358  NULL,
2359  false,
2360  true);
2361  addNSItemToQuery(pstate, nsitem, true, true, true);
2362 
2363  /*
2364  * Process column default expressions.
2365  */
2366  foreach_ptr(RawColumnDefault, colDef, newColDefaults)
2367  {
2368  Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
2369  Oid defOid;
2370 
2371  expr = cookDefault(pstate, colDef->raw_default,
2372  atp->atttypid, atp->atttypmod,
2373  NameStr(atp->attname),
2374  atp->attgenerated);
2375 
2376  /*
2377  * If the expression is just a NULL constant, we do not bother to make
2378  * an explicit pg_attrdef entry, since the default behavior is
2379  * equivalent. This applies to column defaults, but not for
2380  * generation expressions.
2381  *
2382  * Note a nonobvious property of this test: if the column is of a
2383  * domain type, what we'll get is not a bare null Const but a
2384  * CoerceToDomain expr, so we will not discard the default. This is
2385  * critical because the column default needs to be retained to
2386  * override any default that the domain might have.
2387  */
2388  if (expr == NULL ||
2389  (!colDef->generated &&
2390  IsA(expr, Const) &&
2391  castNode(Const, expr)->constisnull))
2392  continue;
2393 
2394  /* If the DEFAULT is volatile we cannot use a missing value */
2395  if (colDef->missingMode &&
2397  colDef->missingMode = false;
2398 
2399  defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal,
2400  colDef->missingMode);
2401 
2402  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2403  cooked->contype = CONSTR_DEFAULT;
2404  cooked->conoid = defOid;
2405  cooked->name = NULL;
2406  cooked->attnum = colDef->attnum;
2407  cooked->expr = expr;
2408  cooked->skip_validation = false;
2409  cooked->is_local = is_local;
2410  cooked->inhcount = is_local ? 0 : 1;
2411  cooked->is_no_inherit = false;
2412  cookedConstraints = lappend(cookedConstraints, cooked);
2413  }
2414 
2415  /*
2416  * Process constraint expressions.
2417  */
2418  numchecks = numoldchecks;
2419  checknames = NIL;
2420  nnnames = NIL;
2421  foreach_node(Constraint, cdef, newConstraints)
2422  {
2423  Oid constrOid;
2424 
2425  if (cdef->contype == CONSTR_CHECK)
2426  {
2427  char *ccname;
2428 
2429  if (cdef->raw_expr != NULL)
2430  {
2431  Assert(cdef->cooked_expr == NULL);
2432 
2433  /*
2434  * Transform raw parsetree to executable expression, and
2435  * verify it's valid as a CHECK constraint.
2436  */
2437  expr = cookConstraint(pstate, cdef->raw_expr,
2439  }
2440  else
2441  {
2442  Assert(cdef->cooked_expr != NULL);
2443 
2444  /*
2445  * Here, we assume the parser will only pass us valid CHECK
2446  * expressions, so we do no particular checking.
2447  */
2448  expr = stringToNode(cdef->cooked_expr);
2449  }
2450 
2451  /*
2452  * Check name uniqueness, or generate a name if none was given.
2453  */
2454  if (cdef->conname != NULL)
2455  {
2456  ccname = cdef->conname;
2457  /* Check against other new constraints */
2458  /* Needed because we don't do CommandCounterIncrement in loop */
2459  foreach_ptr(char, chkname, checknames)
2460  {
2461  if (strcmp(chkname, ccname) == 0)
2462  ereport(ERROR,
2464  errmsg("check constraint \"%s\" already exists",
2465  ccname)));
2466  }
2467 
2468  /* save name for future checks */
2469  checknames = lappend(checknames, ccname);
2470 
2471  /*
2472  * Check against pre-existing constraints. If we are allowed
2473  * to merge with an existing constraint, there's no more to do
2474  * here. (We omit the duplicate constraint from the result,
2475  * which is what ATAddCheckNNConstraint wants.)
2476  */
2477  if (MergeWithExistingConstraint(rel, ccname, expr,
2478  allow_merge, is_local,
2479  cdef->initially_valid,
2480  cdef->is_no_inherit))
2481  continue;
2482  }
2483  else
2484  {
2485  /*
2486  * When generating a name, we want to create "tab_col_check"
2487  * for a column constraint and "tab_check" for a table
2488  * constraint. We no longer have any info about the syntactic
2489  * positioning of the constraint phrase, so we approximate
2490  * this by seeing whether the expression references more than
2491  * one column. (If the user played by the rules, the result
2492  * is the same...)
2493  *
2494  * Note: pull_var_clause() doesn't descend into sublinks, but
2495  * we eliminated those above; and anyway this only needs to be
2496  * an approximate answer.
2497  */
2498  List *vars;
2499  char *colname;
2500 
2501  vars = pull_var_clause(expr, 0);
2502 
2503  /* eliminate duplicates */
2504  vars = list_union(NIL, vars);
2505 
2506  if (list_length(vars) == 1)
2507  colname = get_attname(RelationGetRelid(rel),
2508  ((Var *) linitial(vars))->varattno,
2509  true);
2510  else
2511  colname = NULL;
2512 
2514  colname,
2515  "check",
2516  RelationGetNamespace(rel),
2517  checknames);
2518 
2519  /* save name for future checks */
2520  checknames = lappend(checknames, ccname);
2521  }
2522 
2523  /*
2524  * OK, store it.
2525  */
2526  constrOid =
2527  StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
2528  is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
2529 
2530  numchecks++;
2531 
2532  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2533  cooked->contype = CONSTR_CHECK;
2534  cooked->conoid = constrOid;
2535  cooked->name = ccname;
2536  cooked->attnum = 0;
2537  cooked->expr = expr;
2538  cooked->skip_validation = cdef->skip_validation;
2539  cooked->is_local = is_local;
2540  cooked->inhcount = is_local ? 0 : 1;
2541  cooked->is_no_inherit = cdef->is_no_inherit;
2542  cookedConstraints = lappend(cookedConstraints, cooked);
2543  }
2544  else if (cdef->contype == CONSTR_NOTNULL)
2545  {
2546  CookedConstraint *nncooked;
2547  AttrNumber colnum;
2548  int16 inhcount = is_local ? 0 : 1;
2549  char *nnname;
2550 
2551  /* Determine which column to modify */
2552  colnum = get_attnum(RelationGetRelid(rel), strVal(linitial(cdef->keys)));
2553  if (colnum == InvalidAttrNumber)
2554  ereport(ERROR,
2555  errcode(ERRCODE_UNDEFINED_COLUMN),
2556  errmsg("column \"%s\" of relation \"%s\" does not exist",
2557  strVal(linitial(cdef->keys)), RelationGetRelationName(rel)));
2558  if (colnum < InvalidAttrNumber)
2559  ereport(ERROR,
2560  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2561  errmsg("cannot add not-null constraint on system column \"%s\"",
2562  strVal(linitial(cdef->keys))));
2563 
2564  /*
2565  * If the column already has a not-null constraint, we don't want
2566  * to add another one; just adjust inheritance status as needed.
2567  */
2568  if (AdjustNotNullInheritance(RelationGetRelid(rel), colnum,
2569  is_local, cdef->is_no_inherit))
2570  continue;
2571 
2572  /*
2573  * If a constraint name is specified, check that it isn't already
2574  * used. Otherwise, choose a non-conflicting one ourselves.
2575  */
2576  if (cdef->conname)
2577  {
2579  RelationGetRelid(rel),
2580  cdef->conname))
2581  ereport(ERROR,
2583  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2584  cdef->conname, RelationGetRelationName(rel)));
2585  nnname = cdef->conname;
2586  }
2587  else
2589  strVal(linitial(cdef->keys)),
2590  "not_null",
2591  RelationGetNamespace(rel),
2592  nnnames);
2593  nnnames = lappend(nnnames, nnname);
2594 
2595  constrOid =
2596  StoreRelNotNull(rel, nnname, colnum,
2597  cdef->initially_valid,
2598  is_local,
2599  inhcount,
2600  cdef->is_no_inherit);
2601 
2602  nncooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2603  nncooked->contype = CONSTR_NOTNULL;
2604  nncooked->conoid = constrOid;
2605  nncooked->name = nnname;
2606  nncooked->attnum = colnum;
2607  nncooked->expr = NULL;
2608  nncooked->skip_validation = cdef->skip_validation;
2609  nncooked->is_local = is_local;
2610  nncooked->inhcount = inhcount;
2611  nncooked->is_no_inherit = cdef->is_no_inherit;
2612 
2613  cookedConstraints = lappend(cookedConstraints, nncooked);
2614  }
2615  }
2616 
2617  /*
2618  * Update the count of constraints in the relation's pg_class tuple. We do
2619  * this even if there was no change, in order to ensure that an SI update
2620  * message is sent out for the pg_class tuple, which will force other
2621  * backends to rebuild their relcache entries for the rel. (This is
2622  * critical if we added defaults but not constraints.)
2623  */
2624  SetRelationNumChecks(rel, numchecks);
2625 
2626  return cookedConstraints;
2627 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:725
signed short int16
Definition: c.h:481
#define Assert(condition)
Definition: c.h:837
bool contain_volatile_functions_after_planning(Expr *expr)
Definition: clauses.c:658
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
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:2640
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:2182
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3143
static void SetRelationNumChecks(Relation rel, int numchecks)
Definition: heap.c:3049
static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr, bool is_validated, bool is_local, int16 inhcount, bool is_no_inherit, bool is_internal)
Definition: heap.c:2076
static Node * cookConstraint(ParseState *pstate, Node *raw_constraint, char *relname)
Definition: heap.c:3220
List * list_union(const List *list1, const List *list2)
Definition: list.c:1066
List * lappend(List *list, void *datum)
Definition: list.c:339
#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:1317
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#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:2727
@ CONSTR_NOTNULL
Definition: parsenodes.h:2726
@ CONSTR_CHECK
Definition: parsenodes.h:2730
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)
bool AdjustNotNullInheritance(Oid relid, AttrNumber attnum, bool is_local, bool is_no_inherit)
@ CONSTRAINT_RELATION
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
#define linitial(l)
Definition: pg_list.h:178
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
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:30
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
int16 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:209
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:282
#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:609

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), AdjustNotNullInheritance(), Assert, CookedConstraint::attnum, castNode, ChooseConstraintName(), CookedConstraint::conoid, TupleDescData::constr, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_NOTNULL, CONSTRAINT_RELATION, ConstraintNameIsUsed(), contain_volatile_functions_after_planning(), CookedConstraint::contype, cookConstraint(), cookDefault(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CookedConstraint::expr, foreach_node, foreach_ptr, get_attname(), get_attnum(), CookedConstraint::inhcount, InvalidAttrNumber, CookedConstraint::is_local, CookedConstraint::is_no_inherit, IsA, lappend(), linitial, list_length(), list_union(), make_parsestate(), MergeWithExistingConstraint(), CookedConstraint::name, NameStr, NIL, TupleConstr::num_check, ParseState::p_sourcetext, palloc(), pull_var_clause(), RelationData::rd_att, RelationGetDescr, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, SetRelationNumChecks(), CookedConstraint::skip_validation, StoreAttrDefault(), StoreRelCheck(), StoreRelNotNull(), stringToNode(), strVal, and TupleDescAttr.

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

◆ AddRelationNotNullConstraints()

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

Definition at line 2797 of file heap.c.

2799 {
2800  List *givennames;
2801  List *nnnames;
2802  List *nncols = NIL;
2803 
2804  /*
2805  * We track two lists of names: nnnames keeps all the constraint names,
2806  * givennames tracks user-generated names. The distinction is important,
2807  * because we must raise error for user-generated name conflicts, but for
2808  * system-generated name conflicts we just generate another.
2809  */
2810  nnnames = NIL;
2811  givennames = NIL;
2812 
2813  /*
2814  * First, create all not-null constraints that are directly specified by
2815  * the user. Note that inheritance might have given us another source for
2816  * each, so we must scan the old_notnulls list and increment inhcount for
2817  * each element with identical attnum. We delete from there any element
2818  * that we process.
2819  *
2820  * We don't use foreach() here because we have two nested loops over the
2821  * constraint list, with possible element deletions in the inner one. If
2822  * we used foreach_delete_current() it could only fix up the state of one
2823  * of the loops, so it seems cleaner to use looping over list indexes for
2824  * both loops. Note that any deletion will happen beyond where the outer
2825  * loop is, so its index never needs adjustment.
2826  */
2827  for (int outerpos = 0; outerpos < list_length(constraints); outerpos++)
2828  {
2829  Constraint *constr;
2831  char *conname;
2832  int inhcount = 0;
2833 
2834  constr = list_nth_node(Constraint, constraints, outerpos);
2835 
2836  Assert(constr->contype == CONSTR_NOTNULL);
2837 
2839  strVal(linitial(constr->keys)));
2840  if (attnum == InvalidAttrNumber)
2841  ereport(ERROR,
2842  errcode(ERRCODE_UNDEFINED_COLUMN),
2843  errmsg("column \"%s\" of relation \"%s\" does not exist",
2844  strVal(linitial(constr->keys)),
2845  RelationGetRelationName(rel)));
2846  if (attnum < InvalidAttrNumber)
2847  ereport(ERROR,
2848  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2849  errmsg("cannot add not-null constraint on system column \"%s\"",
2850  strVal(linitial(constr->keys))));
2851 
2852  /*
2853  * A column can only have one not-null constraint, so discard any
2854  * additional ones that appear for columns we already saw; but check
2855  * that the NO INHERIT flags match.
2856  */
2857  for (int restpos = outerpos + 1; restpos < list_length(constraints);)
2858  {
2859  Constraint *other;
2860 
2861  other = list_nth_node(Constraint, constraints, restpos);
2862  if (strcmp(strVal(linitial(constr->keys)),
2863  strVal(linitial(other->keys))) == 0)
2864  {
2865  if (other->is_no_inherit != constr->is_no_inherit)
2866  ereport(ERROR,
2867  errcode(ERRCODE_SYNTAX_ERROR),
2868  errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
2869  strVal(linitial(constr->keys))));
2870 
2871  /*
2872  * Preserve constraint name if one is specified, but raise an
2873  * error if conflicting ones are specified.
2874  */
2875  if (other->conname)
2876  {
2877  if (!constr->conname)
2878  constr->conname = pstrdup(other->conname);
2879  else if (strcmp(constr->conname, other->conname) != 0)
2880  ereport(ERROR,
2881  errcode(ERRCODE_SYNTAX_ERROR),
2882  errmsg("conflicting not-null constraint names \"%s\" and \"%s\"",
2883  constr->conname, other->conname));
2884  }
2885 
2886  /* XXX do we need to verify any other fields? */
2887  constraints = list_delete_nth_cell(constraints, restpos);
2888  }
2889  else
2890  restpos++;
2891  }
2892 
2893  /*
2894  * Search in the list of inherited constraints for any entries on the
2895  * same column; determine an inheritance count from that. Also, if at
2896  * least one parent has a constraint for this column, then we must not
2897  * accept a user specification for a NO INHERIT one. Any constraint
2898  * from parents that we process here is deleted from the list: we no
2899  * longer need to process it in the loop below.
2900  */
2901  foreach_ptr(CookedConstraint, old, old_notnulls)
2902  {
2903  if (old->attnum == attnum)
2904  {
2905  /*
2906  * If we get a constraint from the parent, having a local NO
2907  * INHERIT one doesn't work.
2908  */
2909  if (constr->is_no_inherit)
2910  ereport(ERROR,
2911  (errcode(ERRCODE_DATATYPE_MISMATCH),
2912  errmsg("cannot define not-null constraint on column \"%s\" with NO INHERIT",
2913  strVal(linitial(constr->keys))),
2914  errdetail("The column has an inherited not-null constraint.")));
2915 
2916  inhcount++;
2917  old_notnulls = foreach_delete_current(old_notnulls, old);
2918  }
2919  }
2920 
2921  /*
2922  * Determine a constraint name, which may have been specified by the
2923  * user, or raise an error if a conflict exists with another
2924  * user-specified name.
2925  */
2926  if (constr->conname)
2927  {
2928  foreach_ptr(char, thisname, givennames)
2929  {
2930  if (strcmp(thisname, constr->conname) == 0)
2931  ereport(ERROR,
2933  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2934  constr->conname,
2935  RelationGetRelationName(rel)));
2936  }
2937 
2938  conname = constr->conname;
2939  givennames = lappend(givennames, conname);
2940  }
2941  else
2944  attnum, false),
2945  "not_null",
2946  RelationGetNamespace(rel),
2947  nnnames);
2948  nnnames = lappend(nnnames, conname);
2949 
2950  StoreRelNotNull(rel, conname,
2951  attnum, true, true,
2952  inhcount, constr->is_no_inherit);
2953 
2954  nncols = lappend_int(nncols, attnum);
2955  }
2956 
2957  /*
2958  * If any column remains in the old_notnulls list, we must create a not-
2959  * null constraint marked not-local for that column. Because multiple
2960  * parents could specify a not-null constraint for the same column, we
2961  * must count how many there are and set an appropriate inhcount
2962  * accordingly, deleting elements we've already processed.
2963  *
2964  * We don't use foreach() here because we have two nested loops over the
2965  * constraint list, with possible element deletions in the inner one. If
2966  * we used foreach_delete_current() it could only fix up the state of one
2967  * of the loops, so it seems cleaner to use looping over list indexes for
2968  * both loops. Note that any deletion will happen beyond where the outer
2969  * loop is, so its index never needs adjustment.
2970  */
2971  for (int outerpos = 0; outerpos < list_length(old_notnulls); outerpos++)
2972  {
2973  CookedConstraint *cooked;
2974  char *conname = NULL;
2975  int inhcount = 1;
2976 
2977  cooked = (CookedConstraint *) list_nth(old_notnulls, outerpos);
2978  Assert(cooked->contype == CONSTR_NOTNULL);
2979  Assert(cooked->name);
2980 
2981  /*
2982  * Preserve the first non-conflicting constraint name we come across.
2983  */
2984  if (conname == NULL)
2985  conname = cooked->name;
2986 
2987  for (int restpos = outerpos + 1; restpos < list_length(old_notnulls);)
2988  {
2989  CookedConstraint *other;
2990 
2991  other = (CookedConstraint *) list_nth(old_notnulls, restpos);
2992  Assert(other->name);
2993  if (other->attnum == cooked->attnum)
2994  {
2995  if (conname == NULL)
2996  conname = other->name;
2997 
2998  inhcount++;
2999  old_notnulls = list_delete_nth_cell(old_notnulls, restpos);
3000  }
3001  else
3002  restpos++;
3003  }
3004 
3005  /* If we got a name, make sure it isn't one we've already used */
3006  if (conname != NULL)
3007  {
3008  foreach_ptr(char, thisname, nnnames)
3009  {
3010  if (strcmp(thisname, conname) == 0)
3011  {
3012  conname = NULL;
3013  break;
3014  }
3015  }
3016  }
3017 
3018  /* and choose a name, if needed */
3019  if (conname == NULL)
3022  cooked->attnum, false),
3023  "not_null",
3024  RelationGetNamespace(rel),
3025  nnnames);
3026  nnnames = lappend(nnnames, conname);
3027 
3028  /* ignore the origin constraint's is_local and inhcount */
3029  StoreRelNotNull(rel, conname, cooked->attnum, true,
3030  false, inhcount, false);
3031 
3032  nncols = lappend_int(nncols, cooked->attnum);
3033  }
3034 
3035  return nncols;
3036 }
int errdetail(const char *fmt,...)
Definition: elog.c:1203
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * list_delete_nth_cell(List *list, int n)
Definition: list.c:767
char * pstrdup(const char *in)
Definition: mcxt.c:1696
int16 attnum
Definition: pg_attribute.h:74
#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
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
List * keys
Definition: parsenodes.h:2769
ConstrType contype
Definition: parsenodes.h:2756
bool is_no_inherit
Definition: parsenodes.h:2762
char * conname
Definition: parsenodes.h:2757

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, foreach_ptr, get_attname(), get_attnum(), InvalidAttrNumber, Constraint::is_no_inherit, Constraint::keys, lappend(), lappend_int(), linitial, list_delete_nth_cell(), list_length(), list_nth(), list_nth_node, CookedConstraint::name, NIL, pstrdup(), 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:73
int i
Definition: isn.c:72
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:754
int errhint(const char *fmt,...)
Definition: elog.c:1317
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:3574
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 3143 of file heap.c.

3149 {
3150  Node *expr;
3151 
3152  Assert(raw_default != NULL);
3153 
3154  /*
3155  * Transform raw parsetree to executable expression.
3156  */
3157  expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3158 
3159  if (attgenerated)
3160  {
3161  /* Disallow refs to other generated columns */
3162  check_nested_generated(pstate, expr);
3163 
3164  /* Disallow mutable functions */
3166  ereport(ERROR,
3167  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3168  errmsg("generation expression is not immutable")));
3169  }
3170  else
3171  {
3172  /*
3173  * For a default expression, transformExpr() should have rejected
3174  * column references.
3175  */
3176  Assert(!contain_var_clause(expr));
3177  }
3178 
3179  /*
3180  * Coerce the expression to the correct type and typmod, if given. This
3181  * should match the parser's processing of non-defaulted expressions ---
3182  * see transformAssignedExpr().
3183  */
3184  if (OidIsValid(atttypid))
3185  {
3186  Oid type_id = exprType(expr);
3187 
3188  expr = coerce_to_target_type(pstate, expr, type_id,
3189  atttypid, atttypmod,
3192  -1);
3193  if (expr == NULL)
3194  ereport(ERROR,
3195  (errcode(ERRCODE_DATATYPE_MISMATCH),
3196  errmsg("column \"%s\" is of type %s"
3197  " but default expression is of type %s",
3198  attname,
3199  format_type_be(atttypid),
3200  format_type_be(type_id)),
3201  errhint("You will need to rewrite or cast the expression.")));
3202  }
3203 
3204  /*
3205  * Finally, take care of collations in the finished expression.
3206  */
3207  assign_expr_collations(pstate, expr);
3208 
3209  return expr;
3210 }
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:489
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3125
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:118
@ EXPR_KIND_COLUMN_DEFAULT
Definition: parse_node.h:70
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:83
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
bool contain_var_clause(Node *node)
Definition: var.c:405

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 3258 of file heap.c.

3259 {
3260  HeapTuple tup;
3261  SysScanDesc scan;
3262  ScanKeyData key[1];
3263  Relation statrel;
3264  CatalogIndexState indstate = NULL;
3265 
3266  statrel = table_open(StatisticRelationId, RowExclusiveLock);
3267 
3268  /* Now search for stat records */
3269  ScanKeyInit(&key[0],
3270  Anum_pg_statistic_starelid,
3271  BTEqualStrategyNumber, F_OIDEQ,
3272  ObjectIdGetDatum(fromrelid));
3273 
3274  scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3275  true, NULL, 1, key);
3276 
3277  while (HeapTupleIsValid((tup = systable_getnext(scan))))
3278  {
3279  Form_pg_statistic statform;
3280 
3281  /* make a modifiable copy */
3282  tup = heap_copytuple(tup);
3283  statform = (Form_pg_statistic) GETSTRUCT(tup);
3284 
3285  /* update the copy of the tuple and insert it */
3286  statform->starelid = torelid;
3287 
3288  /* fetch index information when we know we need it */
3289  if (indstate == NULL)
3290  indstate = CatalogOpenIndexes(statrel);
3291 
3292  CatalogTupleInsertWithInfo(statrel, tup, indstate);
3293 
3294  heap_freetuple(tup);
3295  }
3296 
3297  systable_endscan(scan);
3298 
3299  if (indstate != NULL)
3300  CatalogCloseIndexes(indstate);
3301  table_close(statrel, RowExclusiveLock);
3302 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
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
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

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 1588 of file heap.c.

1589 {
1590  Relation attrel;
1591  SysScanDesc scan;
1592  ScanKeyData key[1];
1593  HeapTuple atttup;
1594 
1595  /* Grab an appropriate lock on the pg_attribute relation */
1596  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1597 
1598  /* Use the index to scan only attributes of the target relation */
1599  ScanKeyInit(&key[0],
1600  Anum_pg_attribute_attrelid,
1601  BTEqualStrategyNumber, F_OIDEQ,
1602  ObjectIdGetDatum(relid));
1603 
1604  scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1605  NULL, 1, key);
1606 
1607  /* Delete all the matching tuples */
1608  while ((atttup = systable_getnext(scan)) != NULL)
1609  CatalogTupleDelete(attrel, &atttup->t_self);
1610 
1611  /* Clean up after the scan */
1612  systable_endscan(scan);
1613  table_close(attrel, RowExclusiveLock);
1614 }
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 1559 of file heap.c.

1560 {
1561  Relation pg_class_desc;
1562  HeapTuple tup;
1563 
1564  /* Grab an appropriate lock on the pg_class relation */
1565  pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
1566 
1567  tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1568  if (!HeapTupleIsValid(tup))
1569  elog(ERROR, "cache lookup failed for relation %u", relid);
1570 
1571  /* delete the relation tuple from pg_class, and finish up */
1572  CatalogTupleDelete(pg_class_desc, &tup->t_self);
1573 
1574  ReleaseSysCache(tup);
1575 
1576  table_close(pg_class_desc, RowExclusiveLock);
1577 }
#define elog(elevel,...)
Definition: elog.h:225
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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 1625 of file heap.c.

1626 {
1627  Relation attrel;
1628  SysScanDesc scan;
1629  ScanKeyData key[2];
1630  HeapTuple atttup;
1631 
1632  /* Grab an appropriate lock on the pg_attribute relation */
1633  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1634 
1635  /* Use the index to scan only system attributes of the target relation */
1636  ScanKeyInit(&key[0],
1637  Anum_pg_attribute_attrelid,
1638  BTEqualStrategyNumber, F_OIDEQ,
1639  ObjectIdGetDatum(relid));
1640  ScanKeyInit(&key[1],
1641  Anum_pg_attribute_attnum,
1642  BTLessEqualStrategyNumber, F_INT2LE,
1643  Int16GetDatum(0));
1644 
1645  scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1646  NULL, 2, key);
1647 
1648  /* Delete all the matching tuples */
1649  while ((atttup = systable_getnext(scan)) != NULL)
1650  CatalogTupleDelete(attrel, &atttup->t_self);
1651 
1652  /* Clean up after the scan */
1653  systable_endscan(scan);
1654  table_close(attrel, RowExclusiveLock);
1655 }
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:230
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
Oid MyDatabaseTableSpace
Definition: globals.c:95
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:370
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:3480
#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:1630
#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 1105 of file heap.c.

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

References AccessExclusiveLock, 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, LockRelationOid(), 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 1767 of file heap.c.

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

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 3406 of file heap.c.

3407 {
3408  List *relations = NIL;
3409  ListCell *cell;
3410 
3411  /* Open relations for processing, and grab exclusive access on each */
3412  foreach(cell, relids)
3413  {
3414  Oid rid = lfirst_oid(cell);
3415  Relation rel;
3416 
3417  rel = table_open(rid, AccessExclusiveLock);
3418  relations = lappend(relations, rel);
3419  }
3420 
3421  /* Don't allow truncate on tables that are referenced by foreign keys */
3422  heap_truncate_check_FKs(relations, true);
3423 
3424  /* OK to do it */
3425  foreach(cell, relations)
3426  {
3427  Relation rel = lfirst(cell);
3428 
3429  /* Truncate the relation */
3430  heap_truncate_one_rel(rel);
3431 
3432  /* Close the relation, but keep exclusive lock on it until commit */
3433  table_close(rel, NoLock);
3434  }
3435 }
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3491
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3447
#define lfirst(lc)
Definition: pg_list.h:172
#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 3491 of file heap.c.

3492 {
3493  List *oids = NIL;
3494  List *dependents;
3495  ListCell *cell;
3496 
3497  /*
3498  * Build a list of OIDs of the interesting relations.
3499  *
3500  * If a relation has no triggers, then it can neither have FKs nor be
3501  * referenced by a FK from another table, so we can ignore it. For
3502  * partitioned tables, FKs have no triggers, so we must include them
3503  * anyway.
3504  */
3505  foreach(cell, relations)
3506  {
3507  Relation rel = lfirst(cell);
3508 
3509  if (rel->rd_rel->relhastriggers ||
3510  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3511  oids = lappend_oid(oids, RelationGetRelid(rel));
3512  }
3513 
3514  /*
3515  * Fast path: if no relation has triggers, none has FKs either.
3516  */
3517  if (oids == NIL)
3518  return;
3519 
3520  /*
3521  * Otherwise, must scan pg_constraint. We make one pass with all the
3522  * relations considered; if this finds nothing, then all is well.
3523  */
3524  dependents = heap_truncate_find_FKs(oids);
3525  if (dependents == NIL)
3526  return;
3527 
3528  /*
3529  * Otherwise we repeat the scan once per relation to identify a particular
3530  * pair of relations to complain about. This is pretty slow, but
3531  * performance shouldn't matter much in a failure path. The reason for
3532  * doing things this way is to ensure that the message produced is not
3533  * dependent on chance row locations within pg_constraint.
3534  */
3535  foreach(cell, oids)
3536  {
3537  Oid relid = lfirst_oid(cell);
3538  ListCell *cell2;
3539 
3540  dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3541 
3542  foreach(cell2, dependents)
3543  {
3544  Oid relid2 = lfirst_oid(cell2);
3545 
3546  if (!list_member_oid(oids, relid2))
3547  {
3548  char *relname = get_rel_name(relid);
3549  char *relname2 = get_rel_name(relid2);
3550 
3551  if (tempTables)
3552  ereport(ERROR,
3553  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3554  errmsg("unsupported ON COMMIT and foreign key combination"),
3555  errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3556  relname2, relname)));
3557  else
3558  ereport(ERROR,
3559  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3560  errmsg("cannot truncate a table referenced in a foreign key constraint"),
3561  errdetail("Table \"%s\" references \"%s\".",
3562  relname2, relname),
3563  errhint("Truncate table \"%s\" at the same time, "
3564  "or use TRUNCATE ... CASCADE.",
3565  relname2)));
3566  }
3567  }
3568  }
3569 }
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3586
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 3586 of file heap.c.

3587 {
3588  List *result = NIL;
3589  List *oids;
3590  List *parent_cons;
3591  ListCell *cell;
3592  ScanKeyData key;
3593  Relation fkeyRel;
3594  SysScanDesc fkeyScan;
3595  HeapTuple tuple;
3596  bool restart;
3597 
3598  oids = list_copy(relationIds);
3599 
3600  /*
3601  * Must scan pg_constraint. Right now, it is a seqscan because there is
3602  * no available index on confrelid.
3603  */
3604  fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3605 
3606 restart:
3607  restart = false;
3608  parent_cons = NIL;
3609 
3610  fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3611  NULL, 0, NULL);
3612 
3613  while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3614  {
3616 
3617  /* Not a foreign key */
3618  if (con->contype != CONSTRAINT_FOREIGN)
3619  continue;
3620 
3621  /* Not referencing one of our list of tables */
3622  if (!list_member_oid(oids, con->confrelid))
3623  continue;
3624 
3625  /*
3626  * If this constraint has a parent constraint which we have not seen
3627  * yet, keep track of it for the second loop, below. Tracking parent
3628  * constraints allows us to climb up to the top-level constraint and
3629  * look for all possible relations referencing the partitioned table.
3630  */
3631  if (OidIsValid(con->conparentid) &&
3632  !list_member_oid(parent_cons, con->conparentid))
3633  parent_cons = lappend_oid(parent_cons, con->conparentid);
3634 
3635  /*
3636  * Add referencer to result, unless present in input list. (Don't
3637  * worry about dupes: we'll fix that below).
3638  */
3639  if (!list_member_oid(relationIds, con->conrelid))
3640  result = lappend_oid(result, con->conrelid);
3641  }
3642 
3643  systable_endscan(fkeyScan);
3644 
3645  /*
3646  * Process each parent constraint we found to add the list of referenced
3647  * relations by them to the oids list. If we do add any new such
3648  * relations, redo the first loop above. Also, if we see that the parent
3649  * constraint in turn has a parent, add that so that we process all
3650  * relations in a single additional pass.
3651  */
3652  foreach(cell, parent_cons)
3653  {
3654  Oid parent = lfirst_oid(cell);
3655 
3656  ScanKeyInit(&key,
3657  Anum_pg_constraint_oid,
3658  BTEqualStrategyNumber, F_OIDEQ,
3659  ObjectIdGetDatum(parent));
3660 
3661  fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3662  true, NULL, 1, &key);
3663 
3664  tuple = systable_getnext(fkeyScan);
3665  if (HeapTupleIsValid(tuple))
3666  {
3668 
3669  /*
3670  * pg_constraint rows always appear for partitioned hierarchies
3671  * this way: on the each side of the constraint, one row appears
3672  * for each partition that points to the top-most table on the
3673  * other side.
3674  *
3675  * Because of this arrangement, we can correctly catch all
3676  * relevant relations by adding to 'parent_cons' all rows with
3677  * valid conparentid, and to the 'oids' list all rows with a zero
3678  * conparentid. If any oids are added to 'oids', redo the first
3679  * loop above by setting 'restart'.
3680  */
3681  if (OidIsValid(con->conparentid))
3682  parent_cons = list_append_unique_oid(parent_cons,
3683  con->conparentid);
3684  else if (!list_member_oid(oids, con->confrelid))
3685  {
3686  oids = lappend_oid(oids, con->confrelid);
3687  restart = true;
3688  }
3689  }
3690 
3691  systable_endscan(fkeyScan);
3692  }
3693 
3694  list_free(parent_cons);
3695  if (restart)
3696  goto restart;
3697 
3698  table_close(fkeyRel, AccessShareLock);
3699  list_free(oids);
3700 
3701  /* Now sort and de-duplicate the result list */
3702  list_sort(result, list_oid_cmp);
3703  list_deduplicate_oid(result);
3704 
3705  return result;
3706 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
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 3447 of file heap.c.

3448 {
3449  Oid toastrelid;
3450 
3451  /*
3452  * Truncate the relation. Partitioned tables have no storage, so there is
3453  * nothing to do for them here.
3454  */
3455  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3456  return;
3457 
3458  /* Truncate the underlying relation */
3460 
3461  /* If the relation has indexes, truncate the indexes too */
3463 
3464  /* If there is a toast table, truncate that too */
3465  toastrelid = rel->rd_rel->reltoastrelid;
3466  if (OidIsValid(toastrelid))
3467  {
3468  Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3469 
3471  RelationTruncateIndexes(toastrel);
3472  /* keep the lock... */
3473  table_close(toastrel, NoLock);
3474  }
3475 }
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3358
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1648

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:983
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 896 of file heap.c.

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

1948 {
1949  Relation attr_rel;
1950  Oid relid = RelationGetRelid(rel);
1951  int natts = RelationGetNumberOfAttributes(rel);
1952  int attnum;
1953  Datum repl_val[Natts_pg_attribute];
1954  bool repl_null[Natts_pg_attribute];
1955  bool repl_repl[Natts_pg_attribute];
1956  Form_pg_attribute attrtuple;
1957  HeapTuple tuple,
1958  newtuple;
1959 
1960  memset(repl_val, 0, sizeof(repl_val));
1961  memset(repl_null, false, sizeof(repl_null));
1962  memset(repl_repl, false, sizeof(repl_repl));
1963 
1964  repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false);
1965  repl_null[Anum_pg_attribute_attmissingval - 1] = true;
1966 
1967  repl_repl[Anum_pg_attribute_atthasmissing - 1] = true;
1968  repl_repl[Anum_pg_attribute_attmissingval - 1] = true;
1969 
1970 
1971  /* Get a lock on pg_attribute */
1972  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
1973 
1974  /* process each non-system attribute, including any dropped columns */
1975  for (attnum = 1; attnum <= natts; attnum++)
1976  {
1977  tuple = SearchSysCache2(ATTNUM,
1978  ObjectIdGetDatum(relid),
1980  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1981  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1982  attnum, relid);
1983 
1984  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
1985 
1986  /* ignore any where atthasmissing is not true */
1987  if (attrtuple->atthasmissing)
1988  {
1989  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
1990  repl_val, repl_null, repl_repl);
1991 
1992  CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
1993 
1994  heap_freetuple(newtuple);
1995  }
1996 
1997  ReleaseSysCache(tuple);
1998  }
1999 
2000  /*
2001  * Our update of the pg_attribute rows will force a relcache rebuild, so
2002  * there's nothing else to do here.
2003  */
2004  table_close(attr_rel, RowExclusiveLock);
2005 }
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:232

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 1666 of file heap.c.

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

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 3838 of file heap.c.

3839 {
3840  Relation rel;
3841  HeapTuple tuple;
3842 
3843  rel = table_open(PartitionedRelationId, RowExclusiveLock);
3844 
3845  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3846  if (!HeapTupleIsValid(tuple))
3847  elog(ERROR, "cache lookup failed for partition key of relation %u",
3848  relid);
3849 
3850  CatalogTupleDelete(rel, &tuple->t_self);
3851 
3852  ReleaseSysCache(tuple);
3854 }

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 3311 of file heap.c.

3312 {
3313  Relation pgstatistic;
3314  SysScanDesc scan;
3315  ScanKeyData key[2];
3316  int nkeys;
3317  HeapTuple tuple;
3318 
3319  pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3320 
3321  ScanKeyInit(&key[0],
3322  Anum_pg_statistic_starelid,
3323  BTEqualStrategyNumber, F_OIDEQ,
3324  ObjectIdGetDatum(relid));
3325 
3326  if (attnum == 0)
3327  nkeys = 1;
3328  else
3329  {
3330  ScanKeyInit(&key[1],
3331  Anum_pg_statistic_staattnum,
3332  BTEqualStrategyNumber, F_INT2EQ,
3334  nkeys = 2;
3335  }
3336 
3337  scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3338  NULL, nkeys, key);
3339 
3340  /* we must loop even when attnum != 0, in case of inherited stats */
3341  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3342  CatalogTupleDelete(pgstatistic, &tuple->t_self);
3343 
3344  systable_endscan(scan);
3345 
3346  table_close(pgstatistic, RowExclusiveLock);
3347 }

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 2015 of file heap.c.

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

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 3869 of file heap.c.

3870 {
3871  Relation classRel;
3872  HeapTuple tuple,
3873  newtuple;
3874  Datum new_val[Natts_pg_class];
3875  bool new_null[Natts_pg_class],
3876  new_repl[Natts_pg_class];
3877  Oid defaultPartOid;
3878 
3879  /* Update pg_class tuple */
3880  classRel = table_open(RelationRelationId, RowExclusiveLock);
3881  tuple = SearchSysCacheCopy1(RELOID,
3883  if (!HeapTupleIsValid(tuple))
3884  elog(ERROR, "cache lookup failed for relation %u",
3885  RelationGetRelid(rel));
3886 
3887 #ifdef USE_ASSERT_CHECKING
3888  {
3889  Form_pg_class classForm;
3890  bool isnull;
3891 
3892  classForm = (Form_pg_class) GETSTRUCT(tuple);
3893  Assert(!classForm->relispartition);
3894  (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
3895  &isnull);
3896  Assert(isnull);
3897  }
3898 #endif
3899 
3900  /* Fill in relpartbound value */
3901  memset(new_val, 0, sizeof(new_val));
3902  memset(new_null, false, sizeof(new_null));
3903  memset(new_repl, false, sizeof(new_repl));
3904  new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
3905  new_null[Anum_pg_class_relpartbound - 1] = false;
3906  new_repl[Anum_pg_class_relpartbound - 1] = true;
3907  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
3908  new_val, new_null, new_repl);
3909  /* Also set the flag */
3910  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
3911 
3912  /*
3913  * We already checked for no inheritance children, but reset
3914  * relhassubclass in case it was left over.
3915  */
3916  if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
3917  ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
3918 
3919  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
3920  heap_freetuple(newtuple);
3921  table_close(classRel, RowExclusiveLock);
3922 
3923  /*
3924  * If we're storing bounds for the default partition, update
3925  * pg_partitioned_table too.
3926  */
3927  if (bound->is_default)
3929  RelationGetRelid(rel));
3930 
3931  /* Make these updates visible */
3933 
3934  /*
3935  * The partition constraint for the default partition depends on the
3936  * partition bounds of every other partition, so we must invalidate the
3937  * relcache entry for that partition every time a partition is added or
3938  * removed.
3939  */
3940  defaultPartOid =
3942  if (OidIsValid(defaultPartOid))
3943  CacheInvalidateRelcacheByRelid(defaultPartOid);
3944 
3945  CacheInvalidateRelcache(parent);
3946 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1553
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:501
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void CommandCounterIncrement(void)
Definition: xact.c:1099

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, RelationData::rd_rel, RelationGetDescr, RelationGetPartitionDesc(), RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy1, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and update_default_partition_oid().

Referenced by ATExecAttachPartition(), and DefineRelation().

◆ StorePartitionKey()

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

Definition at line 3713 of file heap.c.

3720 {
3721  int i;
3722  int2vector *partattrs_vec;
3723  oidvector *partopclass_vec;
3724  oidvector *partcollation_vec;
3725  Datum partexprDatum;
3726  Relation pg_partitioned_table;
3727  HeapTuple tuple;
3728  Datum values[Natts_pg_partitioned_table];
3729  bool nulls[Natts_pg_partitioned_table] = {0};
3730  ObjectAddress myself;
3731  ObjectAddress referenced;
3732  ObjectAddresses *addrs;
3733 
3734  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3735 
3736  /* Copy the partition attribute numbers, opclass OIDs into arrays */
3737  partattrs_vec = buildint2vector(partattrs, partnatts);
3738  partopclass_vec = buildoidvector(partopclass, partnatts);
3739  partcollation_vec = buildoidvector(partcollation, partnatts);
3740 
3741  /* Convert the expressions (if any) to a text datum */
3742  if (partexprs)
3743  {
3744  char *exprString;
3745 
3746  exprString = nodeToString(partexprs);
3747  partexprDatum = CStringGetTextDatum(exprString);
3748  pfree(exprString);
3749  }
3750  else
3751  partexprDatum = (Datum) 0;
3752 
3753  pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3754 
3755  /* Only this can ever be NULL */
3756  if (!partexprDatum)
3757  nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3758 
3759  values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3760  values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3761  values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3762  values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3763  values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3764  values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3765  values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3766  values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3767 
3768  tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3769 
3770  CatalogTupleInsert(pg_partitioned_table, tuple);
3771  table_close(pg_partitioned_table, RowExclusiveLock);
3772 
3773  /* Mark this relation as dependent on a few things as follows */
3774  addrs = new_object_addresses();
3775  ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3776 
3777  /* Operator class and collation per key column */
3778  for (i = 0; i < partnatts; i++)
3779  {
3780  ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3781  add_exact_object_address(&referenced, addrs);
3782 
3783  /* The default collation is pinned, so don't bother recording it */
3784  if (OidIsValid(partcollation[i]) &&
3785  partcollation[i] != DEFAULT_COLLATION_OID)
3786  {
3787  ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3788  add_exact_object_address(&referenced, addrs);
3789  }
3790  }
3791 
3793  free_object_addresses(addrs);
3794 
3795  /*
3796  * The partitioning columns are made internally dependent on the table,
3797  * because we cannot drop any of them without dropping the whole table.
3798  * (ATExecDropColumn independently enforces that, but it's not bulletproof
3799  * so we need the dependencies too.)
3800  */
3801  for (i = 0; i < partnatts; i++)
3802  {
3803  if (partattrs[i] == 0)
3804  continue; /* ignore expressions here */
3805 
3806  ObjectAddressSubSet(referenced, RelationRelationId,
3807  RelationGetRelid(rel), partattrs[i]);
3808  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3809  }
3810 
3811  /*
3812  * Also consider anything mentioned in partition expressions. External
3813  * references (e.g. functions) get NORMAL dependencies. Table columns
3814  * mentioned in the expressions are handled the same as plain partitioning
3815  * columns, i.e. they become internally dependent on the whole table.
3816  */
3817  if (partexprs)
3819  (Node *) partexprs,
3820  RelationGetRelid(rel),
3823  true /* reverse the self-deps */ );
3824 
3825  /*
3826  * We must invalidate the relcache so that the next
3827  * CommandCounterIncrement() will cause the same to be rebuilt using the
3828  * information in just created catalog entry.
3829  */
3831 }
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ 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:45
Definition: c.h:694
Definition: c.h:705

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:767
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().