PostgreSQL Source Code  git master
heap.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/relation.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_subscription_rel.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "partitioning/partdesc.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for heap.c:

Go to the source code of this file.

Functions

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)
 
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)
 
static void RelationRemoveInheritance (Oid relid)
 
static Oid StoreRelCheck (Relation rel, const char *ccname, Node *expr, bool is_validated, bool is_local, int inhcount, bool is_no_inherit, bool is_internal)
 
static void StoreConstraints (Relation rel, List *cooked_constraints, bool is_internal)
 
static bool MergeWithExistingConstraint (Relation rel, const char *ccname, Node *expr, bool allow_merge, bool is_local, bool is_initially_valid, bool is_no_inherit)
 
static void SetRelationNumChecks (Relation rel, int numchecks)
 
static NodecookConstraint (ParseState *pstate, Node *raw_constraint, char *relname)
 
const FormData_pg_attributeSystemAttributeDefinition (AttrNumber attno)
 
const FormData_pg_attributeSystemAttributeByName (const char *attname)
 
Relation heap_create (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode, 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)
 
void CheckAttributeNamesTypes (TupleDesc tupdesc, char relkind, int flags)
 
void CheckAttributeType (const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
 
void InsertPgAttributeTuples (Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
 
static void AddNewAttributeTuples (Oid new_rel_oid, TupleDesc tupdesc, char relkind)
 
void InsertPgClassTuple (Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
 
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 DeleteRelationTuple (Oid relid)
 
void DeleteAttributeTuples (Oid relid)
 
void DeleteSystemAttributeTuples (Oid relid)
 
void RemoveAttributeById (Oid relid, AttrNumber attnum)
 
void RemoveAttrDefault (Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
 
void RemoveAttrDefaultById (Oid attrdefId)
 
void heap_drop_with_catalog (Oid relid)
 
void RelationClearMissing (Relation rel)
 
void SetAttrMissing (Oid relid, char *attname, char *value)
 
Oid StoreAttrDefault (Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
 
ListAddRelationNewConstraints (Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
 
static bool check_nested_generated_walker (Node *node, void *context)
 
static void check_nested_generated (ParseState *pstate, Node *node)
 
NodecookDefault (ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
 
void CopyStatistics (Oid fromrelid, Oid torelid)
 
void RemoveStatistics (Oid relid, AttrNumber attnum)
 
static void RelationTruncateIndexes (Relation heapRelation)
 
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 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)
 

Variables

Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid
 
Oid binary_upgrade_next_heap_pg_class_relfilenode = InvalidOid
 
Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid
 
Oid binary_upgrade_next_toast_pg_class_relfilenode = InvalidOid
 
static const FormData_pg_attribute a1
 
static const FormData_pg_attribute a2
 
static const FormData_pg_attribute a3
 
static const FormData_pg_attribute a4
 
static const FormData_pg_attribute a5
 
static const FormData_pg_attribute a6
 
static const FormData_pg_attributeSysAtt [] = {&a1, &a2, &a3, &a4, &a5, &a6}
 

Function Documentation

◆ AddNewAttributeTuples()

static void AddNewAttributeTuples ( Oid  new_rel_oid,
TupleDesc  tupdesc,
char  relkind 
)
static

Definition at line 815 of file heap.c.

818 {
819  Relation rel;
820  CatalogIndexState indstate;
821  int natts = tupdesc->natts;
822  ObjectAddress myself,
823  referenced;
824 
825  /*
826  * open pg_attribute and its indexes.
827  */
828  rel = table_open(AttributeRelationId, RowExclusiveLock);
829 
830  indstate = CatalogOpenIndexes(rel);
831 
832  /* set stats detail level to a sane default */
833  for (int i = 0; i < natts; i++)
834  tupdesc->attrs[i].attstattarget = -1;
835  InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate);
836 
837  /* add dependencies on their datatypes and collations */
838  for (int i = 0; i < natts; i++)
839  {
840  /* Add dependency info */
841  ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1);
842  ObjectAddressSet(referenced, TypeRelationId,
843  tupdesc->attrs[i].atttypid);
844  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845 
846  /* The default collation is pinned, so don't bother recording it */
847  if (OidIsValid(tupdesc->attrs[i].attcollation) &&
848  tupdesc->attrs[i].attcollation != DEFAULT_COLLATION_OID)
849  {
850  ObjectAddressSet(referenced, CollationRelationId,
851  tupdesc->attrs[i].attcollation);
852  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
853  }
854  }
855 
856  /*
857  * Next we add the system attributes. Skip OID if rel has no OIDs. Skip
858  * all for a view or type relation. We don't bother with making datatype
859  * dependencies here, since presumably all these types are pinned.
860  */
861  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
862  {
863  TupleDesc td;
864 
866 
867  InsertPgAttributeTuples(rel, td, new_rel_oid, NULL, indstate);
868  FreeTupleDesc(td);
869  }
870 
871  /*
872  * clean up
873  */
874  CatalogCloseIndexes(indstate);
875 
877 }
#define lengthof(array)
Definition: c.h:734
#define OidIsValid(objectId)
Definition: c.h:710
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:708
static const FormData_pg_attribute * SysAtt[]
Definition: heap.c:245
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
int i
Definition: isn.c:73
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_attribute
Definition: pg_attribute.h:191
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER]
Definition: tupdesc.h:87
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:90

References TupleDescData::attrs, CatalogCloseIndexes(), CatalogOpenIndexes(), CreateTupleDesc(), DEPENDENCY_NORMAL, FormData_pg_attribute, FreeTupleDesc(), i, InsertPgAttributeTuples(), lengthof, TupleDescData::natts, ObjectAddressSet, ObjectAddressSubSet, OidIsValid, recordDependencyOn(), RowExclusiveLock, SysAtt, table_close(), and table_open().

Referenced by heap_create_with_catalog().

◆ AddNewRelationTuple()

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 
)
static

Definition at line 966 of file heap.c.

977 {
978  Form_pg_class new_rel_reltup;
979 
980  /*
981  * first we update some of the information in our uncataloged relation's
982  * relation descriptor.
983  */
984  new_rel_reltup = new_rel_desc->rd_rel;
985 
986  /* The relation is empty */
987  new_rel_reltup->relpages = 0;
988  new_rel_reltup->reltuples = -1;
989  new_rel_reltup->relallvisible = 0;
990 
991  /* Sequences always have a known size */
992  if (relkind == RELKIND_SEQUENCE)
993  {
994  new_rel_reltup->relpages = 1;
995  new_rel_reltup->reltuples = 1;
996  }
997 
998  new_rel_reltup->relfrozenxid = relfrozenxid;
999  new_rel_reltup->relminmxid = relminmxid;
1000  new_rel_reltup->relowner = relowner;
1001  new_rel_reltup->reltype = new_type_oid;
1002  new_rel_reltup->reloftype = reloftype;
1003 
1004  /* relispartition is always set by updating this tuple later */
1005  new_rel_reltup->relispartition = false;
1006 
1007  /* fill rd_att's type ID with something sane even if reltype is zero */
1008  new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
1009  new_rel_desc->rd_att->tdtypmod = -1;
1010 
1011  /* Now build and insert the tuple */
1012  InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
1013  relacl, reloptions);
1014 }
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:893
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
TupleDesc rd_att
Definition: rel.h:110
Form_pg_class rd_rel
Definition: rel.h:109
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82

References InsertPgClassTuple(), RelationData::rd_att, RelationData::rd_rel, TupleDescData::tdtypeid, and TupleDescData::tdtypmod.

Referenced by heap_create_with_catalog().

◆ AddNewRelationType()

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 
)
static

Definition at line 1024 of file heap.c.

1031 {
1032  return
1033  TypeCreate(new_row_type, /* optional predetermined OID */
1034  typeName, /* type name */
1035  typeNamespace, /* type namespace */
1036  new_rel_oid, /* relation oid */
1037  new_rel_kind, /* relation kind */
1038  ownerid, /* owner's ID */
1039  -1, /* internal size (varlena) */
1040  TYPTYPE_COMPOSITE, /* type-type (composite) */
1041  TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
1042  false, /* composite types are never preferred */
1043  DEFAULT_TYPDELIM, /* default array delimiter */
1044  F_RECORD_IN, /* input procedure */
1045  F_RECORD_OUT, /* output procedure */
1046  F_RECORD_RECV, /* receive procedure */
1047  F_RECORD_SEND, /* send procedure */
1048  InvalidOid, /* typmodin procedure - none */
1049  InvalidOid, /* typmodout procedure - none */
1050  InvalidOid, /* analyze procedure - default */
1051  InvalidOid, /* subscript procedure - none */
1052  InvalidOid, /* array element type - irrelevant */
1053  false, /* this is not an array type */
1054  new_array_type, /* array type if any */
1055  InvalidOid, /* domain base type - irrelevant */
1056  NULL, /* default value - none */
1057  NULL, /* default binary representation */
1058  false, /* passed by reference */
1059  TYPALIGN_DOUBLE, /* alignment - must be the largest! */
1060  TYPSTORAGE_EXTENDED, /* fully TOASTable */
1061  -1, /* typmod */
1062  0, /* array dimensions for typBaseType */
1063  false, /* Type NOT NULL */
1064  InvalidOid); /* rowtypes never have a collation */
1065 }
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:198
#define InvalidOid
Definition: postgres_ext.h:36
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22

References DEFAULT_TYPDELIM, InvalidOid, and TypeCreate().

Referenced by heap_create_with_catalog().

◆ AddRelationNewConstraints()

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

Definition at line 2576 of file heap.c.

