PostgreSQL Source Code  git master
heap.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/multixact.h"
#include "access/relation.h"
#include "access/table.h"
#include "access/tableam.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.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 "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "common/int.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 "pgstat.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.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, RelFileNumber relfilenumber, Oid accessmtd, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, bool create_storage)
 
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, const 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 heap_drop_with_catalog (Oid relid)
 
void RelationClearMissing (Relation rel)
 
void SetAttrMissing (Oid relid, char *attname, char *value)
 
static Oid StoreRelNotNull (Relation rel, const char *nnname, AttrNumber attnum, bool is_validated, bool is_local, int inhcount, bool is_no_inherit)
 
ListAddRelationNewConstraints (Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
 
static int list_cookedconstr_attnum_cmp (const ListCell *p1, const ListCell *p2)
 
ListAddRelationNotNullConstraints (Relation rel, List *constraints, List *old_notnulls)
 
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_toast_pg_class_oid = InvalidOid
 
RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber = InvalidRelFileNumber
 
RelFileNumber binary_upgrade_next_toast_pg_class_relfilenumber = InvalidRelFileNumber
 
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_attribute *const SysAtt [] = {&a1, &a2, &a3, &a4, &a5, &a6}
 

Function Documentation

◆ AddNewAttributeTuples()

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

Definition at line 810 of file heap.c.

813 {
814  Relation rel;
815  CatalogIndexState indstate;
816  int natts = tupdesc->natts;
817  ObjectAddress myself,
818  referenced;
819 
820  /*
821  * open pg_attribute and its indexes.
822  */
823  rel = table_open(AttributeRelationId, RowExclusiveLock);
824 
825  indstate = CatalogOpenIndexes(rel);
826 
827  InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate);
828 
829  /* add dependencies on their datatypes and collations */
830  for (int i = 0; i < natts; i++)
831  {
832  /* Add dependency info */
833  ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1);
834  ObjectAddressSet(referenced, TypeRelationId,
835  tupdesc->attrs[i].atttypid);
836  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
837 
838  /* The default collation is pinned, so don't bother recording it */
839  if (OidIsValid(tupdesc->attrs[i].attcollation) &&
840  tupdesc->attrs[i].attcollation != DEFAULT_COLLATION_OID)
841  {
842  ObjectAddressSet(referenced, CollationRelationId,
843  tupdesc->attrs[i].attcollation);
844  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845  }
846  }
847 
848  /*
849  * Next we add the system attributes. Skip all for a view or type
850  * relation. We don't bother with making datatype dependencies here,
851  * since presumably all these types are pinned.
852  */
853  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
854  {
855  TupleDesc td;
856 
858 
859  InsertPgAttributeTuples(rel, td, new_rel_oid, NULL, indstate);
860  FreeTupleDesc(td);
861  }
862 
863  /*
864  * clean up
865  */
866  CatalogCloseIndexes(indstate);
867 
869 }
#define lengthof(array)
Definition: c.h:777
#define OidIsValid(objectId)
Definition: c.h:764
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
static const FormData_pg_attribute *const SysAtt[]
Definition: heap.c:232
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:701
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:193
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:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:331
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:112

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

969 {
970  Form_pg_class new_rel_reltup;
971 
972  /*
973  * first we update some of the information in our uncataloged relation's
974  * relation descriptor.
975  */
976  new_rel_reltup = new_rel_desc->rd_rel;
977 
978  /* The relation is empty */
979  new_rel_reltup->relpages = 0;
980  new_rel_reltup->reltuples = -1;
981  new_rel_reltup->relallvisible = 0;
982 
983  /* Sequences always have a known size */
984  if (relkind == RELKIND_SEQUENCE)
985  {
986  new_rel_reltup->relpages = 1;
987  new_rel_reltup->reltuples = 1;
988  }
989 
990  new_rel_reltup->relfrozenxid = relfrozenxid;
991  new_rel_reltup->relminmxid = relminmxid;
992  new_rel_reltup->relowner = relowner;
993  new_rel_reltup->reltype = new_type_oid;
994  new_rel_reltup->reloftype = reloftype;
995 
996  /* relispartition is always set by updating this tuple later */
997  new_rel_reltup->relispartition = false;
998 
999  /* fill rd_att's type ID with something sane even if reltype is zero */
1000  new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
1001  new_rel_desc->rd_att->tdtypmod = -1;
1002 
1003  /* Now build and insert the tuple */
1004  InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
1005  relacl, reloptions);
1006 }
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:885
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
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 1016 of file heap.c.

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

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

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), AdjustNotNullInheritance1(), Assert(), RawColumnDefault::attnum, CookedConstraint::attnum, castNode, ChooseConstraintName(), Constraint::conname, CookedConstraint::conoid, TupleDescData::constr, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_NOTNULL, CONSTRAINT_RELATION, ConstraintNameIsUsed(), contain_volatile_functions_after_planning(), CookedConstraint::contype, Constraint::contype, cookConstraint(), cookDefault(), Constraint::cooked_expr, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CookedConstraint::expr, RawColumnDefault::generated, get_attname(), get_attnum(), CookedConstraint::inhcount, Constraint::inhcount, Constraint::initially_valid, InvalidAttrNumber, CookedConstraint::is_local, CookedConstraint::is_no_inherit, Constraint::is_no_inherit, IsA, Constraint::keys, lappend(), lfirst, linitial, list_length(), list_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(), StoreRelNotNull(), stringToNode(), strVal, and TupleDescAttr.

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

