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_enforced, bool is_validated, bool is_local, int16 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_enforced, 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 FormExtraData_pg_attribute tupdesc_extra[], 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)
 
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 824 of file heap.c.

827{
828 Relation rel;
829 CatalogIndexState indstate;
830 int natts = tupdesc->natts;
831 ObjectAddress myself,
832 referenced;
833
834 /*
835 * open pg_attribute and its indexes.
836 */
837 rel = table_open(AttributeRelationId, RowExclusiveLock);
838
839 indstate = CatalogOpenIndexes(rel);
840
841 InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate);
842
843 /* add dependencies on their datatypes and collations */
844 for (int i = 0; i < natts; i++)
845 {
846 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
847
848 /* Add dependency info */
849 ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1);
850 ObjectAddressSet(referenced, TypeRelationId, attr->atttypid);
851 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
852
853 /* The default collation is pinned, so don't bother recording it */
854 if (OidIsValid(attr->attcollation) &&
855 attr->attcollation != DEFAULT_COLLATION_OID)
856 {
857 ObjectAddressSet(referenced, CollationRelationId,
858 attr->attcollation);
859 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
860 }
861 }
862
863 /*
864 * Next we add the system attributes. Skip all for a view or type
865 * relation. We don't bother with making datatype dependencies here,
866 * since presumably all these types are pinned.
867 */
868 if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
869 {
870 TupleDesc td;
871
873
874 InsertPgAttributeTuples(rel, td, new_rel_oid, NULL, indstate);
875 FreeTupleDesc(td);
876 }
877
878 /*
879 * clean up
880 */
881 CatalogCloseIndexes(indstate);
882
884}
#define lengthof(array)
Definition: c.h:745
#define OidIsValid(objectId)
Definition: c.h:732
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
static const FormData_pg_attribute *const SysAtt[]
Definition: heap.c:227
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
Definition: heap.c:707
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
int i
Definition: isn.c:72
#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:184
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
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:479
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:211
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154

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

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

984{
985 Form_pg_class new_rel_reltup;
986
987 /*
988 * first we update some of the information in our uncataloged relation's
989 * relation descriptor.
990 */
991 new_rel_reltup = new_rel_desc->rd_rel;
992
993 /* The relation is empty */
994 new_rel_reltup->relpages = 0;
995 new_rel_reltup->reltuples = -1;
996 new_rel_reltup->relallvisible = 0;
997
998 /* Sequences always have a known size */
999 if (relkind == RELKIND_SEQUENCE)
1000 {
1001 new_rel_reltup->relpages = 1;
1002 new_rel_reltup->reltuples = 1;
1003 }
1004
1005 new_rel_reltup->relfrozenxid = relfrozenxid;
1006 new_rel_reltup->relminmxid = relminmxid;
1007 new_rel_reltup->relowner = relowner;
1008 new_rel_reltup->reltype = new_type_oid;
1009 new_rel_reltup->reloftype = reloftype;
1010
1011 /* relispartition is always set by updating this tuple later */
1012 new_rel_reltup->relispartition = false;
1013
1014 /* fill rd_att's type ID with something sane even if reltype is zero */
1015 new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
1016 new_rel_desc->rd_att->tdtypmod = -1;
1017
1018 /* Now build and insert the tuple */
1019 InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
1020 relacl, reloptions);
1021}
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:900
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:133
Oid tdtypeid
Definition: tupdesc.h:132

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

1038{
1039 return
1040 TypeCreate(new_row_type, /* optional predetermined OID */
1041 typeName, /* type name */
1042 typeNamespace, /* type namespace */
1043 new_rel_oid, /* relation oid */
1044 new_rel_kind, /* relation kind */
1045 ownerid, /* owner's ID */
1046 -1, /* internal size (varlena) */
1047 TYPTYPE_COMPOSITE, /* type-type (composite) */
1048 TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
1049 false, /* composite types are never preferred */
1050 DEFAULT_TYPDELIM, /* default array delimiter */
1051 F_RECORD_IN, /* input procedure */
1052 F_RECORD_OUT, /* output procedure */
1053 F_RECORD_RECV, /* receive procedure */
1054 F_RECORD_SEND, /* send procedure */
1055 InvalidOid, /* typmodin procedure - none */
1056 InvalidOid, /* typmodout procedure - none */
1057 InvalidOid, /* analyze procedure - default */
1058 InvalidOid, /* subscript procedure - none */
1059 InvalidOid, /* array element type - irrelevant */
1060 false, /* this is not an array type */
1061 new_array_type, /* array type if any */
1062 InvalidOid, /* domain base type - irrelevant */
1063 NULL, /* default value - none */
1064 NULL, /* default binary representation */
1065 false, /* passed by reference */
1066 TYPALIGN_DOUBLE, /* alignment - must be the largest! */
1067 TYPSTORAGE_EXTENDED, /* fully TOASTable */
1068 -1, /* typmod */
1069 0, /* array dimensions for typBaseType */
1070 false, /* Type NOT NULL */
1071 InvalidOid); /* rowtypes never have a collation */
1072}
ObjectAddress TypeCreate(Oid newTypeOid, const char *typeName, Oid typeNamespace, Oid relationOid, char relationKind, Oid ownerId, int16 internalSize, char typeType, char typeCategory, bool typePreferred, char typDelim, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid subscriptProcedure, Oid elementType, bool isImplicitArray, Oid arrayType, Oid baseType, const char *defaultTypeValue, char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull, Oid typeCollation)
Definition: pg_type.c:195
#define InvalidOid
Definition: postgres_ext.h:37
#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 2318 of file heap.c.

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

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

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

◆ AddRelationNotNullConstraints()

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

Definition at line 2833 of file heap.c.

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