2583 {
2584  List *cookedConstraints = NIL;
2585  TupleDesc tupleDesc;
2586  TupleConstr *oldconstr;
2587  int numoldchecks;
2588  ParseState *pstate;
2589  ParseNamespaceItem *nsitem;
2590  int numchecks;
2591  List *checknames;
2592  ListCell *cell;
2593  Node *expr;
2594  CookedConstraint *cooked;
2595 
2596  /*
2597  * Get info about existing constraints.
2598  */
2599  tupleDesc = RelationGetDescr(rel);
2600  oldconstr = tupleDesc->constr;
2601  if (oldconstr)
2602  numoldchecks = oldconstr->num_check;
2603  else
2604  numoldchecks = 0;
2605 
2606  /*
2607  * Create a dummy ParseState and insert the target relation as its sole
2608  * rangetable entry. We need a ParseState for transformExpr.
2609  */
2610  pstate = make_parsestate(NULL);
2611  pstate->p_sourcetext = queryString;
2612  nsitem = addRangeTableEntryForRelation(pstate,
2613  rel,
2615  NULL,
2616  false,
2617  true);
2618  addNSItemToQuery(pstate, nsitem, true, true, true);
2619 
2620  /*
2621  * Process column default expressions.
2622  */
2623  foreach(cell, newColDefaults)
2624  {
2625  RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
2626  Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
2627  Oid defOid;
2628 
2629  expr = cookDefault(pstate, colDef->raw_default,
2630  atp->atttypid, atp->atttypmod,
2631  NameStr(atp->attname),
2632  atp->attgenerated);
2633 
2634  /*
2635  * If the expression is just a NULL constant, we do not bother to make
2636  * an explicit pg_attrdef entry, since the default behavior is
2637  * equivalent. This applies to column defaults, but not for
2638  * generation expressions.
2639  *
2640  * Note a nonobvious property of this test: if the column is of a
2641  * domain type, what we'll get is not a bare null Const but a
2642  * CoerceToDomain expr, so we will not discard the default. This is
2643  * critical because the column default needs to be retained to
2644  * override any default that the domain might have.
2645  */
2646  if (expr == NULL ||
2647  (!colDef->generated &&
2648  IsA(expr, Const) &&
2649  castNode(Const, expr)->constisnull))
2650  continue;
2651 
2652  /* If the DEFAULT is volatile we cannot use a missing value */
2653  if (colDef->missingMode && contain_volatile_functions((Node *) expr))
2654  colDef->missingMode = false;
2655 
2656  defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal,
2657  colDef->missingMode);
2658 
2659  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2660  cooked->contype = CONSTR_DEFAULT;
2661  cooked->conoid = defOid;
2662  cooked->name = NULL;
2663  cooked->attnum = colDef->attnum;
2664  cooked->expr = expr;
2665  cooked->skip_validation = false;
2666  cooked->is_local = is_local;
2667  cooked->inhcount = is_local ? 0 : 1;
2668  cooked->is_no_inherit = false;
2669  cookedConstraints = lappend(cookedConstraints, cooked);
2670  }
2671 
2672  /*
2673  * Process constraint expressions.
2674  */
2675  numchecks = numoldchecks;
2676  checknames = NIL;
2677  foreach(cell, newConstraints)
2678  {
2679  Constraint *cdef = (Constraint *) lfirst(cell);
2680  char *ccname;
2681  Oid constrOid;
2682 
2683  if (cdef->contype != CONSTR_CHECK)
2684  continue;
2685 
2686  if (cdef->raw_expr != NULL)
2687  {
2688  Assert(cdef->cooked_expr == NULL);
2689 
2690  /*
2691  * Transform raw parsetree to executable expression, and verify
2692  * it's valid as a CHECK constraint.
2693  */
2694  expr = cookConstraint(pstate, cdef->raw_expr,
2696  }
2697  else
2698  {
2699  Assert(cdef->cooked_expr != NULL);
2700 
2701  /*
2702  * Here, we assume the parser will only pass us valid CHECK
2703  * expressions, so we do no particular checking.
2704  */
2705  expr = stringToNode(cdef->cooked_expr);
2706  }
2707 
2708  /*
2709  * Check name uniqueness, or generate a name if none was given.
2710  */
2711  if (cdef->conname != NULL)
2712  {
2713  ListCell *cell2;
2714 
2715  ccname = cdef->conname;
2716  /* Check against other new constraints */
2717  /* Needed because we don't do CommandCounterIncrement in loop */
2718  foreach(cell2, checknames)
2719  {
2720  if (strcmp((char *) lfirst(cell2), ccname) == 0)
2721  ereport(ERROR,
2723  errmsg("check constraint \"%s\" already exists",
2724  ccname)));
2725  }
2726 
2727  /* save name for future checks */
2728  checknames = lappend(checknames, ccname);
2729 
2730  /*
2731  * Check against pre-existing constraints. If we are allowed to
2732  * merge with an existing constraint, there's no more to do here.
2733  * (We omit the duplicate constraint from the result, which is
2734  * what ATAddCheckConstraint wants.)
2735  */
2736  if (MergeWithExistingConstraint(rel, ccname, expr,
2737  allow_merge, is_local,
2738  cdef->initially_valid,
2739  cdef->is_no_inherit))
2740  continue;
2741  }
2742  else
2743  {
2744  /*
2745  * When generating a name, we want to create "tab_col_check" for a
2746  * column constraint and "tab_check" for a table constraint. We
2747  * no longer have any info about the syntactic positioning of the
2748  * constraint phrase, so we approximate this by seeing whether the
2749  * expression references more than one column. (If the user
2750  * played by the rules, the result is the same...)
2751  *
2752  * Note: pull_var_clause() doesn't descend into sublinks, but we
2753  * eliminated those above; and anyway this only needs to be an
2754  * approximate answer.
2755  */
2756  List *vars;
2757  char *colname;
2758 
2759  vars = pull_var_clause(expr, 0);
2760 
2761  /* eliminate duplicates */
2762  vars = list_union(NIL, vars);
2763 
2764  if (list_length(vars) == 1)
2765  colname = get_attname(RelationGetRelid(rel),
2766  ((Var *) linitial(vars))->varattno,
2767  true);
2768  else
2769  colname = NULL;
2770 
2772  colname,
2773  "check",
2774  RelationGetNamespace(rel),
2775  checknames);
2776 
2777  /* save name for future checks */
2778  checknames = lappend(checknames, ccname);
2779  }
2780 
2781  /*
2782  * OK, store it.
2783  */
2784  constrOid =
2785  StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
2786  is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
2787 
2788  numchecks++;
2789 
2790  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2791  cooked->contype = CONSTR_CHECK;
2792  cooked->conoid = constrOid;
2793  cooked->name = ccname;
2794  cooked->attnum = 0;
2795  cooked->expr = expr;
2796  cooked->skip_validation = cdef->skip_validation;
2797  cooked->is_local = is_local;
2798  cooked->inhcount = is_local ? 0 : 1;
2799  cooked->is_no_inherit = cdef->is_no_inherit;
2800  cookedConstraints = lappend(cookedConstraints, cooked);
2801  }
2802 
2803  /*
2804  * Update the count of constraints in the relation's pg_class tuple. We do
2805  * this even if there was no change, in order to ensure that an SI update
2806  * message is sent out for the pg_class tuple, which will force other
2807  * backends to rebuild their relcache entries for the rel. (This is
2808  * critical if we added defaults but not constraints.)
2809  */
2810  SetRelationNumChecks(rel, numchecks);
2811 
2812  return cookedConstraints;
2813 }
#define NameStr(name)
Definition: c.h:681
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:453
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr, bool is_validated, bool is_local, int inhcount, bool is_no_inherit, bool is_internal)
Definition: heap.c:2394
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:2826
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3070
static void SetRelationNumChecks(Relation rel, int numchecks)
Definition: heap.c:2976
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal, bool add_column_mode)
Definition: heap.c:2208
static Node * cookConstraint(ParseState *pstate, Node *raw_constraint, char *relname)
Definition: heap.c:3145
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_union(const List *list1, const List *list2)
Definition: list.c:1025
List * lappend(List *list, void *datum)
Definition: list.c:336
#define AccessShareLock
Definition: lockdefs.h:36
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
void * palloc(Size size)
Definition: mcxt.c:1062
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
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:2235
@ CONSTR_CHECK
Definition: parsenodes.h:2238
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define NIL
Definition: pg_list.h:65
#define linitial(l)
Definition: pg_list.h:174
unsigned int Oid
Definition: postgres_ext.h:31
void * stringToNode(const char *str)
Definition: read.c:89
#define RelationGetRelid(relation)
Definition: rel.h:478
#define RelationGetDescr(relation)
Definition: rel.h:504
#define RelationGetRelationName(relation)
Definition: rel.h:512
#define RelationGetNamespace(relation)
Definition: rel.h:519
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ConstrType contype
Definition: parsenodes.h:2264
bool is_no_inherit
Definition: parsenodes.h:2273
char * cooked_expr
Definition: parsenodes.h:2275
bool initially_valid
Definition: parsenodes.h:2311
bool skip_validation
Definition: parsenodes.h:2310
Node * raw_expr
Definition: parsenodes.h:2274
char * conname
Definition: parsenodes.h:2267
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
AttrNumber attnum
Definition: heap.h:40
bool skip_validation
Definition: heap.h:42
bool is_no_inherit
Definition: heap.h:45
int inhcount
Definition: heap.h:44
bool is_local
Definition: heap.h:43
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
Definition: pg_list.h:51
Definition: nodes.h:540
const char * p_sourcetext
Definition: parse_node.h:181
Node * raw_default
Definition: heap.h:30
AttrNumber attnum
Definition: heap.h:29
char generated
Definition: heap.h:32
bool missingMode
Definition: heap.h:31
uint16 num_check
Definition: tupdesc.h:43
TupleConstr * constr
Definition: tupdesc.h:85
Definition: primnodes.h:187
Definition: regcomp.c:238
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
List * pull_var_clause(Node *node, int flags)
Definition: var.c:604

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), Assert(), RawColumnDefault::attnum, CookedConstraint::attnum, castNode, ChooseConstraintName(), Constraint::conname, CookedConstraint::conoid, TupleDescData::constr, CONSTR_CHECK, CONSTR_DEFAULT, contain_volatile_functions(), CookedConstraint::contype, Constraint::contype, cookConstraint(), cookDefault(), Constraint::cooked_expr, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CookedConstraint::expr, RawColumnDefault::generated, get_attname(), CookedConstraint::inhcount, Constraint::initially_valid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, Constraint::is_no_inherit, IsA, lappend(), lfirst, linitial, list_length(), list_union(), make_parsestate(), MergeWithExistingConstraint(), RawColumnDefault::missingMode, CookedConstraint::name, NameStr, NIL, TupleConstr::num_check, ParseState::p_sourcetext, palloc(), pull_var_clause(), RawColumnDefault::raw_default, Constraint::raw_expr, RelationData::rd_att, RelationGetDescr, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, SetRelationNumChecks(), CookedConstraint::skip_validation, Constraint::skip_validation, StoreAttrDefault(), StoreRelCheck(), stringToNode(), and TupleDescAttr.

Referenced by ATAddCheckConstraint(), ATExecAddColumn(), ATExecColumnDefault(), and DefineRelation().

◆ check_nested_generated()

static void check_nested_generated ( ParseState pstate,
Node node 
)
static

Definition at line 3052 of file heap.c.

3053 {
3054  check_nested_generated_walker(node, pstate);
3055 }
static bool check_nested_generated_walker(Node *node, void *context)
Definition: heap.c:3010

References check_nested_generated_walker().

Referenced by cookDefault().

◆ check_nested_generated_walker()

static bool check_nested_generated_walker ( Node node,
void *  context 
)
static

Definition at line 3010 of file heap.c.

3011 {
3012  ParseState *pstate = context;
3013 
3014  if (node == NULL)
3015  return false;
3016  else if (IsA(node, Var))
3017  {
3018  Var *var = (Var *) node;
3019  Oid relid;
3021 
3022  relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
3023  if (!OidIsValid(relid))
3024  return false; /* XXX shouldn't we raise an error? */
3025 
3026  attnum = var->varattno;
3027 
3028  if (attnum > 0 && get_attgenerated(relid, attnum))
3029  ereport(ERROR,
3030  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3031  errmsg("cannot use generated column \"%s\" in column generation expression",
3032  get_attname(relid, attnum, false)),
3033  errdetail("A generated column cannot reference another generated column."),
3034  parser_errposition(pstate, var->location)));
3035  /* A whole-row Var is necessarily self-referential, so forbid it */
3036  if (attnum == 0)
3037  ereport(ERROR,
3038  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3039  errmsg("cannot use whole-row variable in column generation expression"),
3040  errdetail("This would cause the generated column to depend on its own value."),
3041  parser_errposition(pstate, var->location)));
3042  /* System columns were already checked in the parser */
3043 
3044  return false;
3045  }
3046  else
3048  (void *) context);
3049 }
int16 AttrNumber
Definition: attnum.h:21
int errdetail(const char *fmt,...)
Definition: elog.c:1037
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:913
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
int16 attnum
Definition: pg_attribute.h:83
List * p_rtable
Definition: parse_node.h:182
AttrNumber varattno
Definition: primnodes.h:191
int varno
Definition: primnodes.h:189
int location
Definition: primnodes.h:201