◆ AddRelationNotNullConstraints()

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

Definition at line 2789 of file heap.c.

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

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

Referenced by DefineRelation().

◆ check_nested_generated()

static void check_nested_generated ( ParseState pstate,
Node node 
)
static

Definition at line 3058 of file heap.c.

3059 {
3060  check_nested_generated_walker(node, pstate);
3061 }
static bool check_nested_generated_walker(Node *node, void *context)
Definition: heap.c:3016

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

3017 {
3018  ParseState *pstate = context;
3019 
3020  if (node == NULL)
3021  return false;
3022  else if (IsA(node, Var))
3023  {
3024  Var *var = (Var *) node;
3025  Oid relid;
3027 
3028  relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
3029  if (!OidIsValid(relid))
3030  return false; /* XXX shouldn't we raise an error? */
3031 
3032  attnum = var->varattno;
3033 
3034  if (attnum > 0 && get_attgenerated(relid, attnum))
3035  ereport(ERROR,
3036  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3037  errmsg("cannot use generated column \"%s\" in column generation expression",
3038  get_attname(relid, attnum, false)),
3039  errdetail("A generated column cannot reference another generated column."),
3040  parser_errposition(pstate, var->location)));
3041  /* A whole-row Var is necessarily self-referential, so forbid it */
3042  if (attnum == 0)
3043  ereport(ERROR,
3044  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3045  errmsg("cannot use whole-row variable in column generation expression"),
3046  errdetail("This would cause the generated column to depend on its own value."),
3047  parser_errposition(pstate, var->location)));
3048  /* System columns were already checked in the parser */
3049 
3050  return false;
3051  }
3052  else
3054  (void *) context);
3055 }
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:887
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * p_rtable
Definition: parse_node.h:193
AttrNumber varattno
Definition: primnodes.h:246
int varno
Definition: primnodes.h:241
int location
Definition: primnodes.h:279

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

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

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

Referenced by addRangeTableEntryForFunction(), and heap_create_with_catalog().

◆ CheckAttributeType()

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

Definition at line 548 of file heap.c.

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

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

◆ cookConstraint()

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

Definition at line 3153 of file heap.c.

3156 {
3157  Node *expr;
3158 
3159  /*
3160  * Transform raw parsetree to executable expression.
3161  */
3162  expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
3163 
3164  /*
3165  * Make sure it yields a boolean result.
3166  */
3167  expr = coerce_to_boolean(pstate, expr, "CHECK");
3168 
3169  /*
3170  * Take care of collations.
3171  */
3172  assign_expr_collations(pstate, expr);
3173 
3174  /*
3175  * Make sure no outside relations are referred to (this is probably dead
3176  * code now that add_missing_from is history).
3177  */
3178  if (list_length(pstate->p_rtable) != 1)
3179  ereport(ERROR,
3180  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3181  errmsg("only table \"%s\" can be referenced in check constraint",
3182  relname)));
3183 
3184  return expr;
3185 }
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:110
@ EXPR_KIND_CHECK_CONSTRAINT
Definition: parse_node.h:67
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 3076 of file heap.c.