References Assert, CookedConstraint::attnum, attnum, ChooseConstraintName(), Constraint::conname, CONSTR_NOTNULL, CookedConstraint::contype, Constraint::contype, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, foreach_delete_current, foreach_ptr, get_attgenerated(), get_attname(), get_attnum(), InvalidAttrNumber, Constraint::is_no_inherit, Constraint::keys, lappend(), lappend_int(), linitial, list_delete_nth_cell(), list_length(), list_nth(), list_nth_node, CookedConstraint::name, NIL, pstrdup(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, StoreRelNotNull(), and strVal.

Referenced by DefineRelation().

◆ check_nested_generated()

static void check_nested_generated ( ParseState pstate,
Node node 
)
static

Definition at line 3166 of file heap.c.

3167{
3168 check_nested_generated_walker(node, pstate);
3169}
static bool check_nested_generated_walker(Node *node, void *context)
Definition: heap.c:3124

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

3125{
3126 ParseState *pstate = context;
3127
3128 if (node == NULL)
3129 return false;
3130 else if (IsA(node, Var))
3131 {
3132 Var *var = (Var *) node;
3133 Oid relid;
3135
3136 relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
3137 if (!OidIsValid(relid))
3138 return false; /* XXX shouldn't we raise an error? */
3139
3140 attnum = var->varattno;
3141
3142 if (attnum > 0 && get_attgenerated(relid, attnum))
3143 ereport(ERROR,
3144 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3145 errmsg("cannot use generated column \"%s\" in column generation expression",
3146 get_attname(relid, attnum, false)),
3147 errdetail("A generated column cannot reference another generated column."),
3148 parser_errposition(pstate, var->location)));
3149 /* A whole-row Var is necessarily self-referential, so forbid it */
3150 if (attnum == 0)
3151 ereport(ERROR,
3152 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3153 errmsg("cannot use whole-row variable in column generation expression"),
3154 errdetail("This would cause the generated column to depend on its own value."),
3155 parser_errposition(pstate, var->location)));
3156 /* System columns were already checked in the parser */
3157
3158 return false;
3159 }
3160 else
3162 context);
3163}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * p_rtable
Definition: parse_node.h:212
ParseLoc location
Definition: primnodes.h:310
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269

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

◆ CheckAttributeNamesTypes()

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

Definition at line 451 of file heap.c.

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

References attname, CheckAttributeType(), CHKATYPE_IS_VIRTUAL, 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 543 of file heap.c.

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

References AccessShareLock, attname, check_stack_depth(), CheckAttributeType(), CHKATYPE_ANYARRAY, CHKATYPE_ANYRECORD, CHKATYPE_IS_PARTKEY, CHKATYPE_IS_VIRTUAL, 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(), CheckAttributeType(), ComputePartitionAttrs(), and ConstructTupleDescriptor().

◆ cookConstraint()

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

Definition at line 3261 of file heap.c.

3264{
3265 Node *expr;
3266
3267 /*
3268 * Transform raw parsetree to executable expression.
3269 */
3270 expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
3271
3272 /*
3273 * Make sure it yields a boolean result.
3274 */
3275 expr = coerce_to_boolean(pstate, expr, "CHECK");
3276
3277 /*
3278 * Take care of collations.
3279 */
3280 assign_expr_collations(pstate, expr);
3281
3282 /*
3283 * Make sure no outside relations are referred to (this is probably dead
3284 * code now that add_missing_from is history).
3285 */
3286 if (list_length(pstate->p_rtable) != 1)
3287 ereport(ERROR,
3288 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3289 errmsg("only table \"%s\" can be referenced in check constraint",
3290 relname)));
3291
3292 return expr;
3293}
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:118
@ EXPR_KIND_CHECK_CONSTRAINT
Definition: parse_node.h:68
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 3184 of file heap.c.

3190{
3191 Node *expr;
3192
3193 Assert(raw_default != NULL);
3194
3195 /*
3196 * Transform raw parsetree to executable expression.
3197 */
3198 expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3199
3200 if (attgenerated)
3201 {
3202 /* Disallow refs to other generated columns */
3203 check_nested_generated(pstate, expr);
3204
3205 /* Disallow mutable functions */
3207 ereport(ERROR,
3208 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3209 errmsg("generation expression is not immutable")));
3210 }
3211 else
3212 {
3213 /*
3214 * For a default expression, transformExpr() should have rejected
3215 * column references.
3216 */
3217 Assert(!contain_var_clause(expr));
3218 }
3219
3220 /*
3221 * Coerce the expression to the correct type and typmod, if given. This
3222 * should match the parser's processing of non-defaulted expressions ---
3223 * see transformAssignedExpr().
3224 */
3225 if (OidIsValid(atttypid))
3226 {
3227 Oid type_id = exprType(expr);
3228
3229 expr = coerce_to_target_type(pstate, expr, type_id,
3230 atttypid, atttypmod,
3233 -1);
3234 if (expr == NULL)
3235 ereport(ERROR,
3236 (errcode(ERRCODE_DATATYPE_MISMATCH),
3237 errmsg("column \"%s\" is of type %s"
3238 " but default expression is of type %s",
3239 attname,
3240 format_type_be(atttypid),
3241 format_type_be(type_id)),
3242 errhint("You will need to rewrite or cast the expression.")));
3243 }
3244
3245 /*
3246 * Finally, take care of collations in the finished expression.
3247 */
3248 assign_expr_collations(pstate, expr);
3249
3250 return expr;
3251}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:489
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3166
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
@ EXPR_KIND_COLUMN_DEFAULT
Definition: parse_node.h:70
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:83
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
bool contain_var_clause(Node *node)
Definition: var.c:406

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