References attnum, ereport, errcode(), errdetail(), errmsg(), ERROR, expression_tree_walker(), get_attgenerated(), get_attname(), IsA, Var::location, OidIsValid, ParseState::p_rtable, parser_errposition(), rt_fetch, Var::varattno, and Var::varno.

Referenced by check_nested_generated().

◆ CheckAttributeNamesTypes()

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

Definition at line 466 of file heap.c.

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

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

References AccessShareLock, attname, 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().

◆ cookConstraint()

static Node * cookConstraint ( ParseState pstate,
Node raw_constraint,
char *  relname 
)
static

Definition at line 3145 of file heap.c.

3148 {
3149  Node *expr;
3150 
3151  /*
3152  * Transform raw parsetree to executable expression.
3153  */
3154  expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
3155 
3156  /*
3157  * Make sure it yields a boolean result.
3158  */
3159  expr = coerce_to_boolean(pstate, expr, "CHECK");
3160 
3161  /*
3162  * Take care of collations.
3163  */
3164  assign_expr_collations(pstate, expr);
3165 
3166  /*
3167  * Make sure no outside relations are referred to (this is probably dead
3168  * code now that add_missing_from is history).
3169  */
3170  if (list_length(pstate->p_rtable) != 1)
3171  ereport(ERROR,
3172  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3173  errmsg("only table \"%s\" can be referenced in check constraint",
3174  relname)));
3175 
3176  return expr;
3177 }
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
@ EXPR_KIND_CHECK_CONSTRAINT
Definition: parse_node.h:66
NameData relname
Definition: pg_class.h:38

References assign_expr_collations(), coerce_to_boolean(), ereport, errcode(), errmsg(), ERROR, EXPR_KIND_CHECK_CONSTRAINT, list_length(), ParseState::p_rtable, relname, and transformExpr().

Referenced by AddRelationNewConstraints().

◆ cookDefault()

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

Definition at line 3070 of file heap.c.

3076 {
3077  Node *expr;
3078 
3079  Assert(raw_default != NULL);
3080 
3081  /*
3082  * Transform raw parsetree to executable expression.
3083  */
3084  expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3085 
3086  if (attgenerated)
3087  {
3088  check_nested_generated(pstate, expr);
3089 
3090  if (contain_mutable_functions(expr))
3091  ereport(ERROR,
3092  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3093  errmsg("generation expression is not immutable")));
3094  }
3095  else
3096  {
3097  /*
3098  * For a default expression, transformExpr() should have rejected
3099  * column references.
3100  */
3101  Assert(!contain_var_clause(expr));
3102  }
3103 
3104  /*
3105  * Coerce the expression to the correct type and typmod, if given. This
3106  * should match the parser's processing of non-defaulted expressions ---
3107  * see transformAssignedExpr().
3108  */
3109  if (OidIsValid(atttypid))
3110  {
3111  Oid type_id = exprType(expr);
3112 
3113  expr = coerce_to_target_type(pstate, expr, type_id,
3114  atttypid, atttypmod,
3117  -1);
3118  if (expr == NULL)
3119  ereport(ERROR,
3120  (errcode(ERRCODE_DATATYPE_MISMATCH),
3121  errmsg("column \"%s\" is of type %s"
3122  " but default expression is of type %s",
3123  attname,
3124  format_type_be(atttypid),
3125  format_type_be(type_id)),
3126  errhint("You will need to rewrite or cast the expression.")));
3127  }
3128 
3129  /*
3130  * Finally, take care of collations in the finished expression.
3131  */
3132  assign_expr_collations(pstate, expr);
3133 
3134  return expr;
3135 }
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:364
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3052
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
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
@ EXPR_KIND_COLUMN_DEFAULT
Definition: parse_node.h:68
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:81
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:485
@ COERCION_ASSIGNMENT
Definition: primnodes.h:464
bool contain_var_clause(Node *node)
Definition: var.c:400

References Assert(), assign_expr_collations(), attname, check_nested_generated(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, contain_mutable_functions(), 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 3183 of file heap.c.

3184 {
3185  HeapTuple tup;
3186  SysScanDesc scan;
3187  ScanKeyData key[1];
3188  Relation statrel;
3189 
3190  statrel = table_open(StatisticRelationId, RowExclusiveLock);
3191 
3192  /* Now search for stat records */
3193  ScanKeyInit(&key[0],
3194  Anum_pg_statistic_starelid,
3195  BTEqualStrategyNumber, F_OIDEQ,
3196  ObjectIdGetDatum(fromrelid));
3197 
3198  scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3199  true, NULL, 1, key);
3200 
3201  while (HeapTupleIsValid((tup = systable_getnext(scan))))
3202  {
3203  Form_pg_statistic statform;
3204 
3205  /* make a modifiable copy */
3206  tup = heap_copytuple(tup);
3207  statform = (Form_pg_statistic) GETSTRUCT(tup);
3208 
3209  /* update the copy of the tuple and insert it */
3210  statform->starelid = torelid;
3211  CatalogTupleInsert(statrel, tup);
3212 
3213  heap_freetuple(tup);
3214  }
3215 
3216  systable_endscan(scan);
3217 
3218  table_close(statrel, RowExclusiveLock);
3219 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
FormData_pg_statistic * Form_pg_statistic
Definition: pg_statistic.h:135
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References BTEqualStrategyNumber, CatalogTupleInsert(), 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 1576 of file heap.c.

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

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

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RELOID, 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 1613 of file heap.c.

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

Referenced by DefineQueryRewrite().

◆ heap_create()

Relation heap_create ( const char *  relname,
Oid  relnamespace,
Oid  reltablespace,
Oid  relid,
Oid  relfilenode,
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 302 of file heap.c.

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

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

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

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

References add_exact_object_address(), AddNewAttributeTuples(), AddNewRelationTuple(), AddNewRelationType(), Assert(), AssignTypeArrayOid(), binary_upgrade_next_heap_pg_class_oid, binary_upgrade_next_heap_pg_class_relfilenode, binary_upgrade_next_toast_pg_class_oid, binary_upgrade_next_toast_pg_class_relfilenode, 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(), GetNewRelFileNode(), GetSysCacheOid2, heap_create(), InvalidOid, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsNormalProcessingMode, makeArrayTypeName(), moveArrayTypeName(), new_object_addresses(), NoLock, OBJECT_SEQUENCE, OBJECT_TABLE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, ONCOMMIT_NOOP, pfree(), PointerGetDatum, RelationData::rd_att, RelationData::rd_rel, record_object_address_dependencies(), recordDependencyOnCurrentExtension(), recordDependencyOnNewAcl(), recordDependencyOnOwner(), register_on_commit_action(), RelationGetRelid, relname, RowExclusiveLock, StoreConstraints(), table_close(), table_open(), TypeCreate(), and TYPENAMENSP.

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

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)

Definition at line 1895 of file heap.c.

1896 {
1897  Relation rel;
1898  HeapTuple tuple;
1899  Oid parentOid = InvalidOid,
1900  defaultPartOid = InvalidOid;
1901 
1902  /*
1903  * To drop a partition safely, we must grab exclusive lock on its parent,
1904  * because another backend might be about to execute a query on the parent
1905  * table. If it relies on previously cached partition descriptor, then it
1906  * could attempt to access the just-dropped relation as its partition. We
1907  * must therefore take a table lock strong enough to prevent all queries
1908  * on the table from proceeding until we commit and send out a
1909  * shared-cache-inval notice that will make them update their partition
1910  * descriptors.
1911  */
1912  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1913  if (!HeapTupleIsValid(tuple))
1914  elog(ERROR, "cache lookup failed for relation %u", relid);
1915  if (((Form_pg_class) GETSTRUCT(tuple))->relispartition)
1916  {
1917  /*
1918  * We have to lock the parent if the partition is being detached,
1919  * because it's possible that some query still has a partition
1920  * descriptor that includes this partition.
1921  */
1922  parentOid = get_partition_parent(relid, true);
1924 
1925  /*
1926  * If this is not the default partition, dropping it will change the
1927  * default partition's partition constraint, so we must lock it.
1928  */
1929  defaultPartOid = get_default_partition_oid(parentOid);
1930  if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
1931  LockRelationOid(defaultPartOid, AccessExclusiveLock);
1932  }
1933 
1934  ReleaseSysCache(tuple);
1935 
1936  /*
1937  * Open and lock the relation.
1938  */
1939  rel = relation_open(relid, AccessExclusiveLock);
1940 
1941  /*
1942  * There can no longer be anyone *else* touching the relation, but we
1943  * might still have open queries or cursors, or pending trigger events, in
1944  * our own session.
1945  */
1946  CheckTableNotInUse(rel, "DROP TABLE");
1947 
1948  /*
1949  * This effectively deletes all rows in the table, and may be done in a
1950  * serializable transaction. In that case we must record a rw-conflict in
1951  * to this transaction from each transaction holding a predicate lock on
1952  * the table.
1953  */
1955 
1956  /*
1957  * Delete pg_foreign_table tuple first.
1958  */
1959  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1960  {
1961  Relation rel;
1962  HeapTuple tuple;
1963 
1964  rel = table_open(ForeignTableRelationId, RowExclusiveLock);
1965 
1967  if (!HeapTupleIsValid(tuple))
1968  elog(ERROR, "cache lookup failed for foreign table %u", relid);
1969 
1970  CatalogTupleDelete(rel, &tuple->t_self);
1971 
1972  ReleaseSysCache(tuple);
1974  }
1975 
1976  /*
1977  * If a partitioned table, delete the pg_partitioned_table tuple.
1978  */
1979  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1981 
1982  /*
1983  * If the relation being dropped is the default partition itself,
1984  * invalidate its entry in pg_partitioned_table.
1985  */
1986  if (relid == defaultPartOid)
1988 
1989  /*
1990  * Schedule unlinking of the relation's physical files at commit.
1991  */
1992  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
1993  RelationDropStorage(rel);
1994 
1995  /*
1996  * Close relcache entry, but *keep* AccessExclusiveLock on the relation
1997  * until transaction commit. This ensures no one else will try to do
1998  * something with the doomed relation.
1999  */
2000  relation_close(rel, NoLock);
2001 
2002  /*
2003  * Remove any associated relation synchronization states.
2004  */
2006 
2007  /*
2008  * Forget any ON COMMIT action for the rel
2009  */
2010  remove_on_commit_action(relid);
2011 
2012  /*
2013  * Flush the relation from the relcache. We want to do this before
2014  * starting to remove catalog entries, just to be certain that no relcache
2015  * entry rebuild will happen partway through. (That should not really
2016  * matter, since we don't do CommandCounterIncrement here, but let's be
2017  * safe.)
2018  */
2019  RelationForgetRelation(relid);
2020 
2021  /*
2022  * remove inheritance information
2023  */
2025 
2026  /*
2027  * delete statistics
2028  */
2029  RemoveStatistics(relid, 0);
2030 
2031  /*
2032  * delete attribute tuples
2033  */
2034  DeleteAttributeTuples(relid);
2035 
2036  /*
2037  * delete relation tuple
2038  */
2039  DeleteRelationTuple(relid);
2040 
2041  if (OidIsValid(parentOid))
2042  {
2043  /*
2044  * If this is not the default partition, the partition constraint of
2045  * the default partition has changed to include the portion of the key
2046  * space previously covered by the dropped partition.
2047  */
2048  if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
2049  CacheInvalidateRelcacheByRelid(defaultPartOid);
2050 
2051  /*
2052  * Invalidate the parent's relcache so that the partition is no longer
2053  * included in its partition descriptor.
2054  */
2055  CacheInvalidateRelcacheByRelid(parentOid);
2056  /* keep the lock */
2057  }
2058 }
void DeleteRelationTuple(Oid relid)
Definition: heap.c:1547
void DeleteAttributeTuples(Oid relid)
Definition: heap.c:1576
void RemoveStatistics(Oid relid, AttrNumber attnum)
Definition: heap.c:3228
static void RelationRemoveInheritance(Oid relid)
Definition: heap.c:1514
void RemovePartitionKeyByRelId(Oid relid)
Definition: heap.c:3758
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1421
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
#define AccessExclusiveLock
Definition: lockdefs.h:43
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:338
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:313
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition: partition.c:54
void RemoveSubscriptionRel(Oid subid, Oid relid)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4531
void RelationForgetRelation(Oid rid)
Definition: relcache.c:2798
void RelationDropStorage(Relation rel)
Definition: storage.c:195
@ FOREIGNTABLEREL
Definition: syscache.h:65
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3963
void remove_on_commit_action(Oid relid)
Definition: tablecmds.c:16682

References AccessExclusiveLock, CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), CheckTableForSerializableConflictIn(), CheckTableNotInUse(), DeleteAttributeTuples(), DeleteRelationTuple(), elog, ERROR, FOREIGNTABLEREL, get_default_partition_oid(), get_partition_parent(), GETSTRUCT, HeapTupleIsValid, InvalidOid, LockRelationOid(), NoLock, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationDropStorage(), RelationForgetRelation(), RelationRemoveInheritance(), ReleaseSysCache(), RELOID, 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 3323 of file heap.c.