3082 {
3083  Node *expr;
3084 
3085  Assert(raw_default != NULL);
3086 
3087  /*
3088  * Transform raw parsetree to executable expression.
3089  */
3090  expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3091 
3092  if (attgenerated)
3093  {
3094  /* Disallow refs to other generated columns */
3095  check_nested_generated(pstate, expr);
3096 
3097  /* Disallow mutable functions */
3099  ereport(ERROR,
3100  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3101  errmsg("generation expression is not immutable")));
3102  }
3103  else
3104  {
3105  /*
3106  * For a default expression, transformExpr() should have rejected
3107  * column references.
3108  */
3109  Assert(!contain_var_clause(expr));
3110  }
3111 
3112  /*
3113  * Coerce the expression to the correct type and typmod, if given. This
3114  * should match the parser's processing of non-defaulted expressions ---
3115  * see transformAssignedExpr().
3116  */
3117  if (OidIsValid(atttypid))
3118  {
3119  Oid type_id = exprType(expr);
3120 
3121  expr = coerce_to_target_type(pstate, expr, type_id,
3122  atttypid, atttypmod,
3125  -1);
3126  if (expr == NULL)
3127  ereport(ERROR,
3128  (errcode(ERRCODE_DATATYPE_MISMATCH),
3129  errmsg("column \"%s\" is of type %s"
3130  " but default expression is of type %s",
3131  attname,
3132  format_type_be(atttypid),
3133  format_type_be(type_id)),
3134  errhint("You will need to rewrite or cast the expression.")));
3135  }
3136 
3137  /*
3138  * Finally, take care of collations in the finished expression.
3139  */
3140  assign_expr_collations(pstate, expr);
3141 
3142  return expr;
3143 }
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:473
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3058
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
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:69
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:82
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:671
@ COERCION_ASSIGNMENT
Definition: primnodes.h:650
bool contain_var_clause(Node *node)
Definition: var.c:403

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

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

◆ CopyStatistics()

void CopyStatistics ( Oid  fromrelid,
Oid  torelid 
)

Definition at line 3191 of file heap.c.

3192 {
3193  HeapTuple tup;
3194  SysScanDesc scan;
3195  ScanKeyData key[1];
3196  Relation statrel;
3197  CatalogIndexState indstate = NULL;
3198 
3199  statrel = table_open(StatisticRelationId, RowExclusiveLock);
3200 
3201  /* Now search for stat records */
3202  ScanKeyInit(&key[0],
3203  Anum_pg_statistic_starelid,
3204  BTEqualStrategyNumber, F_OIDEQ,
3205  ObjectIdGetDatum(fromrelid));
3206 
3207  scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3208  true, NULL, 1, key);
3209 
3210  while (HeapTupleIsValid((tup = systable_getnext(scan))))
3211  {
3212  Form_pg_statistic statform;
3213 
3214  /* make a modifiable copy */
3215  tup = heap_copytuple(tup);
3216  statform = (Form_pg_statistic) GETSTRUCT(tup);
3217 
3218  /* update the copy of the tuple and insert it */
3219  statform->starelid = torelid;
3220 
3221  /* fetch index information when we know we need it */
3222  if (indstate == NULL)
3223  indstate = CatalogOpenIndexes(statrel);
3224 
3225  CatalogTupleInsertWithInfo(statrel, tup, indstate);
3226 
3227  heap_freetuple(tup);
3228  }
3229 
3230  systable_endscan(scan);
3231 
3232  if (indstate != NULL)
3233  CatalogCloseIndexes(indstate);
3234  table_close(statrel, RowExclusiveLock);
3235 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:777
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:256
FormData_pg_statistic * Form_pg_statistic
Definition: pg_statistic.h:135
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

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

Referenced by index_concurrently_swap().

◆ DeleteAttributeTuples()

void DeleteAttributeTuples ( Oid  relid)

Definition at line 1568 of file heap.c.

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

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteRelationTuple()

void DeleteRelationTuple ( Oid  relid)

Definition at line 1539 of file heap.c.

1540 {
1541  Relation pg_class_desc;
1542  HeapTuple tup;
1543 
1544  /* Grab an appropriate lock on the pg_class relation */
1545  pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
1546 
1547  tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1548  if (!HeapTupleIsValid(tup))
1549  elog(ERROR, "cache lookup failed for relation %u", relid);
1550 
1551  /* delete the relation tuple from pg_class, and finish up */
1552  CatalogTupleDelete(pg_class_desc, &tup->t_self);
1553 
1554  ReleaseSysCache(tup);
1555 
1556  table_close(pg_class_desc, RowExclusiveLock);
1557 }
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:267
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:219

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteSystemAttributeTuples()