3300{
3301 HeapTuple tup;
3302 SysScanDesc scan;
3303 ScanKeyData key[1];
3304 Relation statrel;
3305 CatalogIndexState indstate = NULL;
3306
3307 statrel = table_open(StatisticRelationId, RowExclusiveLock);
3308
3309 /* Now search for stat records */
3310 ScanKeyInit(&key[0],
3311 Anum_pg_statistic_starelid,
3312 BTEqualStrategyNumber, F_OIDEQ,
3313 ObjectIdGetDatum(fromrelid));
3314
3315 scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3316 true, NULL, 1, key);
3317
3318 while (HeapTupleIsValid((tup = systable_getnext(scan))))
3319 {
3320 Form_pg_statistic statform;
3321
3322 /* make a modifiable copy */
3323 tup = heap_copytuple(tup);
3324 statform = (Form_pg_statistic) GETSTRUCT(tup);
3325
3326 /* update the copy of the tuple and insert it */
3327 statform->starelid = torelid;
3328
3329 /* fetch index information when we know we need it */
3330 if (indstate == NULL)
3331 indstate = CatalogOpenIndexes(statrel);
3332
3333 CatalogTupleInsertWithInfo(statrel, tup, indstate);
3334
3335 heap_freetuple(tup);
3336 }
3337
3338 systable_endscan(scan);
3339
3340 if (indstate != NULL)
3341 CatalogCloseIndexes(indstate);
3342 table_close(statrel, RowExclusiveLock);
3343}
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
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:778
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
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:257
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 1592 of file heap.c.

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

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

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteSystemAttributeTuples()

void DeleteSystemAttributeTuples ( Oid  relid)

Definition at line 1629 of file heap.c.

1630{
1631 Relation attrel;
1632 SysScanDesc scan;
1633 ScanKeyData key[2];
1634 HeapTuple atttup;
1635
1636 /* Grab an appropriate lock on the pg_attribute relation */
1637 attrel = table_open(AttributeRelationId, RowExclusiveLock);
1638
1639 /* Use the index to scan only system attributes of the target relation */
1640 ScanKeyInit(&key[0],
1641 Anum_pg_attribute_attrelid,
1642 BTEqualStrategyNumber, F_OIDEQ,
1643 ObjectIdGetDatum(relid));
1644 ScanKeyInit(&key[1],
1645 Anum_pg_attribute_attnum,
1646 BTLessEqualStrategyNumber, F_INT2LE,
1647 Int16GetDatum(0));
1648
1649 scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1650 NULL, 2, key);
1651
1652 /* Delete all the matching tuples */
1653 while ((atttup = systable_getnext(scan)) != NULL)
1654 CatalogTupleDelete(attrel, &atttup->t_self);
1655
1656 /* Clean up after the scan */
1657 systable_endscan(scan);
1659}
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
#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 284 of file heap.c.

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

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

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

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

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)

Definition at line 1771 of file heap.c.

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

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

3448{
3449 List *relations = NIL;
3450 ListCell *cell;
3451
3452 /* Open relations for processing, and grab exclusive access on each */
3453 foreach(cell, relids)
3454 {
3455 Oid rid = lfirst_oid(cell);
3456 Relation rel;
3457
3458 rel = table_open(rid, AccessExclusiveLock);
3459 relations = lappend(relations, rel);
3460 }
3461
3462 /* Don't allow truncate on tables that are referenced by foreign keys */
3463 heap_truncate_check_FKs(relations, true);
3464
3465 /* OK to do it */
3466 foreach(cell, relations)
3467 {
3468 Relation rel = lfirst(cell);
3469
3470 /* Truncate the relation */
3472
3473 /* Close the relation, but keep exclusive lock on it until commit */
3474 table_close(rel, NoLock);
3475 }
3476}
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3532
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3488
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_oid(lc)
Definition: pg_list.h:174

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

Referenced by PreCommit_on_commit_actions().

◆ heap_truncate_check_FKs()

void heap_truncate_check_FKs ( List relations,
bool  tempTables 
)

Definition at line 3532 of file heap.c.

3533{
3534 List *oids = NIL;
3535 List *dependents;
3536 ListCell *cell;
3537
3538 /*
3539 * Build a list of OIDs of the interesting relations.
3540 *
3541 * If a relation has no triggers, then it can neither have FKs nor be
3542 * referenced by a FK from another table, so we can ignore it. For
3543 * partitioned tables, FKs have no triggers, so we must include them
3544 * anyway.
3545 */
3546 foreach(cell, relations)
3547 {
3548 Relation rel = lfirst(cell);
3549
3550 if (rel->rd_rel->relhastriggers ||
3551 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3552 oids = lappend_oid(oids, RelationGetRelid(rel));
3553 }
3554
3555 /*
3556 * Fast path: if no relation has triggers, none has FKs either.
3557 */
3558 if (oids == NIL)
3559 return;
3560
3561 /*
3562 * Otherwise, must scan pg_constraint. We make one pass with all the
3563 * relations considered; if this finds nothing, then all is well.
3564 */
3565 dependents = heap_truncate_find_FKs(oids);
3566 if (dependents == NIL)
3567 return;
3568
3569 /*
3570 * Otherwise we repeat the scan once per relation to identify a particular
3571 * pair of relations to complain about. This is pretty slow, but
3572 * performance shouldn't matter much in a failure path. The reason for
3573 * doing things this way is to ensure that the message produced is not
3574 * dependent on chance row locations within pg_constraint.
3575 */
3576 foreach(cell, oids)
3577 {
3578 Oid relid = lfirst_oid(cell);
3579 ListCell *cell2;
3580
3581 dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3582
3583 foreach(cell2, dependents)
3584 {
3585 Oid relid2 = lfirst_oid(cell2);
3586
3587 if (!list_member_oid(oids, relid2))
3588 {
3589 char *relname = get_rel_name(relid);
3590 char *relname2 = get_rel_name(relid2);
3591
3592 if (tempTables)
3593 ereport(ERROR,
3594 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3595 errmsg("unsupported ON COMMIT and foreign key combination"),
3596 errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3597 relname2, relname)));
3598 else
3599 ereport(ERROR,
3600 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3601 errmsg("cannot truncate a table referenced in a foreign key constraint"),
3602 errdetail("Table \"%s\" references \"%s\".",
3603 relname2, relname),
3604 errhint("Truncate table \"%s\" at the same time, "
3605 "or use TRUNCATE ... CASCADE.",
3606 relname2)));
3607 }
3608 }
3609 }
3610}
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3627
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1955
#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 3627 of file heap.c.