3324 {
3325  List *relations = NIL;
3326  ListCell *cell;
3327 
3328  /* Open relations for processing, and grab exclusive access on each */
3329  foreach(cell, relids)
3330  {
3331  Oid rid = lfirst_oid(cell);
3332  Relation rel;
3333 
3334  rel = table_open(rid, AccessExclusiveLock);
3335  relations = lappend(relations, rel);
3336  }
3337 
3338  /* Don't allow truncate on tables that are referenced by foreign keys */
3339  heap_truncate_check_FKs(relations, true);
3340 
3341  /* OK to do it */
3342  foreach(cell, relations)
3343  {
3344  Relation rel = lfirst(cell);
3345 
3346  /* Truncate the relation */
3347  heap_truncate_one_rel(rel);
3348 
3349  /* Close the relation, but keep exclusive lock on it until commit */
3350  table_close(rel, NoLock);
3351  }
3352 }
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3408
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3364
#define lfirst_oid(lc)
Definition: pg_list.h:171

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

3409 {
3410  List *oids = NIL;
3411  List *dependents;
3412  ListCell *cell;
3413 
3414  /*
3415  * Build a list of OIDs of the interesting relations.
3416  *
3417  * If a relation has no triggers, then it can neither have FKs nor be
3418  * referenced by a FK from another table, so we can ignore it. For
3419  * partitioned tables, FKs have no triggers, so we must include them
3420  * anyway.
3421  */
3422  foreach(cell, relations)
3423  {
3424  Relation rel = lfirst(cell);
3425 
3426  if (rel->rd_rel->relhastriggers ||
3427  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3428  oids = lappend_oid(oids, RelationGetRelid(rel));
3429  }
3430 
3431  /*
3432  * Fast path: if no relation has triggers, none has FKs either.
3433  */
3434  if (oids == NIL)
3435  return;
3436 
3437  /*
3438  * Otherwise, must scan pg_constraint. We make one pass with all the
3439  * relations considered; if this finds nothing, then all is well.
3440  */
3441  dependents = heap_truncate_find_FKs(oids);
3442  if (dependents == NIL)
3443  return;
3444 
3445  /*
3446  * Otherwise we repeat the scan once per relation to identify a particular
3447  * pair of relations to complain about. This is pretty slow, but
3448  * performance shouldn't matter much in a failure path. The reason for
3449  * doing things this way is to ensure that the message produced is not
3450  * dependent on chance row locations within pg_constraint.
3451  */
3452  foreach(cell, oids)
3453  {
3454  Oid relid = lfirst_oid(cell);
3455  ListCell *cell2;
3456 
3457  dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3458 
3459  foreach(cell2, dependents)
3460  {
3461  Oid relid2 = lfirst_oid(cell2);
3462 
3463  if (!list_member_oid(oids, relid2))
3464  {
3465  char *relname = get_rel_name(relid);
3466  char *relname2 = get_rel_name(relid2);
3467 
3468  if (tempTables)
3469  ereport(ERROR,
3470  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3471  errmsg("unsupported ON COMMIT and foreign key combination"),
3472  errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3473  relname2, relname)));
3474  else
3475  ereport(ERROR,
3476  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3477  errmsg("cannot truncate a table referenced in a foreign key constraint"),
3478  errdetail("Table \"%s\" references \"%s\".",
3479  relname2, relname),
3480  errhint("Truncate table \"%s\" at the same time, "
3481  "or use TRUNCATE ... CASCADE.",
3482  relname2)));
3483  }
3484  }
3485  }
3486 }
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3503
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
#define list_make1_oid(x1)
Definition: pg_list.h:236

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

3504 {
3505  List *result = NIL;
3506  List *oids;
3507  List *parent_cons;
3508  ListCell *cell;
3509  ScanKeyData key;
3510  Relation fkeyRel;
3511  SysScanDesc fkeyScan;
3512  HeapTuple tuple;
3513  bool restart;
3514 
3515  oids = list_copy(relationIds);
3516 
3517  /*
3518  * Must scan pg_constraint. Right now, it is a seqscan because there is
3519  * no available index on confrelid.
3520  */
3521  fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3522 
3523 restart:
3524  restart = false;
3525  parent_cons = NIL;
3526 
3527  fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3528  NULL, 0, NULL);
3529 
3530  while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3531  {
3533 
3534  /* Not a foreign key */
3535  if (con->contype != CONSTRAINT_FOREIGN)
3536  continue;
3537 
3538  /* Not referencing one of our list of tables */
3539  if (!list_member_oid(oids, con->confrelid))
3540  continue;
3541 
3542  /*
3543  * If this constraint has a parent constraint which we have not seen
3544  * yet, keep track of it for the second loop, below. Tracking parent
3545  * constraints allows us to climb up to the top-level constraint
3546  * and look for all possible relations referencing the partitioned
3547  * table.
3548  */
3549  if (OidIsValid(con->conparentid) &&
3550  !list_member_oid(parent_cons, con->conparentid))
3551  parent_cons = lappend_oid(parent_cons, con->conparentid);
3552 
3553  /*
3554  * Add referencer to result, unless present in input list. (Don't
3555  * worry about dupes: we'll fix that below).
3556  */
3557  if (!list_member_oid(relationIds, con->conrelid))
3558  result = lappend_oid(result, con->conrelid);
3559  }
3560 
3561  systable_endscan(fkeyScan);
3562 
3563  /*
3564  * Process each parent constraint we found to add the list of referenced
3565  * relations by them to the oids list. If we do add any new such
3566  * relations, redo the first loop above. Also, if we see that the parent
3567  * constraint in turn has a parent, add that so that we process all
3568  * relations in a single additional pass.
3569  */
3570  foreach(cell, parent_cons)
3571  {
3572  Oid parent = lfirst_oid(cell);
3573 
3574  ScanKeyInit(&key,
3575  Anum_pg_constraint_oid,
3576  BTEqualStrategyNumber, F_OIDEQ,
3577  ObjectIdGetDatum(parent));
3578 
3579  fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3580  true, NULL, 1, &key);
3581 
3582  tuple = systable_getnext(fkeyScan);
3583  if (HeapTupleIsValid(tuple))
3584  {
3586 
3587  /*
3588  * pg_constraint rows always appear for partitioned hierarchies
3589  * this way: on the each side of the constraint, one row appears
3590  * for each partition that points to the top-most table on the
3591  * other side.
3592  *
3593  * Because of this arrangement, we can correctly catch all
3594  * relevant relations by adding to 'parent_cons' all rows with
3595  * valid conparentid, and to the 'oids' list all rows with a zero
3596  * conparentid. If any oids are added to 'oids', redo the first
3597  * loop above by setting 'restart'.
3598  */
3599  if (OidIsValid(con->conparentid))
3600  parent_cons = list_append_unique_oid(parent_cons,
3601  con->conparentid);
3602  else if (!list_member_oid(oids, con->confrelid))
3603  {
3604  oids = lappend_oid(oids, con->confrelid);
3605  restart = true;
3606  }
3607  }
3608 
3609  systable_endscan(fkeyScan);
3610  }
3611 
3612  list_free(parent_cons);
3613  if (restart)
3614  goto restart;
3615 
3616  table_close(fkeyRel, AccessShareLock);
3617  list_free(oids);
3618 
3619  /* Now sort and de-duplicate the result list */
3620  list_sort(result, list_oid_cmp);
3621  list_deduplicate_oid(result);
3622 
3623  return result;
3624 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1612
List * list_copy(const List *oldlist)
Definition: list.c:1532
void list_deduplicate_oid(List *list)
Definition: list.c:1454
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1645
void list_free(List *list)
Definition: list.c:1505
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1339
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 3364 of file heap.c.

3365 {
3366  Oid toastrelid;
3367 
3368  /*
3369  * Truncate the relation. Partitioned tables have no storage, so there is
3370  * nothing to do for them here.
3371  */
3372  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3373  return;
3374 
3375  /* Truncate the underlying relation */
3377 
3378  /* If the relation has indexes, truncate the indexes too */
3380 
3381  /* If there is a toast table, truncate that too */
3382  toastrelid = rel->rd_rel->reltoastrelid;
3383  if (OidIsValid(toastrelid))
3384  {
3385  Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3386 
3388  RelationTruncateIndexes(toastrel);
3389  /* keep the lock... */
3390  table_close(toastrel, NoLock);
3391  }
3392 }
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3275
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1609

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,
Datum attoptions,
CatalogIndexState  indstate 
)

Definition at line 708 of file heap.c.