void DeleteSystemAttributeTuples ( Oid  relid)

Definition at line 1605 of file heap.c.

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

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

◆ heap_create()

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

Definition at line 289 of file heap.c.

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

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

Referenced by heap_create_with_catalog(), and index_create().

◆ heap_create_with_catalog()

Oid heap_create_with_catalog ( const char *  relname,
Oid  relnamespace,
Oid  reltablespace,
Oid  relid,
Oid  reltypeid,
Oid  reloftypeid,
Oid  ownerid,
Oid  accessmtd,
TupleDesc  tupdesc,
List cooked_constraints,
char  relkind,
char  relpersistence,
bool  shared_relation,
bool  mapped_relation,
OnCommitAction  oncommit,
Datum  reloptions,
bool  use_user_acl,
bool  allow_system_table_mods,
bool  is_internal,
Oid  relrewrite,
ObjectAddress typaddress 
)

Definition at line 1094 of file heap.c.

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

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

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

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)

Definition at line 1747 of file heap.c.

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

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

Referenced by doDeletion().

◆ heap_truncate()

void heap_truncate ( List relids)

Definition at line 3339 of file heap.c.

3340 {
3341  List *relations = NIL;
3342  ListCell *cell;
3343 
3344  /* Open relations for processing, and grab exclusive access on each */
3345  foreach(cell, relids)
3346  {
3347  Oid rid = lfirst_oid(cell);
3348  Relation rel;
3349 
3350  rel = table_open(rid, AccessExclusiveLock);
3351  relations = lappend(relations, rel);
3352  }
3353 
3354  /* Don't allow truncate on tables that are referenced by foreign keys */
3355  heap_truncate_check_FKs(relations, true);
3356 
3357  /* OK to do it */
3358  foreach(cell, relations)
3359  {
3360  Relation rel = lfirst(cell);
3361 
3362  /* Truncate the relation */
3363  heap_truncate_one_rel(rel);
3364 
3365  /* Close the relation, but keep exclusive lock on it until commit */
3366  table_close(rel, NoLock);
3367  }
3368 }
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3424
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3380
#define lfirst_oid(lc)
Definition: pg_list.h:174

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

Referenced by PreCommit_on_commit_actions().

◆ heap_truncate_check_FKs()

void heap_truncate_check_FKs ( List relations,
bool  tempTables 
)

Definition at line 3424 of file heap.c.

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

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

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ heap_truncate_find_FKs()

List* heap_truncate_find_FKs ( List relationIds)

Definition at line 3519 of file heap.c.

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

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

Referenced by ExecuteTruncateGuts(), and heap_truncate_check_FKs().

◆ heap_truncate_one_rel()

void heap_truncate_one_rel ( Relation  rel)

Definition at line 3380 of file heap.c.

3381 {
3382  Oid toastrelid;
3383 
3384  /*
3385  * Truncate the relation. Partitioned tables have no storage, so there is
3386  * nothing to do for them here.
3387  */
3388  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3389  return;
3390 
3391  /* Truncate the underlying relation */
3393 
3394  /* If the relation has indexes, truncate the indexes too */
3396 
3397  /* If there is a toast table, truncate that too */
3398  toastrelid = rel->rd_rel->reltoastrelid;
3399  if (OidIsValid(toastrelid))
3400  {
3401  Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3402 
3404  RelationTruncateIndexes(toastrel);
3405  /* keep the lock... */
3406  table_close(toastrel, NoLock);
3407  }
3408 }
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3291
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1634

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

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ InsertPgAttributeTuples()

void InsertPgAttributeTuples ( Relation  pg_attribute_rel,
TupleDesc  tupdesc,
Oid  new_rel_oid,
const Datum attoptions,
CatalogIndexState  indstate 
)

Definition at line 701 of file heap.c.

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

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

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

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

Referenced by AddNewRelationTuple(), and index_create().

◆ list_cookedconstr_attnum_cmp()

static int list_cookedconstr_attnum_cmp ( const ListCell p1,
const ListCell p2 
)
static

Definition at line 2761 of file heap.c.

2762 {
2763  AttrNumber v1 = ((CookedConstraint *) lfirst(p1))->attnum;
2765 
2766  return pg_cmp_s16(v1, v2);
2767 }
static int pg_cmp_s16(int16 a, int16 b)
Definition: int.h:471

References attnum, lfirst, p2, and pg_cmp_s16().