3628{
3629 List *result = NIL;
3630 List *oids;
3631 List *parent_cons;
3632 ListCell *cell;
3634 Relation fkeyRel;
3635 SysScanDesc fkeyScan;
3636 HeapTuple tuple;
3637 bool restart;
3638
3639 oids = list_copy(relationIds);
3640
3641 /*
3642 * Must scan pg_constraint. Right now, it is a seqscan because there is
3643 * no available index on confrelid.
3644 */
3645 fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3646
3647restart:
3648 restart = false;
3649 parent_cons = NIL;
3650
3651 fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3652 NULL, 0, NULL);
3653
3654 while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3655 {
3657
3658 /* Not a foreign key */
3659 if (con->contype != CONSTRAINT_FOREIGN)
3660 continue;
3661
3662 /* Not referencing one of our list of tables */
3663 if (!list_member_oid(oids, con->confrelid))
3664 continue;
3665
3666 /*
3667 * If this constraint has a parent constraint which we have not seen
3668 * yet, keep track of it for the second loop, below. Tracking parent
3669 * constraints allows us to climb up to the top-level constraint and
3670 * look for all possible relations referencing the partitioned table.
3671 */
3672 if (OidIsValid(con->conparentid) &&
3673 !list_member_oid(parent_cons, con->conparentid))
3674 parent_cons = lappend_oid(parent_cons, con->conparentid);
3675
3676 /*
3677 * Add referencer to result, unless present in input list. (Don't
3678 * worry about dupes: we'll fix that below).
3679 */
3680 if (!list_member_oid(relationIds, con->conrelid))
3681 result = lappend_oid(result, con->conrelid);
3682 }
3683
3684 systable_endscan(fkeyScan);
3685
3686 /*
3687 * Process each parent constraint we found to add the list of referenced
3688 * relations by them to the oids list. If we do add any new such
3689 * relations, redo the first loop above. Also, if we see that the parent
3690 * constraint in turn has a parent, add that so that we process all
3691 * relations in a single additional pass.
3692 */
3693 foreach(cell, parent_cons)
3694 {
3695 Oid parent = lfirst_oid(cell);
3696
3698 Anum_pg_constraint_oid,
3699 BTEqualStrategyNumber, F_OIDEQ,
3700 ObjectIdGetDatum(parent));
3701
3702 fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3703 true, NULL, 1, &key);
3704
3705 tuple = systable_getnext(fkeyScan);
3706 if (HeapTupleIsValid(tuple))
3707 {
3709
3710 /*
3711 * pg_constraint rows always appear for partitioned hierarchies
3712 * this way: on the each side of the constraint, one row appears
3713 * for each partition that points to the top-most table on the
3714 * other side.
3715 *
3716 * Because of this arrangement, we can correctly catch all
3717 * relevant relations by adding to 'parent_cons' all rows with
3718 * valid conparentid, and to the 'oids' list all rows with a zero
3719 * conparentid. If any oids are added to 'oids', redo the first
3720 * loop above by setting 'restart'.
3721 */
3722 if (OidIsValid(con->conparentid))
3723 parent_cons = list_append_unique_oid(parent_cons,
3724 con->conparentid);
3725 else if (!list_member_oid(oids, con->confrelid))
3726 {
3727 oids = lappend_oid(oids, con->confrelid);
3728 restart = true;
3729 }
3730 }
3731
3732 systable_endscan(fkeyScan);
3733 }
3734
3735 list_free(parent_cons);
3736 if (restart)
3737 goto restart;
3738
3739 table_close(fkeyRel, AccessShareLock);
3740 list_free(oids);
3741
3742 /* Now sort and de-duplicate the result list */
3743 list_sort(result, list_oid_cmp);
3744 list_deduplicate_oid(result);
3745
3746 return result;
3747}
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
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
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 3488 of file heap.c.

3489{
3490 Oid toastrelid;
3491
3492 /*
3493 * Truncate the relation. Partitioned tables have no storage, so there is
3494 * nothing to do for them here.
3495 */
3496 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3497 return;
3498
3499 /* Truncate the underlying relation */
3501
3502 /* If the relation has indexes, truncate the indexes too */
3504
3505 /* If there is a toast table, truncate that too */
3506 toastrelid = rel->rd_rel->reltoastrelid;
3507 if (OidIsValid(toastrelid))
3508 {
3509 Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3510
3512 RelationTruncateIndexes(toastrel);
3513 /* keep the lock... */
3514 table_close(toastrel, NoLock);
3515 }
3516}
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3399
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1645

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

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ InsertPgAttributeTuples()

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

Definition at line 707 of file heap.c.

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

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

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

◆ InsertPgClassTuple()

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

Definition at line 900 of file heap.c.

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

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

Referenced by AddNewRelationTuple(), and index_create().

◆ MergeWithExistingConstraint()

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

Definition at line 2650 of file heap.c.