713 {
714  TupleTableSlot **slot;
715  TupleDesc td;
716  int nslots;
717  int natts = 0;
718  int slotCount = 0;
719  bool close_index = false;
720 
721  td = RelationGetDescr(pg_attribute_rel);
722 
723  /* Initialize the number of slots to use */
724  nslots = Min(tupdesc->natts,
726  slot = palloc(sizeof(TupleTableSlot *) * nslots);
727  for (int i = 0; i < nslots; i++)
729 
730  while (natts < tupdesc->natts)
731  {
732  Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts);
733 
734  ExecClearTuple(slot[slotCount]);
735 
736  memset(slot[slotCount]->tts_isnull, false,
737  slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
738 
739  if (new_rel_oid != InvalidOid)
740  slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid);
741  else
742  slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid);
743 
744  slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname);
745  slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid);
746  slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attrs->attstattarget);
747  slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen);
748  slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum);
749  slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(attrs->attndims);
750  slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
751  slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod);
752  slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval);
753  slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign);
754  slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage);
755  slot[slotCount]->tts_values[Anum_pg_attribute_attcompression - 1] = CharGetDatum(attrs->attcompression);
756  slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull);
757  slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef);
758  slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing);
759  slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity);
760  slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated);
761  slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped);
762  slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal);
763  slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(attrs->attinhcount);
764  slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation);
765  if (attoptions && attoptions[natts] != (Datum) 0)
766  slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attoptions[natts];
767  else
768  slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
769 
770  /* start out with empty permissions and empty options */
771  slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true;
772  slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true;
773  slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true;
774 
775  ExecStoreVirtualTuple(slot[slotCount]);
776  slotCount++;
777 
778  /*
779  * If slots are full or the end of processing has been reached, insert
780  * a batch of tuples.
781  */
782  if (slotCount == nslots || natts == tupdesc->natts - 1)
783  {
784  /* fetch index info only when we know we need it */
785  if (!indstate)
786  {
787  indstate = CatalogOpenIndexes(pg_attribute_rel);
788  close_index = true;
789  }
790 
791  /* insert the new tuples and update the indexes */
792  CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount,
793  indstate);
794  slotCount = 0;
795  }
796 
797  natts++;
798  }
799 
800  if (close_index)
801  CatalogCloseIndexes(indstate);
802  for (int i = 0; i < nslots; i++)
804  pfree(slot);
805 }
#define Min(x, y)
Definition: c.h:986
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:261
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
uintptr_t Datum
Definition: postgres.h:411
#define BoolGetDatum(X)
Definition: postgres.h:446
#define Int32GetDatum(X)
Definition: postgres.h:523
#define NameGetDatum(X)
Definition: postgres.h:639
#define CharGetDatum(X)
Definition: postgres.h:460
bool * tts_isnull
Definition: tuptable.h:128
Datum * tts_values
Definition: tuptable.h:126
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425

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

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

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

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

◆ MergeWithExistingConstraint()

static bool MergeWithExistingConstraint ( Relation  rel,
const char *  ccname,
Node expr,
bool  allow_merge,
bool  is_local,
bool  is_initially_valid,
bool  is_no_inherit 
)
static

Definition at line 2826 of file heap.c.

2830 {
2831  bool found;
2832  Relation conDesc;
2833  SysScanDesc conscan;
2834  ScanKeyData skey[3];
2835  HeapTuple tup;
2836 
2837  /* Search for a pg_constraint entry with same name and relation */
2838  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
2839 
2840  found = false;
2841 
2842  ScanKeyInit(&skey[0],
2843  Anum_pg_constraint_conrelid,
2844  BTEqualStrategyNumber, F_OIDEQ,
2846  ScanKeyInit(&skey[1],
2847  Anum_pg_constraint_contypid,
2848  BTEqualStrategyNumber, F_OIDEQ,
2850  ScanKeyInit(&skey[2],
2851  Anum_pg_constraint_conname,
2852  BTEqualStrategyNumber, F_NAMEEQ,
2853  CStringGetDatum(ccname));
2854 
2855  conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
2856  NULL, 3, skey);
2857 
2858  /* There can be at most one matching row */
2859  if (HeapTupleIsValid(tup = systable_getnext(conscan)))
2860  {
2862 
2863  /* Found it. Conflicts if not identical check constraint */
2864  if (con->contype == CONSTRAINT_CHECK)
2865  {
2866  Datum val;
2867  bool isnull;
2868 
2869  val = fastgetattr(tup,
2870  Anum_pg_constraint_conbin,
2871  conDesc->rd_att, &isnull);
2872  if (isnull)
2873  elog(ERROR, "null conbin for rel %s",
2876  found = true;
2877  }
2878 
2879  /*
2880  * If the existing constraint is purely inherited (no local
2881  * definition) then interpret addition of a local constraint as a
2882  * legal merge. This allows ALTER ADD CONSTRAINT on parent and child
2883  * tables to be given in either order with same end state. However if
2884  * the relation is a partition, all inherited constraints are always
2885  * non-local, including those that were merged.
2886  */
2887  if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
2888  allow_merge = true;
2889 
2890  if (!found || !allow_merge)
2891  ereport(ERROR,
2893  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2894  ccname, RelationGetRelationName(rel))));
2895 
2896  /* If the child constraint is "no inherit" then cannot merge */
2897  if (con->connoinherit)
2898  ereport(ERROR,
2899  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2900  errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
2901  ccname, RelationGetRelationName(rel))));
2902 
2903  /*
2904  * Must not change an existing inherited constraint to "no inherit"
2905  * status. That's because inherited constraints should be able to
2906  * propagate to lower-level children.
2907  */
2908  if (con->coninhcount > 0 && is_no_inherit)
2909  ereport(ERROR,
2910  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2911  errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
2912  ccname, RelationGetRelationName(rel))));
2913 
2914  /*
2915  * If the child constraint is "not valid" then cannot merge with a
2916  * valid parent constraint.
2917  */
2918  if (is_initially_valid && !con->convalidated)
2919  ereport(ERROR,
2920  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2921  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
2922  ccname, RelationGetRelationName(rel))));
2923 
2924  /* OK to update the tuple */
2925  ereport(NOTICE,
2926  (errmsg("merging constraint \"%s\" with inherited definition",
2927  ccname)));
2928 
2929  tup = heap_copytuple(tup);
2930  con = (Form_pg_constraint) GETSTRUCT(tup);
2931 
2932  /*
2933  * In case of partitions, an inherited constraint must be inherited
2934  * only once since it cannot have multiple parents and it is never
2935  * considered local.
2936  */
2937  if (rel->rd_rel->relispartition)
2938  {
2939  con->coninhcount = 1;
2940  con->conislocal = false;
2941  }
2942  else
2943  {
2944  if (is_local)
2945  con->conislocal = true;
2946  else
2947  con->coninhcount++;
2948  }
2949 
2950  if (is_no_inherit)
2951  {
2952  Assert(is_local);
2953  con->connoinherit = true;
2954  }
2955 
2956  CatalogTupleUpdate(conDesc, &tup->t_self, tup);
2957  }
2958 
2959  systable_endscan(conscan);
2960  table_close(conDesc, RowExclusiveLock);
2961 
2962  return found;
2963 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
#define NOTICE
Definition: elog.h:29
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3170
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:706
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
long val
Definition: informix.c:664

References Assert(), BTEqualStrategyNumber, CatalogTupleUpdate(), CStringGetDatum, elog, equal(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fastgetattr, GETSTRUCT, heap_copytuple(), HeapTupleIsValid, InvalidOid, NOTICE, ObjectIdGetDatum, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, and val.

Referenced by AddRelationNewConstraints().

◆ RelationClearMissing()

void RelationClearMissing ( Relation  rel)

Definition at line 2072 of file heap.c.

2073 {
2074  Relation attr_rel;
2075  Oid relid = RelationGetRelid(rel);
2076  int natts = RelationGetNumberOfAttributes(rel);
2077  int attnum;
2078  Datum repl_val[Natts_pg_attribute];
2079  bool repl_null[Natts_pg_attribute];
2080  bool repl_repl[Natts_pg_attribute];
2081  Form_pg_attribute attrtuple;
2082  HeapTuple tuple,
2083  newtuple;
2084 
2085  memset(repl_val, 0, sizeof(repl_val));
2086  memset(repl_null, false, sizeof(repl_null));
2087  memset(repl_repl, false, sizeof(repl_repl));
2088 
2089  repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false);
2090  repl_null[Anum_pg_attribute_attmissingval - 1] = true;
2091 
2092  repl_repl[Anum_pg_attribute_atthasmissing - 1] = true;
2093  repl_repl[Anum_pg_attribute_attmissingval - 1] = true;
2094 
2095 
2096  /* Get a lock on pg_attribute */
2097  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
2098 
2099  /* process each non-system attribute, including any dropped columns */
2100  for (attnum = 1; attnum <= natts; attnum++)
2101  {
2102  tuple = SearchSysCache2(ATTNUM,
2103  ObjectIdGetDatum(relid),
2105  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
2106  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2107  attnum, relid);
2108 
2109  attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
2110 
2111  /* ignore any where atthasmissing is not true */
2112  if (attrtuple->atthasmissing)
2113  {
2114  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
2115  repl_val, repl_null, repl_repl);
2116 
2117  CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
2118 
2119  heap_freetuple(newtuple);
2120  }
2121 
2122  ReleaseSysCache(tuple);
2123  }
2124 
2125  /*
2126  * Our update of the pg_attribute rows will force a relcache rebuild, so
2127  * there's nothing else to do here.
2128  */
2129  table_close(attr_rel, RowExclusiveLock);
2130 }
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:484
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1161
@ ATTNUM
Definition: syscache.h:41

References attnum, 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(), and finish_heap_swap().

◆ RelationRemoveInheritance()

static void RelationRemoveInheritance ( Oid  relid)
static

Definition at line 1514 of file heap.c.

1515 {
1516  Relation catalogRelation;
1517  SysScanDesc scan;
1518  ScanKeyData key;
1519  HeapTuple tuple;
1520 
1521  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
1522 
1523  ScanKeyInit(&key,
1524  Anum_pg_inherits_inhrelid,
1525  BTEqualStrategyNumber, F_OIDEQ,
1526  ObjectIdGetDatum(relid));
1527 
1528  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1529  NULL, 1, &key);
1530 
1531  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1532  CatalogTupleDelete(catalogRelation, &tuple->t_self);
1533 
1534  systable_endscan(scan);
1535  table_close(catalogRelation, RowExclusiveLock);
1536 }

References BTEqualStrategyNumber, CatalogTupleDelete(), HeapTupleIsValid, 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().

◆ RelationTruncateIndexes()

static void RelationTruncateIndexes ( Relation  heapRelation)
static

Definition at line 3275 of file heap.c.

3276 {
3277  ListCell *indlist;
3278 
3279  /* Ask the relcache to produce a list of the indexes of the rel */
3280  foreach(indlist, RelationGetIndexList(heapRelation))
3281  {
3282  Oid indexId = lfirst_oid(indlist);
3283  Relation currentIndex;
3284  IndexInfo *indexInfo;
3285 
3286  /* Open the index relation; use exclusive lock, just to be sure */
3287  currentIndex = index_open(indexId, AccessExclusiveLock);
3288 
3289  /*
3290  * Fetch info needed for index_build. Since we know there are no
3291  * tuples that actually need indexing, we can use a dummy IndexInfo.
3292  * This is slightly cheaper to build, but the real point is to avoid
3293  * possibly running user-defined code in index expressions or
3294  * predicates. We might be getting invoked during ON COMMIT
3295  * processing, and we don't want to run any such code then.
3296  */
3297  indexInfo = BuildDummyIndexInfo(currentIndex);
3298 
3299  /*
3300  * Now truncate the actual file (and discard buffers).
3301  */
3302  RelationTruncate(currentIndex, 0);
3303 
3304  /* Initialize the index and rebuild */
3305  /* Note: we do not need to re-establish pkey setting */
3306  index_build(heapRelation, currentIndex, indexInfo, true, false);
3307 
3308  /* We're done with this index */
3309  index_close(currentIndex, NoLock);
3310  }
3311 }
IndexInfo * BuildDummyIndexInfo(Relation index)
Definition: index.c:2468
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:2929
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4649
void RelationTruncate(Relation rel, BlockNumber nblocks)
Definition: storage.c:277