Referenced by AddRelationNotNullConstraints().

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

2619 {
2620  bool found;
2621  Relation conDesc;
2622  SysScanDesc conscan;
2623  ScanKeyData skey[3];
2624  HeapTuple tup;
2625 
2626  /* Search for a pg_constraint entry with same name and relation */
2627  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
2628 
2629  found = false;
2630 
2631  ScanKeyInit(&skey[0],
2632  Anum_pg_constraint_conrelid,
2633  BTEqualStrategyNumber, F_OIDEQ,
2635  ScanKeyInit(&skey[1],
2636  Anum_pg_constraint_contypid,
2637  BTEqualStrategyNumber, F_OIDEQ,
2639  ScanKeyInit(&skey[2],
2640  Anum_pg_constraint_conname,
2641  BTEqualStrategyNumber, F_NAMEEQ,
2642  CStringGetDatum(ccname));
2643 
2644  conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
2645  NULL, 3, skey);
2646 
2647  /* There can be at most one matching row */
2648  if (HeapTupleIsValid(tup = systable_getnext(conscan)))
2649  {
2651 
2652  /* Found it. Conflicts if not identical check constraint */
2653  if (con->contype == CONSTRAINT_CHECK)
2654  {
2655  Datum val;
2656  bool isnull;
2657 
2658  val = fastgetattr(tup,
2659  Anum_pg_constraint_conbin,
2660  conDesc->rd_att, &isnull);
2661  if (isnull)
2662  elog(ERROR, "null conbin for rel %s",
2665  found = true;
2666  }
2667 
2668  /*
2669  * If the existing constraint is purely inherited (no local
2670  * definition) then interpret addition of a local constraint as a
2671  * legal merge. This allows ALTER ADD CONSTRAINT on parent and child
2672  * tables to be given in either order with same end state. However if
2673  * the relation is a partition, all inherited constraints are always
2674  * non-local, including those that were merged.
2675  */
2676  if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
2677  allow_merge = true;
2678 
2679  if (!found || !allow_merge)
2680  ereport(ERROR,
2682  errmsg("constraint \"%s\" for relation \"%s\" already exists",
2683  ccname, RelationGetRelationName(rel))));
2684 
2685  /* If the child constraint is "no inherit" then cannot merge */
2686  if (con->connoinherit)
2687  ereport(ERROR,
2688  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2689  errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
2690  ccname, RelationGetRelationName(rel))));
2691 
2692  /*
2693  * Must not change an existing inherited constraint to "no inherit"
2694  * status. That's because inherited constraints should be able to
2695  * propagate to lower-level children.
2696  */
2697  if (con->coninhcount > 0 && is_no_inherit)
2698  ereport(ERROR,
2699  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2700  errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
2701  ccname, RelationGetRelationName(rel))));
2702 
2703  /*
2704  * If the child constraint is "not valid" then cannot merge with a
2705  * valid parent constraint.
2706  */
2707  if (is_initially_valid && !con->convalidated)
2708  ereport(ERROR,
2709  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2710  errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
2711  ccname, RelationGetRelationName(rel))));
2712 
2713  /* OK to update the tuple */
2714  ereport(NOTICE,
2715  (errmsg("merging constraint \"%s\" with inherited definition",
2716  ccname)));
2717 
2718  tup = heap_copytuple(tup);
2719  con = (Form_pg_constraint) GETSTRUCT(tup);
2720 
2721  /*
2722  * In case of partitions, an inherited constraint must be inherited
2723  * only once since it cannot have multiple parents and it is never
2724  * considered local.
2725  */
2726  if (rel->rd_rel->relispartition)
2727  {
2728  con->coninhcount = 1;
2729  con->conislocal = false;
2730  }
2731  else
2732  {
2733  if (is_local)
2734  con->conislocal = true;
2735  else
2736  con->coninhcount++;
2737 
2738  if (con->coninhcount < 0)
2739  ereport(ERROR,
2740  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2741  errmsg("too many inheritance parents"));
2742  }
2743 
2744  if (is_no_inherit)
2745  {
2746  Assert(is_local);
2747  con->connoinherit = true;
2748  }
2749 
2750  CatalogTupleUpdate(conDesc, &tup->t_self, tup);
2751  }
2752 
2753  systable_endscan(conscan);
2754  table_close(conDesc, RowExclusiveLock);
2755 
2756  return found;
2757 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NOTICE
Definition: elog.h:35
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
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 1927 of file heap.c.

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

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

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