2655{
2656 bool found;
2657 Relation conDesc;
2658 SysScanDesc conscan;
2659 ScanKeyData skey[3];
2660 HeapTuple tup;
2661
2662 /* Search for a pg_constraint entry with same name and relation */
2663 conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
2664
2665 found = false;
2666
2667 ScanKeyInit(&skey[0],
2668 Anum_pg_constraint_conrelid,
2669 BTEqualStrategyNumber, F_OIDEQ,
2671 ScanKeyInit(&skey[1],
2672 Anum_pg_constraint_contypid,
2673 BTEqualStrategyNumber, F_OIDEQ,
2675 ScanKeyInit(&skey[2],
2676 Anum_pg_constraint_conname,
2677 BTEqualStrategyNumber, F_NAMEEQ,
2678 CStringGetDatum(ccname));
2679
2680 conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
2681 NULL, 3, skey);
2682
2683 /* There can be at most one matching row */
2684 if (HeapTupleIsValid(tup = systable_getnext(conscan)))
2685 {
2687
2688 /* Found it. Conflicts if not identical check constraint */
2689 if (con->contype == CONSTRAINT_CHECK)
2690 {
2691 Datum val;
2692 bool isnull;
2693
2694 val = fastgetattr(tup,
2695 Anum_pg_constraint_conbin,
2696 conDesc->rd_att, &isnull);
2697 if (isnull)
2698 elog(ERROR, "null conbin for rel %s",
2701 found = true;
2702 }
2703
2704 /*
2705 * If the existing constraint is purely inherited (no local
2706 * definition) then interpret addition of a local constraint as a
2707 * legal merge. This allows ALTER ADD CONSTRAINT on parent and child
2708 * tables to be given in either order with same end state. However if
2709 * the relation is a partition, all inherited constraints are always
2710 * non-local, including those that were merged.
2711 */
2712 if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
2713 allow_merge = true;
2714
2715 if (!found || !allow_merge)
2716 ereport(ERROR,
2718 errmsg("constraint \"%s\" for relation \"%s\" already exists",
2719 ccname, RelationGetRelationName(rel))));
2720
2721 /* If the child constraint is "no inherit" then cannot merge */
2722 if (con->connoinherit)
2723 ereport(ERROR,
2724 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2725 errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
2726 ccname, RelationGetRelationName(rel))));
2727
2728 /*
2729 * Must not change an existing inherited constraint to "no inherit"
2730 * status. That's because inherited constraints should be able to
2731 * propagate to lower-level children.
2732 */
2733 if (con->coninhcount > 0 && is_no_inherit)
2734 ereport(ERROR,
2735 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2736 errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
2737 ccname, RelationGetRelationName(rel))));
2738
2739 /*
2740 * If the child constraint is "not valid" then cannot merge with a
2741 * valid parent constraint.
2742 */
2743 if (is_initially_valid && con->conenforced && !con->convalidated)
2744 ereport(ERROR,
2745 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2746 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
2747 ccname, RelationGetRelationName(rel))));
2748
2749 /*
2750 * A non-enforced child constraint cannot be merged with an enforced
2751 * parent constraint. However, the reverse is allowed, where the child
2752 * constraint is enforced.
2753 */
2754 if ((!is_local && is_enforced && !con->conenforced) ||
2755 (is_local && !is_enforced && con->conenforced))
2756 ereport(ERROR,
2757 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2758 errmsg("constraint \"%s\" conflicts with NOT ENFORCED constraint on relation \"%s\"",
2759 ccname, RelationGetRelationName(rel))));
2760
2761 /* OK to update the tuple */
2763 (errmsg("merging constraint \"%s\" with inherited definition",
2764 ccname)));
2765
2766 tup = heap_copytuple(tup);
2767 con = (Form_pg_constraint) GETSTRUCT(tup);
2768
2769 /*
2770 * In case of partitions, an inherited constraint must be inherited
2771 * only once since it cannot have multiple parents and it is never
2772 * considered local.
2773 */
2774 if (rel->rd_rel->relispartition)
2775 {
2776 con->coninhcount = 1;
2777 con->conislocal = false;
2778 }
2779 else
2780 {
2781 if (is_local)
2782 con->conislocal = true;
2783 else if (pg_add_s16_overflow(con->coninhcount, 1,
2784 &con->coninhcount))
2785 ereport(ERROR,
2786 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2787 errmsg("too many inheritance parents"));
2788 }
2789
2790 if (is_no_inherit)
2791 {
2792 Assert(is_local);
2793 con->connoinherit = true;
2794 }
2795
2796 /*
2797 * If the child constraint is required to be enforced while the parent
2798 * constraint is not, this should be allowed by marking the child
2799 * constraint as enforced. In the reverse case, an error would have
2800 * already been thrown before reaching this point.
2801 */
2802 if (is_enforced && !con->conenforced)
2803 {
2804 Assert(is_local);
2805 con->conenforced = true;
2806 con->convalidated = true;
2807 }
2808
2809 CatalogTupleUpdate(conDesc, &tup->t_self, tup);
2810 }
2811
2812 systable_endscan(conscan);
2813 table_close(conDesc, RowExclusiveLock);
2814
2815 return found;
2816}
#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:860
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
long val
Definition: informix.c:689
static bool pg_add_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:67

References Assert, BTEqualStrategyNumber, CatalogTupleUpdate(), CStringGetDatum(), elog, equal(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fastgetattr(), GETSTRUCT(), heap_copytuple(), HeapTupleIsValid, InvalidOid, NOTICE, ObjectIdGetDatum(), pg_add_s16_overflow(), 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 1951 of file heap.c.

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

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

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

◆ RelationRemoveInheritance()

static void RelationRemoveInheritance ( Oid  relid)
static

Definition at line 1530 of file heap.c.

1531{
1532 Relation catalogRelation;
1533 SysScanDesc scan;
1535 HeapTuple tuple;
1536
1537 catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
1538
1540 Anum_pg_inherits_inhrelid,
1541 BTEqualStrategyNumber, F_OIDEQ,
1542 ObjectIdGetDatum(relid));
1543
1544 scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1545 NULL, 1, &key);
1546
1547 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1548 CatalogTupleDelete(catalogRelation, &tuple->t_self);
1549
1550 systable_endscan(scan);
1551 table_close(catalogRelation, RowExclusiveLock);
1552}

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