References AccessExclusiveLock, BuildDummyIndexInfo(), index_build(), index_close(), index_open(), lfirst_oid, NoLock, RelationGetIndexList(), and RelationTruncate().

Referenced by heap_truncate_one_rel().

◆ RemoveAttrDefault()

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

Definition at line 1767 of file heap.c.

1769 {
1770  Relation attrdef_rel;
1771  ScanKeyData scankeys[2];
1772  SysScanDesc scan;
1773  HeapTuple tuple;
1774  bool found = false;
1775 
1776  attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
1777 
1778  ScanKeyInit(&scankeys[0],
1779  Anum_pg_attrdef_adrelid,
1780  BTEqualStrategyNumber, F_OIDEQ,
1781  ObjectIdGetDatum(relid));
1782  ScanKeyInit(&scankeys[1],
1783  Anum_pg_attrdef_adnum,
1784  BTEqualStrategyNumber, F_INT2EQ,
1786 
1787  scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
1788  NULL, 2, scankeys);
1789 
1790  /* There should be at most one matching tuple, but we loop anyway */
1791  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1792  {
1793  ObjectAddress object;
1794  Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
1795 
1796  object.classId = AttrDefaultRelationId;
1797  object.objectId = attrtuple->oid;
1798  object.objectSubId = 0;
1799 
1800  performDeletion(&object, behavior,
1801  internal ? PERFORM_DELETION_INTERNAL : 0);
1802 
1803  found = true;
1804  }
1805 
1806  systable_endscan(scan);
1807  table_close(attrdef_rel, RowExclusiveLock);
1808 
1809  if (complain && !found)
1810  elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
1811  relid, attnum);
1812 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:315
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:134
FormData_pg_attrdef * Form_pg_attrdef
Definition: pg_attrdef.h:48

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

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

◆ RemoveAttrDefaultById()

void RemoveAttrDefaultById ( Oid  attrdefId)

Definition at line 1822 of file heap.c.

1823 {
1824  Relation attrdef_rel;
1825  Relation attr_rel;
1826  Relation myrel;
1827  ScanKeyData scankeys[1];
1828  SysScanDesc scan;
1829  HeapTuple tuple;
1830  Oid myrelid;
1831  AttrNumber myattnum;
1832 
1833  /* Grab an appropriate lock on the pg_attrdef relation */
1834  attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);
1835 
1836  /* Find the pg_attrdef tuple */
1837  ScanKeyInit(&scankeys[0],
1838  Anum_pg_attrdef_oid,
1839  BTEqualStrategyNumber, F_OIDEQ,
1840  ObjectIdGetDatum(attrdefId));
1841 
1842  scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
1843  NULL, 1, scankeys);
1844 
1845  tuple = systable_getnext(scan);
1846  if (!HeapTupleIsValid(tuple))
1847  elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
1848 
1849  myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
1850  myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
1851 
1852  /* Get an exclusive lock on the relation owning the attribute */
1853  myrel = relation_open(myrelid, AccessExclusiveLock);
1854 
1855  /* Now we can delete the pg_attrdef row */
1856  CatalogTupleDelete(attrdef_rel, &tuple->t_self);
1857 
1858  systable_endscan(scan);
1859  table_close(attrdef_rel, RowExclusiveLock);
1860 
1861  /* Fix the pg_attribute row */
1862  attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
1863 
1864  tuple = SearchSysCacheCopy2(ATTNUM,
1865  ObjectIdGetDatum(myrelid),
1866  Int16GetDatum(myattnum));
1867  if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1868  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1869  myattnum, myrelid);
1870 
1871  ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
1872 
1873  CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
1874 
1875  /*
1876  * Our update of the pg_attribute row will force a relcache rebuild, so
1877  * there's nothing else to do here.
1878  */
1879  table_close(attr_rel, RowExclusiveLock);
1880 
1881  /* Keep lock on attribute's rel until end of xact */
1882  relation_close(myrel, NoLock);
1883 }
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:179

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

Referenced by doDeletion().

◆ RemoveAttributeById()

void RemoveAttributeById ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 1654 of file heap.c.

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

References AccessExclusiveLock, attnum, ATTNUM, BoolGetDatum, CatalogTupleDelete(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum, InvalidOid, MemSet, 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 3758 of file heap.c.

3759 {
3760  Relation rel;
3761  HeapTuple tuple;
3762 
3763  rel = table_open(PartitionedRelationId, RowExclusiveLock);
3764 
3765  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3766  if (!HeapTupleIsValid(tuple))
3767  elog(ERROR, "cache lookup failed for partition key of relation %u",
3768  relid);
3769 
3770  CatalogTupleDelete(rel, &tuple->t_self);
3771 
3772  ReleaseSysCache(tuple);
3774 }
@ PARTRELID
Definition: syscache.h:75

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, PARTRELID, 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 3228 of file heap.c.

3229 {
3230  Relation pgstatistic;
3231  SysScanDesc scan;
3232  ScanKeyData key[2];
3233  int nkeys;
3234  HeapTuple tuple;
3235 
3236  pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3237 
3238  ScanKeyInit(&key[0],
3239  Anum_pg_statistic_starelid,
3240  BTEqualStrategyNumber, F_OIDEQ,
3241  ObjectIdGetDatum(relid));
3242 
3243  if (attnum == 0)
3244  nkeys = 1;
3245  else
3246  {
3247  ScanKeyInit(&key[1],
3248  Anum_pg_statistic_staattnum,
3249  BTEqualStrategyNumber, F_INT2EQ,
3251  nkeys = 2;
3252  }
3253 
3254  scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3255  NULL, nkeys, key);
3256 
3257  /* we must loop even when attnum != 0, in case of inherited stats */
3258  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3259  CatalogTupleDelete(pgstatistic, &tuple->t_self);
3260 
3261  systable_endscan(scan);
3262 
3263  table_close(pgstatistic, RowExclusiveLock);
3264 }

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(), heap_drop_with_catalog(), index_drop(), and RemoveAttributeById().

◆ SetAttrMissing()

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

Definition at line 2140 of file heap.c.

2141 {
2142  Datum valuesAtt[Natts_pg_attribute];
2143  bool nullsAtt[Natts_pg_attribute];
2144  bool replacesAtt[Natts_pg_attribute];
2145  Datum missingval;
2146  Form_pg_attribute attStruct;
2147  Relation attrrel,
2148  tablerel;
2149  HeapTuple atttup,
2150  newtup;
2151 
2152  /* lock the table the attribute belongs to */
2153  tablerel = table_open(relid, AccessExclusiveLock);
2154 
2155  /* Don't do anything unless it's a plain table */
2156  if (tablerel->rd_rel->relkind != RELKIND_RELATION)
2157  {
2158  table_close(tablerel, AccessExclusiveLock);
2159  return;
2160  }
2161 
2162  /* Lock the attribute row and get the data */
2163  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2164  atttup = SearchSysCacheAttName(relid, attname);
2165  if (!HeapTupleIsValid(atttup))
2166  elog(ERROR, "cache lookup failed for attribute %s of relation %u",
2167  attname, relid);
2168  attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2169 
2170  /* get an array value from the value string */
2171  missingval = OidFunctionCall3(F_ARRAY_IN,
2173  ObjectIdGetDatum(attStruct->atttypid),
2174  Int32GetDatum(attStruct->atttypmod));
2175 
2176  /* update the tuple - set atthasmissing and attmissingval */
2177  MemSet(valuesAtt, 0, sizeof(valuesAtt));
2178  MemSet(nullsAtt, false, sizeof(nullsAtt));
2179  MemSet(replacesAtt, false, sizeof(replacesAtt));
2180 
2181  valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
2182  replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2183  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2184  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2185 
2186  newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2187  valuesAtt, nullsAtt, replacesAtt);
2188  CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
2189 
2190  /* clean up */
2191  ReleaseSysCache(atttup);
2192  table_close(attrrel, RowExclusiveLock);
2193  table_close(tablerel, AccessExclusiveLock);
2194 }
#define OidFunctionCall3(functionId, arg1, arg2, arg3)
Definition: fmgr.h:673
static struct @142 value
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1291

References AccessExclusiveLock, attname, BoolGetDatum, CatalogTupleUpdate(), CStringGetDatum, elog, ERROR, GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, Int32GetDatum, MemSet, 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().

◆ SetRelationNumChecks()

static void SetRelationNumChecks ( Relation  rel,
int  numchecks 
)
static

Definition at line 2976 of file heap.c.