◆ RelationRemoveInheritance()

static void RelationRemoveInheritance ( Oid  relid)
static

Definition at line 1506 of file heap.c.

1507 {
1508  Relation catalogRelation;
1509  SysScanDesc scan;
1510  ScanKeyData key;
1511  HeapTuple tuple;
1512 
1513  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
1514 
1515  ScanKeyInit(&key,
1516  Anum_pg_inherits_inhrelid,
1517  BTEqualStrategyNumber, F_OIDEQ,
1518  ObjectIdGetDatum(relid));
1519 
1520  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1521  NULL, 1, &key);
1522 
1523  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1524  CatalogTupleDelete(catalogRelation, &tuple->t_self);
1525 
1526  systable_endscan(scan);
1527  table_close(catalogRelation, RowExclusiveLock);
1528 }

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

3292 {
3293  ListCell *indlist;
3294 
3295  /* Ask the relcache to produce a list of the indexes of the rel */
3296  foreach(indlist, RelationGetIndexList(heapRelation))
3297  {
3298  Oid indexId = lfirst_oid(indlist);
3299  Relation currentIndex;
3300  IndexInfo *indexInfo;
3301 
3302  /* Open the index relation; use exclusive lock, just to be sure */
3303  currentIndex = index_open(indexId, AccessExclusiveLock);
3304 
3305  /*
3306  * Fetch info needed for index_build. Since we know there are no
3307  * tuples that actually need indexing, we can use a dummy IndexInfo.
3308  * This is slightly cheaper to build, but the real point is to avoid
3309  * possibly running user-defined code in index expressions or
3310  * predicates. We might be getting invoked during ON COMMIT
3311  * processing, and we don't want to run any such code then.
3312  */
3313  indexInfo = BuildDummyIndexInfo(currentIndex);
3314 
3315  /*
3316  * Now truncate the actual file (and discard buffers).
3317  */
3318  RelationTruncate(currentIndex, 0);
3319 
3320  /* Initialize the index and rebuild */
3321  /* Note: we do not need to re-establish pkey setting */
3322  index_build(heapRelation, currentIndex, indexInfo, true, false);
3323 
3324  /* We're done with this index */
3325  index_close(currentIndex, NoLock);
3326  }
3327 }
IndexInfo * BuildDummyIndexInfo(Relation index)
Definition: index.c:2497
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:2972
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4755
void RelationTruncate(Relation rel, BlockNumber nblocks)
Definition: storage.c:287

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

Referenced by heap_truncate_one_rel().

◆ RemoveAttributeById()

void RemoveAttributeById ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 1646 of file heap.c.

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

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

Referenced by doDeletion().

◆ RemovePartitionKeyByRelId()

void RemovePartitionKeyByRelId ( Oid  relid)

Definition at line 3771 of file heap.c.

3772 {
3773  Relation rel;
3774  HeapTuple tuple;
3775 
3776  rel = table_open(PartitionedRelationId, RowExclusiveLock);
3777 
3778  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3779  if (!HeapTupleIsValid(tuple))
3780  elog(ERROR, "cache lookup failed for partition key of relation %u",
3781  relid);
3782 
3783  CatalogTupleDelete(rel, &tuple->t_self);
3784 
3785  ReleaseSysCache(tuple);
3787 }

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

Referenced by heap_drop_with_catalog().

◆ RemoveStatistics()

void RemoveStatistics ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 3244 of file heap.c.

3245 {
3246  Relation pgstatistic;
3247  SysScanDesc scan;
3248  ScanKeyData key[2];
3249  int nkeys;
3250  HeapTuple tuple;
3251 
3252  pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3253 
3254  ScanKeyInit(&key[0],
3255  Anum_pg_statistic_starelid,
3256  BTEqualStrategyNumber, F_OIDEQ,
3257  ObjectIdGetDatum(relid));
3258 
3259  if (attnum == 0)
3260  nkeys = 1;
3261  else
3262  {
3263  ScanKeyInit(&key[1],
3264  Anum_pg_statistic_staattnum,
3265  BTEqualStrategyNumber, F_INT2EQ,
3267  nkeys = 2;
3268  }
3269 
3270  scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3271  NULL, nkeys, key);
3272 
3273  /* we must loop even when attnum != 0, in case of inherited stats */
3274  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3275  CatalogTupleDelete(pgstatistic, &tuple->t_self);
3276 
3277  systable_endscan(scan);
3278 
3279  table_close(pgstatistic, RowExclusiveLock);
3280 }

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

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