3400{
3401 ListCell *indlist;
3402
3403 /* Ask the relcache to produce a list of the indexes of the rel */
3404 foreach(indlist, RelationGetIndexList(heapRelation))
3405 {
3406 Oid indexId = lfirst_oid(indlist);
3407 Relation currentIndex;
3408 IndexInfo *indexInfo;
3409
3410 /* Open the index relation; use exclusive lock, just to be sure */
3411 currentIndex = index_open(indexId, AccessExclusiveLock);
3412
3413 /*
3414 * Fetch info needed for index_build. Since we know there are no
3415 * tuples that actually need indexing, we can use a dummy IndexInfo.
3416 * This is slightly cheaper to build, but the real point is to avoid
3417 * possibly running user-defined code in index expressions or
3418 * predicates. We might be getting invoked during ON COMMIT
3419 * processing, and we don't want to run any such code then.
3420 */
3421 indexInfo = BuildDummyIndexInfo(currentIndex);
3422
3423 /*
3424 * Now truncate the actual file (and discard buffers).
3425 */
3426 RelationTruncate(currentIndex, 0);
3427
3428 /* Initialize the index and rebuild */
3429 /* Note: we do not need to re-establish pkey setting */
3430 index_build(heapRelation, currentIndex, indexInfo, true, false);
3431
3432 /* We're done with this index */
3433 index_close(currentIndex, NoLock);
3434 }
3435}
IndexInfo * BuildDummyIndexInfo(Relation index)
Definition: index.c:2487
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:2975
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:4759
void RelationTruncate(Relation rel, BlockNumber nblocks)
Definition: storage.c:288

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

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

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

Referenced by doDeletion().

◆ RemovePartitionKeyByRelId()

void RemovePartitionKeyByRelId ( Oid  relid)

Definition at line 3879 of file heap.c.

3880{
3881 Relation rel;
3882 HeapTuple tuple;
3883
3884 rel = table_open(PartitionedRelationId, RowExclusiveLock);
3885
3886 tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3887 if (!HeapTupleIsValid(tuple))
3888 elog(ERROR, "cache lookup failed for partition key of relation %u",
3889 relid);
3890
3891 CatalogTupleDelete(rel, &tuple->t_self);
3892
3893 ReleaseSysCache(tuple);
3895}

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

3353{
3354 Relation pgstatistic;
3355 SysScanDesc scan;
3356 ScanKeyData key[2];
3357 int nkeys;
3358 HeapTuple tuple;
3359
3360 pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3361
3362 ScanKeyInit(&key[0],
3363 Anum_pg_statistic_starelid,
3364 BTEqualStrategyNumber, F_OIDEQ,
3365 ObjectIdGetDatum(relid));
3366
3367 if (attnum == 0)
3368 nkeys = 1;
3369 else
3370 {
3371 ScanKeyInit(&key[1],
3372 Anum_pg_statistic_staattnum,
3373 BTEqualStrategyNumber, F_INT2EQ,
3375 nkeys = 2;
3376 }
3377
3378 scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3379 NULL, nkeys, key);
3380
3381 /* we must loop even when attnum != 0, in case of inherited stats */
3382 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3383 CatalogTupleDelete(pgstatistic, &tuple->t_self);
3384
3385 systable_endscan(scan);
3386
3387 table_close(pgstatistic, RowExclusiveLock);
3388}

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

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

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

Referenced by binary_upgrade_set_missing_value().

◆ SetRelationNumChecks()

static void SetRelationNumChecks ( Relation  rel,
int  numchecks 
)
static

Definition at line 3090 of file heap.c.

3091{
3092 Relation relrel;
3093 HeapTuple reltup;
3094 Form_pg_class relStruct;
3095
3096 relrel = table_open(RelationRelationId, RowExclusiveLock);
3097 reltup = SearchSysCacheCopy1(RELOID,
3099 if (!HeapTupleIsValid(reltup))
3100 elog(ERROR, "cache lookup failed for relation %u",
3101 RelationGetRelid(rel));
3102 relStruct = (Form_pg_class) GETSTRUCT(reltup);
3103
3104 if (relStruct->relchecks != numchecks)
3105 {
3106 relStruct->relchecks = numchecks;
3107
3108 CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
3109 }
3110 else
3111 {
3112 /* Skip the disk update, but force relcache inval anyway */
3114 }
3115
3116 heap_freetuple(reltup);
3118}
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1556
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91

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

2244{
2245 int numchecks = 0;
2246 ListCell *lc;
2247
2248 if (cooked_constraints == NIL)
2249 return; /* nothing to do */
2250
2251 /*
2252 * Deparsing of constraint expressions will fail unless the just-created
2253 * pg_attribute tuples for this relation are made visible. So, bump the
2254 * command counter. CAUTION: this will cause a relcache entry rebuild.
2255 */
2257
2258 foreach(lc, cooked_constraints)
2259 {
2261
2262 switch (con->contype)
2263 {
2264 case CONSTR_DEFAULT:
2265 con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
2266 is_internal, false);
2267 break;
2268 case CONSTR_CHECK:
2269 con->conoid =
2270 StoreRelCheck(rel, con->name, con->expr,
2271 con->is_enforced, !con->skip_validation,
2272 con->is_local, con->inhcount,
2273 con->is_no_inherit, is_internal);
2274 numchecks++;
2275 break;
2276
2277 default:
2278 elog(ERROR, "unrecognized constraint type: %d",
2279 (int) con->contype);
2280 }
2281 }
2282
2283 if (numchecks > 0)
2284 SetRelationNumChecks(rel, numchecks);
2285}
void CommandCounterIncrement(void)
Definition: xact.c:1099

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

Referenced by heap_create_with_catalog().

◆ StorePartitionBound()

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

Definition at line 3910 of file heap.c.