2977 {
2978  Relation relrel;
2979  HeapTuple reltup;
2980  Form_pg_class relStruct;
2981 
2982  relrel = table_open(RelationRelationId, RowExclusiveLock);
2983  reltup = SearchSysCacheCopy1(RELOID,
2985  if (!HeapTupleIsValid(reltup))
2986  elog(ERROR, "cache lookup failed for relation %u",
2987  RelationGetRelid(rel));
2988  relStruct = (Form_pg_class) GETSTRUCT(reltup);
2989 
2990  if (relStruct->relchecks != numchecks)
2991  {
2992  relStruct->relchecks = numchecks;
2993 
2994  CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
2995  }
2996  else
2997  {
2998  /* Skip the disk update, but force relcache inval anyway */
3000  }
3001 
3002  heap_freetuple(reltup);
3003  table_close(relrel, RowExclusiveLock);
3004 }
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1362
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:177

References CacheInvalidateRelcache(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum, RelationGetRelid, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AddRelationNewConstraints(), and StoreConstraints().

◆ StoreAttrDefault()

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

Definition at line 2208 of file heap.c.

2210 {
2211  char *adbin;
2212  Relation adrel;
2213  HeapTuple tuple;
2214  Datum values[4];
2215  static bool nulls[4] = {false, false, false, false};
2216  Relation attrrel;
2217  HeapTuple atttup;
2218  Form_pg_attribute attStruct;
2219  char attgenerated;
2220  Oid attrdefOid;
2221  ObjectAddress colobject,
2222  defobject;
2223 
2224  adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
2225 
2226  /*
2227  * Flatten expression to string form for storage.
2228  */
2229  adbin = nodeToString(expr);
2230 
2231  /*
2232  * Make the pg_attrdef entry.
2233  */
2234  attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
2235  Anum_pg_attrdef_oid);
2236  values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
2237  values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
2238  values[Anum_pg_attrdef_adnum - 1] = attnum;
2239  values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
2240 
2241  tuple = heap_form_tuple(adrel->rd_att, values, nulls);
2242  CatalogTupleInsert(adrel, tuple);
2243 
2244  defobject.classId = AttrDefaultRelationId;
2245  defobject.objectId = attrdefOid;
2246  defobject.objectSubId = 0;
2247 
2248  table_close(adrel, RowExclusiveLock);
2249 
2250  /* now can free some of the stuff allocated above */
2251  pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
2252  heap_freetuple(tuple);
2253  pfree(adbin);
2254 
2255  /*
2256  * Update the pg_attribute entry for the column to show that a default
2257  * exists.
2258  */
2259  attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2260  atttup = SearchSysCacheCopy2(ATTNUM,
2263  if (!HeapTupleIsValid(atttup))
2264  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2265  attnum, RelationGetRelid(rel));
2266  attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2267  attgenerated = attStruct->attgenerated;
2268  if (!attStruct->atthasdef)
2269  {
2270  Form_pg_attribute defAttStruct;
2271 
2272  ExprState *exprState;
2273  Expr *expr2 = (Expr *) expr;
2274  EState *estate = NULL;
2275  ExprContext *econtext;
2276  Datum valuesAtt[Natts_pg_attribute];
2277  bool nullsAtt[Natts_pg_attribute];
2278  bool replacesAtt[Natts_pg_attribute];
2279  Datum missingval = (Datum) 0;
2280  bool missingIsNull = true;
2281 
2282  MemSet(valuesAtt, 0, sizeof(valuesAtt));
2283  MemSet(nullsAtt, false, sizeof(nullsAtt));
2284  MemSet(replacesAtt, false, sizeof(replacesAtt));
2285  valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
2286  replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
2287 
2288  if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
2289  !attgenerated)
2290  {
2291  expr2 = expression_planner(expr2);
2292  estate = CreateExecutorState();
2293  exprState = ExecPrepareExpr(expr2, estate);
2294  econtext = GetPerTupleExprContext(estate);
2295 
2296  missingval = ExecEvalExpr(exprState, econtext,
2297  &missingIsNull);
2298 
2299  FreeExecutorState(estate);
2300 
2301  defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
2302 
2303  if (missingIsNull)
2304  {
2305  /* if the default evaluates to NULL, just store a NULL array */
2306  missingval = (Datum) 0;
2307  }
2308  else
2309  {
2310  /* otherwise make a one-element array of the value */
2311  missingval = PointerGetDatum(construct_array(&missingval,
2312  1,
2313  defAttStruct->atttypid,
2314  defAttStruct->attlen,
2315  defAttStruct->attbyval,
2316  defAttStruct->attalign));
2317  }
2318 
2319  valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
2320  replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2321  valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2322  replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2323  nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
2324  }
2325  atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2326  valuesAtt, nullsAtt, replacesAtt);
2327 
2328  CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
2329 
2330  if (!missingIsNull)
2331  pfree(DatumGetPointer(missingval));
2332 
2333  }
2334  table_close(attrrel, RowExclusiveLock);
2335  heap_freetuple(atttup);
2336 
2337  /*
2338  * Make a dependency so that the pg_attrdef entry goes away if the column
2339  * (or whole table) is deleted.
2340  */
2341  colobject.classId = RelationRelationId;
2342  colobject.objectId = RelationGetRelid(rel);
2343  colobject.objectSubId = attnum;
2344 
2345  recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
2346 
2347  /*
2348  * Record dependencies on objects used in the expression, too.
2349  */
2350  if (attgenerated)
2351  {
2352  /*
2353  * Generated column: Dropping anything that the generation expression
2354  * refers to automatically drops the generated column.
2355  */
2356  recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
2358  DEPENDENCY_AUTO, false);
2359  }
2360  else
2361  {
2362  /*
2363  * Normal default: Dropping anything that the default refers to
2364  * requires CASCADE and drops the default only.
2365  */
2366  recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
2368  DEPENDENCY_NORMAL, false);
2369  }
2370 
2371  /*
2372  * Post creation hook for attribute defaults.
2373  *
2374  * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
2375  * couple of deletion/creation of the attribute's default entry, so the
2376  * callee should check existence of an older version of this entry if it
2377  * needs to distinguish.
2378  */
2379  InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
2380  RelationGetRelid(rel), attnum, is_internal);
2381 
2382  return attrdefOid;
2383 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
#define CStringGetTextDatum(s)
Definition: builtins.h:85
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:381
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1629
@ DEPENDENCY_AUTO
Definition: dependency.h:34
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
EState * CreateExecutorState(void)
Definition: execUtils.c:90
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
char * nodeToString(const void *obj)
Definition: outfuncs.c:4558
Expr * expression_planner(Expr *expr)
Definition: planner.c:5807
#define DatumGetPointer(X)
Definition: postgres.h:593

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

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

◆ StoreConstraints()

static void StoreConstraints ( Relation  rel,
List cooked_constraints,
bool  is_internal 
)
static

Definition at line 2504 of file heap.c.

2505 {
2506  int numchecks = 0;
2507  ListCell *lc;
2508 
2509  if (cooked_constraints == NIL)
2510  return; /* nothing to do */
2511 
2512  /*
2513  * Deparsing of constraint expressions will fail unless the just-created
2514  * pg_attribute tuples for this relation are made visible. So, bump the
2515  * command counter. CAUTION: this will cause a relcache entry rebuild.
2516  */
2518 
2519  foreach(lc, cooked_constraints)
2520  {
2521  CookedConstraint *con = (CookedConstraint *) lfirst(lc);
2522 
2523  switch (con->contype)
2524  {
2525  case CONSTR_DEFAULT:
2526  con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
2527  is_internal, false);
2528  break;
2529  case CONSTR_CHECK:
2530  con->conoid =
2531  StoreRelCheck(rel, con->name, con->expr,
2532  !con->skip_validation, con->is_local,
2533  con->inhcount, con->is_no_inherit,
2534  is_internal);
2535  numchecks++;
2536  break;
2537  default:
2538  elog(ERROR, "unrecognized constraint type: %d",
2539  (int) con->contype);
2540  }
2541  }
2542 
2543  if (numchecks > 0)
2544  SetRelationNumChecks(rel, numchecks);
2545 }
void CommandCounterIncrement(void)
Definition: xact.c:1073

References CookedConstraint::attnum, CommandCounterIncrement(), CookedConstraint::conoid, CONSTR_CHECK, CONSTR_DEFAULT, CookedConstraint::contype, elog, ERROR, CookedConstraint::expr, CookedConstraint::inhcount, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lfirst, CookedConstraint::name, NIL, SetRelationNumChecks(), CookedConstraint::skip_validation, StoreAttrDefault(), and StoreRelCheck().

Referenced by heap_create_with_catalog().

◆ StorePartitionBound()

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

Definition at line 3789 of file heap.c.

3790 {
3791  Relation classRel;
3792  HeapTuple tuple,
3793  newtuple;
3794  Datum new_val[Natts_pg_class];
3795  bool new_null[Natts_pg_class],
3796  new_repl[Natts_pg_class];
3797  Oid defaultPartOid;
3798 
3799  /* Update pg_class tuple */
3800  classRel = table_open(RelationRelationId, RowExclusiveLock);
3801  tuple = SearchSysCacheCopy1(RELOID,
3803  if (!HeapTupleIsValid(tuple))
3804  elog(ERROR, "cache lookup failed for relation %u",
3805  RelationGetRelid(rel));
3806 
3807 #ifdef USE_ASSERT_CHECKING
3808  {
3809  Form_pg_class classForm;
3810  bool isnull;
3811 
3812  classForm = (Form_pg_class) GETSTRUCT(tuple);
3813  Assert(!classForm->relispartition);
3814  (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
3815  &isnull);
3816  Assert(isnull);
3817  }
3818 #endif
3819 
3820  /* Fill in relpartbound value */
3821  memset(new_val, 0, sizeof(new_val));
3822  memset(new_null, false, sizeof(new_null));
3823  memset(new_repl, false, sizeof(new_repl));
3824  new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
3825  new_null[Anum_pg_class_relpartbound - 1] = false;
3826  new_repl[Anum_pg_class_relpartbound - 1] = true;
3827  newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
3828  new_val, new_null, new_repl);
3829  /* Also set the flag */
3830  ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
3831  CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
3832  heap_freetuple(newtuple);
3833  table_close(classRel, RowExclusiveLock);
3834 
3835  /*
3836  * If we're storing bounds for the default partition, update
3837  * pg_partitioned_table too.
3838  */
3839  if (bound->is_default)
3841  RelationGetRelid(rel));
3842 
3843  /* Make these updates visible */
3845 
3846  /*
3847  * The partition constraint for the default partition depends on the
3848  * partition bounds of every other partition, so we must invalidate the
3849  * relcache entry for that partition every time a partition is added or
3850  * removed.
3851  */
3852  defaultPartOid =
3854  if (OidIsValid(defaultPartOid))
3855  CacheInvalidateRelcacheByRelid(defaultPartOid);
3856 
3857  CacheInvalidateRelcache(parent);
3858 }
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:455
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1411

References Assert(), CacheInvalidateRelcache(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CommandCounterIncrement(), CStringGetTextDatum, elog, ERROR, get_default_oid_from_partdesc(), GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, PartitionBoundSpec::is_default, nodeToString(), ObjectIdGetDatum, OidIsValid, RelationGetDescr, RelationGetPartitionDesc(), RelationGetRelid, RELOID, 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 3631 of file heap.c.

3638 {
3639  int i;
3640  int2vector *partattrs_vec;
3641  oidvector *partopclass_vec;
3642  oidvector *partcollation_vec;
3643  Datum partexprDatum;
3644  Relation pg_partitioned_table;
3645  HeapTuple tuple;
3646  Datum values[Natts_pg_partitioned_table];
3647  bool nulls[Natts_pg_partitioned_table];
3648  ObjectAddress myself;
3649  ObjectAddress referenced;
3650  ObjectAddresses *addrs;
3651 
3652  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3653 
3654  /* Copy the partition attribute numbers, opclass OIDs into arrays */
3655  partattrs_vec = buildint2vector(partattrs, partnatts);
3656  partopclass_vec = buildoidvector(partopclass, partnatts);
3657  partcollation_vec = buildoidvector(partcollation, partnatts);
3658 
3659  /* Convert the expressions (if any) to a text datum */
3660  if (partexprs)
3661  {
3662  char *exprString;
3663 
3664  exprString = nodeToString(partexprs);
3665  partexprDatum = CStringGetTextDatum(exprString);
3666  pfree(exprString);
3667  }
3668  else
3669  partexprDatum = (Datum) 0;
3670 
3671  pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3672 
3673  MemSet(nulls, false, sizeof(nulls));
3674 
3675  /* Only this can ever be NULL */
3676  if (!partexprDatum)
3677  nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3678 
3679  values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3680  values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3681  values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3682  values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3683  values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3684  values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3685  values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3686  values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3687 
3688  tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3689 
3690  CatalogTupleInsert(pg_partitioned_table, tuple);
3691  table_close(pg_partitioned_table, RowExclusiveLock);
3692 
3693  /* Mark this relation as dependent on a few things as follows */
3694  addrs = new_object_addresses();
3695  ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3696 
3697  /* Operator class and collation per key column */
3698  for (i = 0; i < partnatts; i++)
3699  {
3700  ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3701  add_exact_object_address(&referenced, addrs);
3702 
3703  /* The default collation is pinned, so don't bother recording it */
3704  if (OidIsValid(partcollation[i]) &&
3705  partcollation[i] != DEFAULT_COLLATION_OID)
3706  {
3707  ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3708  add_exact_object_address(&referenced, addrs);
3709  }
3710  }
3711 
3713  free_object_addresses(addrs);
3714 
3715  /*
3716  * The partitioning columns are made internally dependent on the table,
3717  * because we cannot drop any of them without dropping the whole table.
3718  * (ATExecDropColumn independently enforces that, but it's not bulletproof
3719  * so we need the dependencies too.)
3720  */
3721  for (i = 0; i < partnatts; i++)
3722  {
3723  if (partattrs[i] == 0)
3724  continue; /* ignore expressions here */
3725 
3726  ObjectAddressSubSet(referenced, RelationRelationId,
3727  RelationGetRelid(rel), partattrs[i]);
3728  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3729  }
3730 
3731  /*
3732  * Also consider anything mentioned in partition expressions. External
3733  * references (e.g. functions) get NORMAL dependencies. Table columns
3734  * mentioned in the expressions are handled the same as plain partitioning
3735  * columns, i.e. they become internally dependent on the whole table.
3736  */
3737  if (partexprs)
3739  (Node *) partexprs,
3740  RelationGetRelid(rel),
3743  true /* reverse the self-deps */ );
3744 
3745  /*
3746  * We must invalidate the relcache so that the next
3747  * CommandCounterIncrement() will cause the same to be rebuilt using the
3748  * information in just created catalog entry.
3749  */
3751 }
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:167
Definition: c.h:650
Definition: c.h:661

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, MemSet, 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().