◆ SetAttrMissing()

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

Definition at line 1995 of file heap.c.

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

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

Referenced by binary_upgrade_set_missing_value().

◆ SetRelationNumChecks()

static void SetRelationNumChecks ( Relation  rel,
int  numchecks 
)
static

Definition at line 2982 of file heap.c.

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

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

Referenced by AddRelationNewConstraints(), and StoreConstraints().

◆ StoreConstraints()

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

Definition at line 2215 of file heap.c.

2216 {
2217  int numchecks = 0;
2218  ListCell *lc;
2219 
2220  if (cooked_constraints == NIL)
2221  return; /* nothing to do */
2222 
2223  /*
2224  * Deparsing of constraint expressions will fail unless the just-created
2225  * pg_attribute tuples for this relation are made visible. So, bump the
2226  * command counter. CAUTION: this will cause a relcache entry rebuild.
2227  */
2229 
2230  foreach(lc, cooked_constraints)
2231  {
2232  CookedConstraint *con = (CookedConstraint *) lfirst(lc);
2233 
2234  switch (con->contype)
2235  {
2236  case CONSTR_DEFAULT:
2237  con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
2238  is_internal, false);
2239  break;
2240  case CONSTR_CHECK:
2241  con->conoid =
2242  StoreRelCheck(rel, con->name, con->expr,
2243  !con->skip_validation, con->is_local,
2244  con->inhcount, con->is_no_inherit,
2245  is_internal);
2246  numchecks++;
2247  break;
2248 
2249  case CONSTR_NOTNULL:
2250  con->conoid =
2251  StoreRelNotNull(rel, con->name, con->attnum,
2252  !con->skip_validation, con->is_local,
2253  con->inhcount, con->is_no_inherit);
2254  break;
2255 
2256  default:
2257  elog(ERROR, "unrecognized constraint type: %d",
2258  (int) con->contype);
2259  }
2260  }
2261 
2262  if (numchecks > 0)
2263  SetRelationNumChecks(rel, numchecks);
2264 }
void CommandCounterIncrement(void)
Definition: xact.c:1078

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

Referenced by heap_create_with_catalog().

◆ StorePartitionBound()

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

Definition at line 3802 of file heap.c.

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

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

Referenced by ATExecAttachPartition(), and DefineRelation().

◆ StorePartitionKey()

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

Definition at line 3646 of file heap.c.

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

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

Referenced by DefineRelation().

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

2059 {
2060  char *ccbin;
2061  List *varList;
2062  int keycount;
2063  int16 *attNos;
2064  Oid constrOid;
2065 
2066  /*
2067  * Flatten expression to string form for storage.
2068  */
2069  ccbin = nodeToString(expr);
2070 
2071  /*
2072  * Find columns of rel that are used in expr
2073  *
2074  * NB: pull_var_clause is okay here only because we don't allow subselects
2075  * in check constraints; it would fail to examine the contents of
2076  * subselects.
2077  */
2078  varList = pull_var_clause(expr, 0);
2079  keycount = list_length(varList);
2080 
2081  if (keycount > 0)
2082  {
2083  ListCell *vl;
2084  int i = 0;
2085 
2086  attNos = (int16 *) palloc(keycount * sizeof(int16));
2087  foreach(vl, varList)
2088  {
2089  Var *var = (Var *) lfirst(vl);
2090  int j;
2091 
2092  for (j = 0; j < i; j++)
2093  if (attNos[j] == var->varattno)
2094  break;
2095  if (j == i)
2096  attNos[i++] = var->varattno;
2097  }
2098  keycount = i;
2099  }
2100  else
2101  attNos = NULL;
2102 
2103  /*
2104  * Partitioned tables do not contain any rows themselves, so a NO INHERIT
2105  * constraint makes no sense.
2106  */
2107  if (is_no_inherit &&
2108  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2109  ereport(ERROR,
2110  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2111  errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
2112  RelationGetRelationName(rel))));
2113 
2114  /*
2115  * Create the Check Constraint
2116  */
2117  constrOid =
2118  CreateConstraintEntry(ccname, /* Constraint Name */
2119  RelationGetNamespace(rel), /* namespace */
2120  CONSTRAINT_CHECK, /* Constraint Type */
2121  false, /* Is Deferrable */
2122  false, /* Is Deferred */
2123  is_validated,
2124  InvalidOid, /* no parent constraint */
2125  RelationGetRelid(rel), /* relation */
2126  attNos, /* attrs in the constraint */
2127  keycount, /* # key attrs in the constraint */
2128  keycount, /* # total attrs in the constraint */
2129  InvalidOid, /* not a domain constraint */
2130  InvalidOid, /* no associated index */
2131  InvalidOid, /* Foreign key fields */
2132  NULL,
2133  NULL,
2134  NULL,
2135  NULL,
2136  0,
2137  ' ',
2138  ' ',
2139  NULL,
2140  0,
2141  ' ',
2142  NULL, /* not an exclusion constraint */
2143  expr, /* Tree form of check constraint */
2144  ccbin, /* Binary form of check constraint */
2145  is_local, /* conislocal */
2146  inhcount, /* coninhcount */
2147  is_no_inherit, /* connoinherit */
2148  false, /* conwithoutoverlaps */
2149  is_internal); /* internally constructed? */
2150 
2151  pfree(ccbin);
2152 
2153  return constrOid;
2154 }
signed short int16
Definition: c.h:482
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 conWithoutOverlaps, bool is_internal)
Definition: pg_constraint.c:51

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