3911{
3912 Relation classRel;
3913 HeapTuple tuple,
3914 newtuple;
3915 Datum new_val[Natts_pg_class];
3916 bool new_null[Natts_pg_class],
3917 new_repl[Natts_pg_class];
3918 Oid defaultPartOid;
3919
3920 /* Update pg_class tuple */
3921 classRel = table_open(RelationRelationId, RowExclusiveLock);
3922 tuple = SearchSysCacheCopy1(RELOID,
3924 if (!HeapTupleIsValid(tuple))
3925 elog(ERROR, "cache lookup failed for relation %u",
3926 RelationGetRelid(rel));
3927
3928#ifdef USE_ASSERT_CHECKING
3929 {
3930 Form_pg_class classForm;
3931 bool isnull;
3932
3933 classForm = (Form_pg_class) GETSTRUCT(tuple);
3934 Assert(!classForm->relispartition);
3935 (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
3936 &isnull);
3937 Assert(isnull);
3938 }
3939#endif
3940
3941 /* Fill in relpartbound value */
3942 memset(new_val, 0, sizeof(new_val));
3943 memset(new_null, false, sizeof(new_null));
3944 memset(new_repl, false, sizeof(new_repl));
3945 new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
3946 new_null[Anum_pg_class_relpartbound - 1] = false;
3947 new_repl[Anum_pg_class_relpartbound - 1] = true;
3948 newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
3949 new_val, new_null, new_repl);
3950 /* Also set the flag */
3951 ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
3952
3953 /*
3954 * We already checked for no inheritance children, but reset
3955 * relhassubclass in case it was left over.
3956 */
3957 if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
3958 ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
3959
3960 CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
3961 heap_freetuple(newtuple);
3962 table_close(classRel, RowExclusiveLock);
3963
3964 /*
3965 * If we're storing bounds for the default partition, update
3966 * pg_partitioned_table too.
3967 */
3968 if (bound->is_default)
3970 RelationGetRelid(rel));
3971
3972 /* Make these updates visible */
3974
3975 /*
3976 * The partition constraint for the default partition depends on the
3977 * partition bounds of every other partition, so we must invalidate the
3978 * relcache entry for that partition every time a partition is added or
3979 * removed.
3980 */
3981 defaultPartOid =
3983 if (OidIsValid(defaultPartOid))
3984 CacheInvalidateRelcacheByRelid(defaultPartOid);
3985
3987}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:501
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600

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

Referenced by ATExecAttachPartition(), and DefineRelation().

◆ StorePartitionKey()

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

Definition at line 3754 of file heap.c.

3761{
3762 int i;
3763 int2vector *partattrs_vec;
3764 oidvector *partopclass_vec;
3765 oidvector *partcollation_vec;
3766 Datum partexprDatum;
3767 Relation pg_partitioned_table;
3768 HeapTuple tuple;
3769 Datum values[Natts_pg_partitioned_table];
3770 bool nulls[Natts_pg_partitioned_table] = {0};
3771 ObjectAddress myself;
3772 ObjectAddress referenced;
3773 ObjectAddresses *addrs;
3774
3775 Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3776
3777 /* Copy the partition attribute numbers, opclass OIDs into arrays */
3778 partattrs_vec = buildint2vector(partattrs, partnatts);
3779 partopclass_vec = buildoidvector(partopclass, partnatts);
3780 partcollation_vec = buildoidvector(partcollation, partnatts);
3781
3782 /* Convert the expressions (if any) to a text datum */
3783 if (partexprs)
3784 {
3785 char *exprString;
3786
3787 exprString = nodeToString(partexprs);
3788 partexprDatum = CStringGetTextDatum(exprString);
3789 pfree(exprString);
3790 }
3791 else
3792 partexprDatum = (Datum) 0;
3793
3794 pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3795
3796 /* Only this can ever be NULL */
3797 if (!partexprDatum)
3798 nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3799
3800 values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3801 values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3802 values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3803 values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3804 values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3805 values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3806 values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3807 values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3808
3809 tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3810
3811 CatalogTupleInsert(pg_partitioned_table, tuple);
3812 table_close(pg_partitioned_table, RowExclusiveLock);
3813
3814 /* Mark this relation as dependent on a few things as follows */
3815 addrs = new_object_addresses();
3816 ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3817
3818 /* Operator class and collation per key column */
3819 for (i = 0; i < partnatts; i++)
3820 {
3821 ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3822 add_exact_object_address(&referenced, addrs);
3823
3824 /* The default collation is pinned, so don't bother recording it */
3825 if (OidIsValid(partcollation[i]) &&
3826 partcollation[i] != DEFAULT_COLLATION_OID)
3827 {
3828 ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3829 add_exact_object_address(&referenced, addrs);
3830 }
3831 }
3832
3834 free_object_addresses(addrs);
3835
3836 /*
3837 * The partitioning columns are made internally dependent on the table,
3838 * because we cannot drop any of them without dropping the whole table.
3839 * (ATExecDropColumn independently enforces that, but it's not bulletproof
3840 * so we need the dependencies too.)
3841 */
3842 for (i = 0; i < partnatts; i++)
3843 {
3844 if (partattrs[i] == 0)
3845 continue; /* ignore expressions here */
3846
3847 ObjectAddressSubSet(referenced, RelationRelationId,
3848 RelationGetRelid(rel), partattrs[i]);
3849 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3850 }
3851
3852 /*
3853 * Also consider anything mentioned in partition expressions. External
3854 * references (e.g. functions) get NORMAL dependencies. Table columns
3855 * mentioned in the expressions are handled the same as plain partitioning
3856 * columns, i.e. they become internally dependent on the whole table.
3857 */
3858 if (partexprs)
3860 (Node *) partexprs,
3861 RelationGetRelid(rel),
3864 true /* reverse the self-deps */ );
3865
3866 /*
3867 * We must invalidate the relcache so that the next
3868 * CommandCounterIncrement() will cause the same to be rebuilt using the
3869 * information in just created catalog entry.
3870 */
3872}
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
Definition: c.h:672
Definition: c.h:683

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_enforced,
bool  is_validated,
bool  is_local,
int16  inhcount,
bool  is_no_inherit,
bool  is_internal 
)
static