◆ StoreRelCheck()

static Oid StoreRelCheck ( Relation  rel,
const char *  ccname,
Node expr,
bool  is_validated,
bool  is_local,
int  inhcount,
bool  is_no_inherit,
bool  is_internal 
)
static

Definition at line 2394 of file heap.c.

2397 {
2398  char *ccbin;
2399  List *varList;
2400  int keycount;
2401  int16 *attNos;
2402  Oid constrOid;
2403 
2404  /*
2405  * Flatten expression to string form for storage.
2406  */
2407  ccbin = nodeToString(expr);
2408 
2409  /*
2410  * Find columns of rel that are used in expr
2411  *
2412  * NB: pull_var_clause is okay here only because we don't allow subselects
2413  * in check constraints; it would fail to examine the contents of
2414  * subselects.
2415  */
2416  varList = pull_var_clause(expr, 0);
2417  keycount = list_length(varList);
2418 
2419  if (keycount > 0)
2420  {
2421  ListCell *vl;
2422  int i = 0;
2423 
2424  attNos = (int16 *) palloc(keycount * sizeof(int16));
2425  foreach(vl, varList)
2426  {
2427  Var *var = (Var *) lfirst(vl);
2428  int j;
2429 
2430  for (j = 0; j < i; j++)
2431  if (attNos[j] == var->varattno)
2432  break;
2433  if (j == i)
2434  attNos[i++] = var->varattno;
2435  }
2436  keycount = i;
2437  }
2438  else
2439  attNos = NULL;
2440 
2441  /*
2442  * Partitioned tables do not contain any rows themselves, so a NO INHERIT
2443  * constraint makes no sense.
2444  */
2445  if (is_no_inherit &&
2446  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2447  ereport(ERROR,
2448  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2449  errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
2450  RelationGetRelationName(rel))));
2451 
2452  /*
2453  * Create the Check Constraint
2454  */
2455  constrOid =
2456  CreateConstraintEntry(ccname, /* Constraint Name */
2457  RelationGetNamespace(rel), /* namespace */
2458  CONSTRAINT_CHECK, /* Constraint Type */
2459  false, /* Is Deferrable */
2460  false, /* Is Deferred */
2461  is_validated,
2462  InvalidOid, /* no parent constraint */
2463  RelationGetRelid(rel), /* relation */
2464  attNos, /* attrs in the constraint */
2465  keycount, /* # key attrs in the constraint */
2466  keycount, /* # total attrs in the constraint */
2467  InvalidOid, /* not a domain constraint */
2468  InvalidOid, /* no associated index */
2469  InvalidOid, /* Foreign key fields */
2470  NULL,
2471  NULL,
2472  NULL,
2473  NULL,
2474  0,
2475  ' ',
2476  ' ',
2477  NULL,
2478  0,
2479  ' ',
2480  NULL, /* not an exclusion constraint */
2481  expr, /* Tree form of check constraint */
2482  ccbin, /* Binary form of check constraint */
2483  is_local, /* conislocal */
2484  inhcount, /* coninhcount */
2485  is_no_inherit, /* connoinherit */
2486  is_internal); /* internally constructed? */
2487 
2488  pfree(ccbin);
2489 
2490  return constrOid;
2491 }
signed short int16
Definition: c.h:428
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50

References CreateConstraintEntry(), ereport, errcode(), errmsg(), ERROR, i, InvalidOid, j, lfirst, list_length(), nodeToString(), palloc(), pfree(), pull_var_clause(), RelationData::rd_rel, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, and Var::varattno.

Referenced by AddRelationNewConstraints(), and StoreConstraints().

◆ SystemAttributeByName()

const FormData_pg_attribute* SystemAttributeByName ( const char *  attname)

Definition at line 265 of file heap.c.

266 {
267  int j;
268 
269  for (j = 0; j < (int) lengthof(SysAtt); j++)
270  {
271  const FormData_pg_attribute *att = SysAtt[j];
272 
273  if (strcmp(NameStr(att->attname), attname) == 0)
274  return att;
275  }
276 
277  return NULL;
278 }

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

254 {
255  if (attno >= 0 || attno < -(int) lengthof(SysAtt))
256  elog(ERROR, "invalid system attribute number %d", attno);
257  return SysAtt[-attno - 1];
258 }

References elog, ERROR, lengthof, and SysAtt.

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

Variable Documentation

◆ a1

const FormData_pg_attribute a1
static
Initial value:
= {
.attname = {"ctid"},
.atttypid = TIDOID,
.attlen = sizeof(ItemPointerData),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = false,
.attalign = TYPALIGN_SHORT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
struct ItemPointerData ItemPointerData
char attstorage
Definition: pg_attribute.h:126
bool attbyval
Definition: pg_attribute.h:112
char attalign
Definition: pg_attribute.h:118
bool attnotnull
Definition: pg_attribute.h:139
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

Definition at line 155 of file heap.c.

Referenced by aclitem_eq(), aclitem_match(), aclitemComparator(), brin_minmax_multi_distance_float4(), brin_minmax_multi_distance_float8(), brin_minmax_multi_distance_int2(), brin_minmax_multi_distance_int4(), brin_minmax_multi_distance_int8(), brin_minmax_multi_distance_numeric(), brin_minmax_multi_distance_uuid(), build_distances(), cmpaffix(), deccall2(), deccall3(), distance_1D(), entryIndexByFrequencyCmp(), evalLazyFunc(), float8_qsort_cmp(), inet_merge(), inet_same_family(), int4gcd_internal(), int8gcd_internal(), macaddr8_cmp(), macaddr8_cmp_internal(), macaddr8_eq(), macaddr8_ge(), macaddr8_gt(), macaddr8_le(), macaddr8_lt(), macaddr8_ne(), macaddr_cmp(), macaddr_cmp_internal(), macaddr_eq(), macaddr_ge(), macaddr_gt(), macaddr_le(), macaddr_lt(), macaddr_ne(), MergeAffix(), network_cmp(), network_cmp_internal(), network_eq(), network_ge(), network_gt(), network_larger(), network_le(), network_lt(), network_ne(), network_overlap(), network_smaller(), network_sub(), network_subeq(), network_sup(), network_supeq(), packArcInfoCmp(), range_bound_qsort_cmp(), and sqrt_var().

◆ a2

const FormData_pg_attribute a2
static
Initial value:
= {
.attname = {"xmin"},
.atttypid = XIDOID,
.attlen = sizeof(TransactionId),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:22

Definition at line 169 of file heap.c.

Referenced by aclitem_eq(), aclitem_match(), aclitemComparator(), brin_minmax_multi_distance_float4(), brin_minmax_multi_distance_float8(), brin_minmax_multi_distance_int2(), brin_minmax_multi_distance_int4(), brin_minmax_multi_distance_int8(), brin_minmax_multi_distance_numeric(), brin_minmax_multi_distance_uuid(), build_distances(), clonesuccessorstates(), cmpaffix(), deccall2(), deccall3(), distance_1D(), entryIndexByFrequencyCmp(), evalLazyFunc(), float8_qsort_cmp(), inet_merge(), inet_same_family(), int4gcd_internal(), int8gcd_internal(), macaddr8_cmp(), macaddr8_cmp_internal(), macaddr8_eq(), macaddr8_ge(), macaddr8_gt(), macaddr8_le(), macaddr8_lt(), macaddr8_ne(), macaddr_cmp(), macaddr_cmp_internal(), macaddr_eq(), macaddr_ge(), macaddr_gt(), macaddr_le(), macaddr_lt(), macaddr_ne(), MergeAffix(), network_cmp(), network_cmp_internal(), network_eq(), network_ge(), network_gt(), network_larger(), network_le(), network_lt(), network_ne(), network_overlap(), network_smaller(), network_sub(), network_subeq(), network_sup(), network_supeq(), packArcInfoCmp(), and range_bound_qsort_cmp().

◆ a3

const FormData_pg_attribute a3
static
Initial value:
= {
.attname = {"cmin"},
.atttypid = CIDOID,
.attlen = sizeof(CommandId),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
uint32 CommandId
Definition: c.h:601
#define MinCommandIdAttributeNumber
Definition: sysattr.h:23

Definition at line 183 of file heap.c.

◆ a4

const FormData_pg_attribute a4
static
Initial value:
= {
.attname = {"xmax"},
.atttypid = XIDOID,
.attlen = sizeof(TransactionId),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
#define MaxTransactionIdAttributeNumber
Definition: sysattr.h:24

Definition at line 197 of file heap.c.

◆ a5

const FormData_pg_attribute a5
static
Initial value:
= {
.attname = {"cmax"},
.atttypid = CIDOID,
.attlen = sizeof(CommandId),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
#define MaxCommandIdAttributeNumber
Definition: sysattr.h:25

Definition at line 211 of file heap.c.

◆ a6

const FormData_pg_attribute a6
static
Initial value:
= {
.attname = {"tableoid"},
.atttypid = OIDOID,
.attlen = sizeof(Oid),
.attcacheoff = -1,
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
#define TableOidAttributeNumber
Definition: sysattr.h:26

Definition at line 231 of file heap.c.

◆ binary_upgrade_next_heap_pg_class_oid

Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid

Definition at line 93 of file heap.c.

Referenced by binary_upgrade_set_next_heap_pg_class_oid(), and heap_create_with_catalog().

◆ binary_upgrade_next_heap_pg_class_relfilenode

Oid binary_upgrade_next_heap_pg_class_relfilenode = InvalidOid

Definition at line 94 of file heap.c.

Referenced by binary_upgrade_set_next_heap_relfilenode(), and heap_create_with_catalog().

◆ binary_upgrade_next_toast_pg_class_oid

Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid

◆ binary_upgrade_next_toast_pg_class_relfilenode

Oid binary_upgrade_next_toast_pg_class_relfilenode = InvalidOid

Definition at line 96 of file heap.c.

Referenced by binary_upgrade_set_next_toast_relfilenode(), and heap_create_with_catalog().

◆ SysAtt

const FormData_pg_attribute* SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6}
static

Definition at line 245 of file heap.c.

Referenced by AddNewAttributeTuples(), SystemAttributeByName(), and SystemAttributeDefinition().