◆ StoreRelNotNull()

static Oid StoreRelNotNull ( Relation  rel,
const char *  nnname,
AttrNumber  attnum,
bool  is_validated,
bool  is_local,
int  inhcount,
bool  is_no_inherit 
)
static

Definition at line 2162 of file heap.c.

2165 {
2166  Oid constrOid;
2167 
2168  constrOid =
2169  CreateConstraintEntry(nnname,
2170  RelationGetNamespace(rel),
2171  CONSTRAINT_NOTNULL,
2172  false,
2173  false,
2174  is_validated,
2175  InvalidOid,
2176  RelationGetRelid(rel),
2177  &attnum,
2178  1,
2179  1,
2180  InvalidOid, /* not a domain constraint */
2181  InvalidOid, /* no associated index */
2182  InvalidOid, /* Foreign key fields */
2183  NULL,
2184  NULL,
2185  NULL,
2186  NULL,
2187  0,
2188  ' ',
2189  ' ',
2190  NULL,
2191  0,
2192  ' ',
2193  NULL, /* not an exclusion constraint */
2194  NULL,
2195  NULL,
2196  is_local,
2197  inhcount,
2198  is_no_inherit,
2199  false, /* conwithoutoverlaps */
2200  false);
2201  return constrOid;
2202 }

References attnum, CreateConstraintEntry(), InvalidOid, RelationGetNamespace, and RelationGetRelid.

Referenced by AddRelationNewConstraints(), AddRelationNotNullConstraints(), and StoreConstraints().

◆ SystemAttributeByName()

const FormData_pg_attribute* SystemAttributeByName ( const char *  attname)

Definition at line 252 of file heap.c.

253 {
254  int j;
255 
256  for (j = 0; j < (int) lengthof(SysAtt); j++)
257  {
258  const FormData_pg_attribute *att = SysAtt[j];
259 
260  if (strcmp(NameStr(att->attname), attname) == 0)
261  return att;
262  }
263 
264  return NULL;
265 }

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

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

◆ SystemAttributeDefinition()

const FormData_pg_attribute* SystemAttributeDefinition ( AttrNumber  attno)

Definition at line 240 of file heap.c.

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

References elog(), ERROR, lengthof, and SysAtt.

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

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:117
bool attbyval
Definition: pg_attribute.h:103
char attalign
Definition: pg_attribute.h:109
bool attnotnull
Definition: pg_attribute.h:130
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

Definition at line 142 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 156 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:655
#define MinCommandIdAttributeNumber
Definition: sysattr.h:23

Definition at line 170 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 184 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 198 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 218 of file heap.c.

◆ binary_upgrade_next_heap_pg_class_oid

Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid

Definition at line 80 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_relfilenumber

RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber = InvalidRelFileNumber

◆ binary_upgrade_next_toast_pg_class_oid

Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid

◆ binary_upgrade_next_toast_pg_class_relfilenumber

RelFileNumber binary_upgrade_next_toast_pg_class_relfilenumber = InvalidRelFileNumber

Definition at line 83 of file heap.c.

Referenced by binary_upgrade_set_next_toast_relfilenode(), and heap_create_with_catalog().

◆ SysAtt

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

Definition at line 232 of file heap.c.

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