Definition at line 2080 of file heap.c.

2083{
2084 char *ccbin;
2085 List *varList;
2086 int keycount;
2087 int16 *attNos;
2088 Oid constrOid;
2089
2090 /*
2091 * Flatten expression to string form for storage.
2092 */
2093 ccbin = nodeToString(expr);
2094
2095 /*
2096 * Find columns of rel that are used in expr
2097 *
2098 * NB: pull_var_clause is okay here only because we don't allow subselects
2099 * in check constraints; it would fail to examine the contents of
2100 * subselects.
2101 */
2102 varList = pull_var_clause(expr, 0);
2103 keycount = list_length(varList);
2104
2105 if (keycount > 0)
2106 {
2107 ListCell *vl;
2108 int i = 0;
2109
2110 attNos = (int16 *) palloc(keycount * sizeof(int16));
2111 foreach(vl, varList)
2112 {
2113 Var *var = (Var *) lfirst(vl);
2114 int j;
2115
2116 for (j = 0; j < i; j++)
2117 if (attNos[j] == var->varattno)
2118 break;
2119 if (j == i)
2120 attNos[i++] = var->varattno;
2121 }
2122 keycount = i;
2123 }
2124 else
2125 attNos = NULL;
2126
2127 /*
2128 * Partitioned tables do not contain any rows themselves, so a NO INHERIT
2129 * constraint makes no sense.
2130 */
2131 if (is_no_inherit &&
2132 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2133 ereport(ERROR,
2134 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2135 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
2137
2138 /*
2139 * Create the Check Constraint
2140 */
2141 constrOid =
2142 CreateConstraintEntry(ccname, /* Constraint Name */
2143 RelationGetNamespace(rel), /* namespace */
2144 CONSTRAINT_CHECK, /* Constraint Type */
2145 false, /* Is Deferrable */
2146 false, /* Is Deferred */
2147 is_enforced, /* Is Enforced */
2148 is_validated,
2149 InvalidOid, /* no parent constraint */
2150 RelationGetRelid(rel), /* relation */
2151 attNos, /* attrs in the constraint */
2152 keycount, /* # key attrs in the constraint */
2153 keycount, /* # total attrs in the constraint */
2154 InvalidOid, /* not a domain constraint */
2155 InvalidOid, /* no associated index */
2156 InvalidOid, /* Foreign key fields */
2157 NULL,
2158 NULL,
2159 NULL,
2160 NULL,
2161 0,
2162 ' ',
2163 ' ',
2164 NULL,
2165 0,
2166 ' ',
2167 NULL, /* not an exclusion constraint */
2168 expr, /* Tree form of check constraint */
2169 ccbin, /* Binary form of check constraint */
2170 is_local, /* conislocal */
2171 inhcount, /* coninhcount */
2172 is_no_inherit, /* connoinherit */
2173 false, /* conperiod */
2174 is_internal); /* internally constructed? */
2175
2176 pfree(ccbin);
2177
2178 return constrOid;
2179}
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, 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, int16 conInhCount, bool conNoInherit, bool conPeriod, 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 2187 of file heap.c.

2190{
2191 Oid constrOid;
2192
2194
2195 constrOid =
2196 CreateConstraintEntry(nnname,
2198 CONSTRAINT_NOTNULL,
2199 false,
2200 false,
2201 true, /* Is Enforced */
2202 is_validated,
2203 InvalidOid,
2204 RelationGetRelid(rel),
2205 &attnum,
2206 1,
2207 1,
2208 InvalidOid, /* not a domain constraint */
2209 InvalidOid, /* no associated index */
2210 InvalidOid, /* Foreign key fields */
2211 NULL,
2212 NULL,
2213 NULL,
2214 NULL,
2215 0,
2216 ' ',
2217 ' ',
2218 NULL,
2219 0,
2220 ' ',
2221 NULL, /* not an exclusion constraint */
2222 NULL,
2223 NULL,
2224 is_local,
2225 inhcount,
2226 is_no_inherit,
2227 false,
2228 false);
2229 return constrOid;
2230}

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

Referenced by AddRelationNewConstraints(), and AddRelationNotNullConstraints().

◆ SystemAttributeByName()

const FormData_pg_attribute * SystemAttributeByName ( const char *  attname)

Definition at line 247 of file heap.c.

248{
249 int j;
250
251 for (j = 0; j < (int) lengthof(SysAtt); j++)
252 {
253 const FormData_pg_attribute *att = SysAtt[j];
254
255 if (strcmp(NameStr(att->attname), attname) == 0)
256 return att;
257 }
258
259 return NULL;
260}

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

236{
237 if (attno >= 0 || attno < -(int) lengthof(SysAtt))
238 elog(ERROR, "invalid system attribute number %d", attno);
239 return SysAtt[-attno - 1];
240}

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),
.atttypmod = -1,
.attbyval = false,
.attalign = TYPALIGN_SHORT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
struct ItemPointerData ItemPointerData
char attstorage
Definition: pg_attribute.h:108
bool attbyval
Definition: pg_attribute.h:94
char attalign
Definition: pg_attribute.h:100
bool attnotnull
Definition: pg_attribute.h:121
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

Definition at line 143 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),
.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),
.atttypmod = -1,
.attbyval = true,
.attalign = TYPALIGN_INT,
.attstorage = TYPSTORAGE_PLAIN,
.attnotnull = true,
.attislocal = true,
}
uint32 CommandId
Definition: c.h:623
#define MinCommandIdAttributeNumber
Definition: sysattr.h:23

Definition at line 169 of file heap.c.

◆ a4

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

Definition at line 182 of file heap.c.

◆ a5

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

Definition at line 195 of file heap.c.

◆ a6

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

Definition at line 214 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 227 of file heap.c.

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