Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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/array.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 StoreAttrMissingVal (Relation rel, AttrNumber attnum, Datum missingval)
 
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)
 
static bool contains_user_functions_checker (Oid func_id, void *context)
 
static bool check_virtual_generated_security_walker (Node *node, void *context)
 
static void check_virtual_generated_security (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 834 of file heap.c.

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

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

995{
996 Form_pg_class new_rel_reltup;
997
998 /*
999 * first we update some of the information in our uncataloged relation's
1000 * relation descriptor.
1001 */
1002 new_rel_reltup = new_rel_desc->rd_rel;
1003
1004 /* The relation is empty */
1005 new_rel_reltup->relpages = 0;
1006 new_rel_reltup->reltuples = -1;
1007 new_rel_reltup->relallvisible = 0;
1008 new_rel_reltup->relallfrozen = 0;
1009
1010 /* Sequences always have a known size */
1011 if (relkind == RELKIND_SEQUENCE)
1012 {
1013 new_rel_reltup->relpages = 1;
1014 new_rel_reltup->reltuples = 1;
1015 }
1016
1017 new_rel_reltup->relfrozenxid = relfrozenxid;
1018 new_rel_reltup->relminmxid = relminmxid;
1019 new_rel_reltup->relowner = relowner;
1020 new_rel_reltup->reltype = new_type_oid;
1021 new_rel_reltup->reloftype = reloftype;
1022
1023 /* relispartition is always set by updating this tuple later */
1024 new_rel_reltup->relispartition = false;
1025
1026 /* fill rd_att's type ID with something sane even if reltype is zero */
1027 new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
1028 new_rel_desc->rd_att->tdtypmod = -1;
1029
1030 /* Now build and insert the tuple */
1031 InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
1032 relacl, reloptions);
1033}
void InsertPgClassTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Definition: heap.c:910
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138

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

1050{
1051 return
1052 TypeCreate(new_row_type, /* optional predetermined OID */
1053 typeName, /* type name */
1054 typeNamespace, /* type namespace */
1055 new_rel_oid, /* relation oid */
1056 new_rel_kind, /* relation kind */
1057 ownerid, /* owner's ID */
1058 -1, /* internal size (varlena) */
1059 TYPTYPE_COMPOSITE, /* type-type (composite) */
1060 TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
1061 false, /* composite types are never preferred */
1062 DEFAULT_TYPDELIM, /* default array delimiter */
1063 F_RECORD_IN, /* input procedure */
1064 F_RECORD_OUT, /* output procedure */
1065 F_RECORD_RECV, /* receive procedure */
1066 F_RECORD_SEND, /* send procedure */
1067 InvalidOid, /* typmodin procedure - none */
1068 InvalidOid, /* typmodout procedure - none */
1069 InvalidOid, /* analyze procedure - default */
1070 InvalidOid, /* subscript procedure - none */
1071 InvalidOid, /* array element type - irrelevant */
1072 false, /* this is not an array type */
1073 new_array_type, /* array type if any */
1074 InvalidOid, /* domain base type - irrelevant */
1075 NULL, /* default value - none */
1076 NULL, /* default binary representation */
1077 false, /* passed by reference */
1078 TYPALIGN_DOUBLE, /* alignment - must be the largest! */
1079 TYPSTORAGE_EXTENDED, /* fully TOASTable */
1080 -1, /* typmod */
1081 0, /* array dimensions for typBaseType */
1082 false, /* Type NOT NULL */
1083 InvalidOid); /* rowtypes never have a collation */
1084}
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 2385 of file heap.c.

2392{
2393 List *cookedConstraints = NIL;
2394 TupleDesc tupleDesc;
2395 TupleConstr *oldconstr;
2396 int numoldchecks;
2397 ParseState *pstate;
2398 ParseNamespaceItem *nsitem;
2399 int numchecks;
2400 List *checknames;
2401 List *nnnames;
2402 Node *expr;
2403 CookedConstraint *cooked;
2404
2405 /*
2406 * Get info about existing constraints.
2407 */
2408 tupleDesc = RelationGetDescr(rel);
2409 oldconstr = tupleDesc->constr;
2410 if (oldconstr)
2411 numoldchecks = oldconstr->num_check;
2412 else
2413 numoldchecks = 0;
2414
2415 /*
2416 * Create a dummy ParseState and insert the target relation as its sole
2417 * rangetable entry. We need a ParseState for transformExpr.
2418 */
2419 pstate = make_parsestate(NULL);
2420 pstate->p_sourcetext = queryString;
2421 nsitem = addRangeTableEntryForRelation(pstate,
2422 rel,
2424 NULL,
2425 false,
2426 true);
2427 addNSItemToQuery(pstate, nsitem, true, true, true);
2428
2429 /*
2430 * Process column default expressions.
2431 */
2432 foreach_ptr(RawColumnDefault, colDef, newColDefaults)
2433 {
2434 Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
2435 Oid defOid;
2436
2437 expr = cookDefault(pstate, colDef->raw_default,
2438 atp->atttypid, atp->atttypmod,
2439 NameStr(atp->attname),
2440 atp->attgenerated);
2441
2442 /*
2443 * If the expression is just a NULL constant, we do not bother to make
2444 * an explicit pg_attrdef entry, since the default behavior is
2445 * equivalent. This applies to column defaults, but not for
2446 * generation expressions.
2447 *
2448 * Note a nonobvious property of this test: if the column is of a
2449 * domain type, what we'll get is not a bare null Const but a
2450 * CoerceToDomain expr, so we will not discard the default. This is
2451 * critical because the column default needs to be retained to
2452 * override any default that the domain might have.
2453 */
2454 if (expr == NULL ||
2455 (!colDef->generated &&
2456 IsA(expr, Const) &&
2457 castNode(Const, expr)->constisnull))
2458 continue;
2459
2460 defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal);
2461
2462 cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2463 cooked->contype = CONSTR_DEFAULT;
2464 cooked->conoid = defOid;
2465 cooked->name = NULL;
2466 cooked->attnum = colDef->attnum;
2467 cooked->expr = expr;
2468 cooked->is_enforced = true;
2469 cooked->skip_validation = false;
2470 cooked->is_local = is_local;
2471 cooked->inhcount = is_local ? 0 : 1;
2472 cooked->is_no_inherit = false;
2473 cookedConstraints = lappend(cookedConstraints, cooked);
2474 }
2475
2476 /*
2477 * Process constraint expressions.
2478 */
2479 numchecks = numoldchecks;
2480 checknames = NIL;
2481 nnnames = NIL;
2482 foreach_node(Constraint, cdef, newConstraints)
2483 {
2484 Oid constrOid;
2485
2486 if (cdef->contype == CONSTR_CHECK)
2487 {
2488 char *ccname;
2489
2490 if (cdef->raw_expr != NULL)
2491 {
2492 Assert(cdef->cooked_expr == NULL);
2493
2494 /*
2495 * Transform raw parsetree to executable expression, and
2496 * verify it's valid as a CHECK constraint.
2497 */
2498 expr = cookConstraint(pstate, cdef->raw_expr,
2500 }
2501 else
2502 {
2503 Assert(cdef->cooked_expr != NULL);
2504
2505 /*
2506 * Here, we assume the parser will only pass us valid CHECK
2507 * expressions, so we do no particular checking.
2508 */
2509 expr = stringToNode(cdef->cooked_expr);
2510 }
2511
2512 /*
2513 * Check name uniqueness, or generate a name if none was given.
2514 */
2515 if (cdef->conname != NULL)
2516 {
2517 ccname = cdef->conname;
2518 /* Check against other new constraints */
2519 /* Needed because we don't do CommandCounterIncrement in loop */
2520 foreach_ptr(char, chkname, checknames)
2521 {
2522 if (strcmp(chkname, ccname) == 0)
2523 ereport(ERROR,
2525 errmsg("check constraint \"%s\" already exists",
2526 ccname)));
2527 }
2528
2529 /* save name for future checks */
2530 checknames = lappend(checknames, ccname);
2531
2532 /*
2533 * Check against pre-existing constraints. If we are allowed
2534 * to merge with an existing constraint, there's no more to do
2535 * here. (We omit the duplicate constraint from the result,
2536 * which is what ATAddCheckNNConstraint wants.)
2537 */
2538 if (MergeWithExistingConstraint(rel, ccname, expr,
2539 allow_merge, is_local,
2540 cdef->is_enforced,
2541 cdef->initially_valid,
2542 cdef->is_no_inherit))
2543 continue;
2544 }
2545 else
2546 {
2547 /*
2548 * When generating a name, we want to create "tab_col_check"
2549 * for a column constraint and "tab_check" for a table
2550 * constraint. We no longer have any info about the syntactic
2551 * positioning of the constraint phrase, so we approximate
2552 * this by seeing whether the expression references more than
2553 * one column. (If the user played by the rules, the result
2554 * is the same...)
2555 *
2556 * Note: pull_var_clause() doesn't descend into sublinks, but
2557 * we eliminated those above; and anyway this only needs to be
2558 * an approximate answer.
2559 */
2560 List *vars;
2561 char *colname;
2562
2563 vars = pull_var_clause(expr, 0);
2564
2565 /* eliminate duplicates */
2566 vars = list_union(NIL, vars);
2567
2568 if (list_length(vars) == 1)
2569 colname = get_attname(RelationGetRelid(rel),
2570 ((Var *) linitial(vars))->varattno,
2571 true);
2572 else
2573 colname = NULL;
2574
2576 colname,
2577 "check",
2579 checknames);
2580
2581 /* save name for future checks */
2582 checknames = lappend(checknames, ccname);
2583 }
2584
2585 /*
2586 * OK, store it.
2587 */
2588 constrOid =
2589 StoreRelCheck(rel, ccname, expr, cdef->is_enforced,
2590 cdef->initially_valid, is_local,
2591 is_local ? 0 : 1, cdef->is_no_inherit,
2592 is_internal);
2593
2594 numchecks++;
2595
2596 cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2597 cooked->contype = CONSTR_CHECK;
2598 cooked->conoid = constrOid;
2599 cooked->name = ccname;
2600 cooked->attnum = 0;
2601 cooked->expr = expr;
2602 cooked->is_enforced = cdef->is_enforced;
2603 cooked->skip_validation = cdef->skip_validation;
2604 cooked->is_local = is_local;
2605 cooked->inhcount = is_local ? 0 : 1;
2606 cooked->is_no_inherit = cdef->is_no_inherit;
2607 cookedConstraints = lappend(cookedConstraints, cooked);
2608 }
2609 else if (cdef->contype == CONSTR_NOTNULL)
2610 {
2611 CookedConstraint *nncooked;
2612 AttrNumber colnum;
2613 int16 inhcount = is_local ? 0 : 1;
2614 char *nnname;
2615
2616 /* Determine which column to modify */
2617 colnum = get_attnum(RelationGetRelid(rel), strVal(linitial(cdef->keys)));
2618 if (colnum == InvalidAttrNumber)
2619 ereport(ERROR,
2620 errcode(ERRCODE_UNDEFINED_COLUMN),
2621 errmsg("column \"%s\" of relation \"%s\" does not exist",
2622 strVal(linitial(cdef->keys)), RelationGetRelationName(rel)));
2623 if (colnum < InvalidAttrNumber)
2624 ereport(ERROR,
2625 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2626 errmsg("cannot add not-null constraint on system column \"%s\"",
2627 strVal(linitial(cdef->keys))));
2628
2629 Assert(cdef->initially_valid != cdef->skip_validation);
2630
2631 /*
2632 * If the column already has a not-null constraint, we don't want
2633 * to add another one; adjust inheritance status as needed. This
2634 * also checks whether the existing constraint matches the
2635 * requested validity.
2636 */
2638 is_local, cdef->is_no_inherit,
2639 cdef->skip_validation))
2640 continue;
2641
2642 /*
2643 * If a constraint name is specified, check that it isn't already
2644 * used. Otherwise, choose a non-conflicting one ourselves.
2645 */
2646 if (cdef->conname)
2647 {
2649 RelationGetRelid(rel),
2650 cdef->conname))
2651 ereport(ERROR,
2653 errmsg("constraint \"%s\" for relation \"%s\" already exists",
2654 cdef->conname, RelationGetRelationName(rel)));
2655 nnname = cdef->conname;
2656 }
2657 else
2659 strVal(linitial(cdef->keys)),
2660 "not_null",
2662 nnnames);
2663 nnnames = lappend(nnnames, nnname);
2664
2665 constrOid =
2666 StoreRelNotNull(rel, nnname, colnum,
2667 cdef->initially_valid,
2668 is_local,
2669 inhcount,
2670 cdef->is_no_inherit);
2671
2672 nncooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
2673 nncooked->contype = CONSTR_NOTNULL;
2674 nncooked->conoid = constrOid;
2675 nncooked->name = nnname;
2676 nncooked->attnum = colnum;
2677 nncooked->expr = NULL;
2678 nncooked->is_enforced = true;
2679 nncooked->skip_validation = cdef->skip_validation;
2680 nncooked->is_local = is_local;
2681 nncooked->inhcount = inhcount;
2682 nncooked->is_no_inherit = cdef->is_no_inherit;
2683
2684 cookedConstraints = lappend(cookedConstraints, nncooked);
2685 }
2686 }
2687
2688 /*
2689 * Update the count of constraints in the relation's pg_class tuple. We do
2690 * this even if there was no change, in order to ensure that an SI update
2691 * message is sent out for the pg_class tuple, which will force other
2692 * backends to rebuild their relcache entries for the rel. (This is
2693 * critical if we added defaults but not constraints.)
2694 */
2695 SetRelationNumChecks(rel, numchecks);
2696
2697 return cookedConstraints;
2698}
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define NameStr(name)
Definition: c.h:752
int16_t int16
Definition: c.h:534
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
Assert(PointerIsAligned(start, uint64))
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:2147
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:2711
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:2254
static void SetRelationNumChecks(Relation rel, int numchecks)
Definition: heap.c:3146
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3320
static Node * cookConstraint(ParseState *pstate, Node *raw_constraint, char *relname)
Definition: heap.c:3401
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:951
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:920
void * palloc(Size size)
Definition: mcxt.c:1365
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
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:2801
@ CONSTR_NOTNULL
Definition: parsenodes.h:2800
@ CONSTR_CHECK
Definition: parsenodes.h:2804
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal)
Definition: pg_attrdef.c:35
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, bool is_notvalid)
@ 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:514
#define RelationGetDescr(relation)
Definition: rel.h:540
#define RelationGetRelationName(relation)
Definition: rel.h:548
#define RelationGetNamespace(relation)
Definition: rel.h:555
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:44
bool is_enforced
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:47
int16 inhcount
Definition: heap.h:46
bool is_local
Definition: heap.h:45
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
Definition: pg_list.h:54
Definition: nodes.h:135
const char * p_sourcetext
Definition: parse_node.h:195
uint16 num_check
Definition: tupdesc.h:44
TupleConstr * constr
Definition: tupdesc.h:141
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(), CookedConstraint::contype, cookConstraint(), cookDefault(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CookedConstraint::expr, foreach_node, foreach_ptr, get_attname(), get_attnum(), CookedConstraint::inhcount, InvalidAttrNumber, CookedConstraint::is_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 2894 of file heap.c.

2896{
2897 List *givennames;
2898 List *nnnames;
2899 List *nncols = NIL;
2900
2901 /*
2902 * We track two lists of names: nnnames keeps all the constraint names,
2903 * givennames tracks user-generated names. The distinction is important,
2904 * because we must raise error for user-generated name conflicts, but for
2905 * system-generated name conflicts we just generate another.
2906 */
2907 nnnames = NIL;
2908 givennames = NIL;
2909
2910 /*
2911 * First, create all not-null constraints that are directly specified by
2912 * the user. Note that inheritance might have given us another source for
2913 * each, so we must scan the old_notnulls list and increment inhcount for
2914 * each element with identical attnum. We delete from there any element
2915 * that we process.
2916 *
2917 * We don't use foreach() here because we have two nested loops over the
2918 * constraint list, with possible element deletions in the inner one. If
2919 * we used foreach_delete_current() it could only fix up the state of one
2920 * of the loops, so it seems cleaner to use looping over list indexes for
2921 * both loops. Note that any deletion will happen beyond where the outer
2922 * loop is, so its index never needs adjustment.
2923 */
2924 for (int outerpos = 0; outerpos < list_length(constraints); outerpos++)
2925 {
2926 Constraint *constr;
2928 char *conname;
2929 int inhcount = 0;
2930
2931 constr = list_nth_node(Constraint, constraints, outerpos);
2932
2933 Assert(constr->contype == CONSTR_NOTNULL);
2934
2936 strVal(linitial(constr->keys)));
2938 ereport(ERROR,
2939 errcode(ERRCODE_UNDEFINED_COLUMN),
2940 errmsg("column \"%s\" of relation \"%s\" does not exist",
2941 strVal(linitial(constr->keys)),
2944 ereport(ERROR,
2945 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2946 errmsg("cannot add not-null constraint on system column \"%s\"",
2947 strVal(linitial(constr->keys))));
2948
2949 /*
2950 * A column can only have one not-null constraint, so discard any
2951 * additional ones that appear for columns we already saw; but check
2952 * that the NO INHERIT flags match.
2953 */
2954 for (int restpos = outerpos + 1; restpos < list_length(constraints);)
2955 {
2956 Constraint *other;
2957
2958 other = list_nth_node(Constraint, constraints, restpos);
2959 if (strcmp(strVal(linitial(constr->keys)),
2960 strVal(linitial(other->keys))) == 0)
2961 {
2962 if (other->is_no_inherit != constr->is_no_inherit)
2963 ereport(ERROR,
2964 errcode(ERRCODE_SYNTAX_ERROR),
2965 errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
2966 strVal(linitial(constr->keys))));
2967
2968 /*
2969 * Preserve constraint name if one is specified, but raise an
2970 * error if conflicting ones are specified.
2971 */
2972 if (other->conname)
2973 {
2974 if (!constr->conname)
2975 constr->conname = pstrdup(other->conname);
2976 else if (strcmp(constr->conname, other->conname) != 0)
2977 ereport(ERROR,
2978 errcode(ERRCODE_SYNTAX_ERROR),
2979 errmsg("conflicting not-null constraint names \"%s\" and \"%s\"",
2980 constr->conname, other->conname));
2981 }
2982
2983 /* XXX do we need to verify any other fields? */
2984 constraints = list_delete_nth_cell(constraints, restpos);
2985 }
2986 else
2987 restpos++;
2988 }
2989
2990 /*
2991 * Search in the list of inherited constraints for any entries on the
2992 * same column; determine an inheritance count from that. Also, if at
2993 * least one parent has a constraint for this column, then we must not
2994 * accept a user specification for a NO INHERIT one. Any constraint
2995 * from parents that we process here is deleted from the list: we no
2996 * longer need to process it in the loop below.
2997 */
2998 foreach_ptr(CookedConstraint, old, old_notnulls)
2999 {
3000 if (old->attnum == attnum)
3001 {
3002 /*
3003 * If we get a constraint from the parent, having a local NO
3004 * INHERIT one doesn't work.
3005 */
3006 if (constr->is_no_inherit)
3007 ereport(ERROR,
3008 (errcode(ERRCODE_DATATYPE_MISMATCH),
3009 errmsg("cannot define not-null constraint with NO INHERIT on column \"%s\"",
3010 strVal(linitial(constr->keys))),
3011 errdetail("The column has an inherited not-null constraint.")));
3012
3013 inhcount++;
3014 old_notnulls = foreach_delete_current(old_notnulls, old);
3015 }
3016 }
3017
3018 /*
3019 * Determine a constraint name, which may have been specified by the
3020 * user, or raise an error if a conflict exists with another
3021 * user-specified name.
3022 */
3023 if (constr->conname)
3024 {
3025 foreach_ptr(char, thisname, givennames)
3026 {
3027 if (strcmp(thisname, constr->conname) == 0)
3028 ereport(ERROR,
3030 errmsg("constraint \"%s\" for relation \"%s\" already exists",
3031 constr->conname,
3033 }
3034
3035 conname = constr->conname;
3036 givennames = lappend(givennames, conname);
3037 }
3038 else
3041 attnum, false),
3042 "not_null",
3044 nnnames);
3045 nnnames = lappend(nnnames, conname);
3046
3047 StoreRelNotNull(rel, conname,
3048 attnum, true, true,
3049 inhcount, constr->is_no_inherit);
3050
3051 nncols = lappend_int(nncols, attnum);
3052 }
3053
3054 /*
3055 * If any column remains in the old_notnulls list, we must create a not-
3056 * null constraint marked not-local for that column. Because multiple
3057 * parents could specify a not-null constraint for the same column, we
3058 * must count how many there are and set an appropriate inhcount
3059 * accordingly, deleting elements we've already processed.
3060 *
3061 * We don't use foreach() here because we have two nested loops over the
3062 * constraint list, with possible element deletions in the inner one. If
3063 * we used foreach_delete_current() it could only fix up the state of one
3064 * of the loops, so it seems cleaner to use looping over list indexes for
3065 * both loops. Note that any deletion will happen beyond where the outer
3066 * loop is, so its index never needs adjustment.
3067 */
3068 for (int outerpos = 0; outerpos < list_length(old_notnulls); outerpos++)
3069 {
3070 CookedConstraint *cooked;
3071 char *conname = NULL;
3072 int inhcount = 1;
3073
3074 cooked = (CookedConstraint *) list_nth(old_notnulls, outerpos);
3075 Assert(cooked->contype == CONSTR_NOTNULL);
3076 Assert(cooked->name);
3077
3078 /*
3079 * Preserve the first non-conflicting constraint name we come across.
3080 */
3081 if (conname == NULL)
3082 conname = cooked->name;
3083
3084 for (int restpos = outerpos + 1; restpos < list_length(old_notnulls);)
3085 {
3086 CookedConstraint *other;
3087
3088 other = (CookedConstraint *) list_nth(old_notnulls, restpos);
3089 Assert(other->name);
3090 if (other->attnum == cooked->attnum)
3091 {
3092 if (conname == NULL)
3093 conname = other->name;
3094
3095 inhcount++;
3096 old_notnulls = list_delete_nth_cell(old_notnulls, restpos);
3097 }
3098 else
3099 restpos++;
3100 }
3101
3102 /* If we got a name, make sure it isn't one we've already used */
3103 if (conname != NULL)
3104 {
3105 foreach_ptr(char, thisname, nnnames)
3106 {
3107 if (strcmp(thisname, conname) == 0)
3108 {
3109 conname = NULL;
3110 break;
3111 }
3112 }
3113 }
3114
3115 /* and choose a name, if needed */
3116 if (conname == NULL)
3119 cooked->attnum, false),
3120 "not_null",
3122 nnnames);
3123 nnnames = lappend(nnnames, conname);
3124
3125 /* ignore the origin constraint's is_local and inhcount */
3126 StoreRelNotNull(rel, conname, cooked->attnum, true,
3127 false, inhcount, false);
3128
3129 nncols = lappend_int(nncols, cooked->attnum);
3130 }
3131
3132 return nncols;
3133}
int errdetail(const char *fmt,...)
Definition: elog.c:1207
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:1759
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:2847
ConstrType contype
Definition: parsenodes.h:2832
bool is_no_inherit
Definition: parsenodes.h:2839
char * conname
Definition: parsenodes.h:2833

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

Referenced by DefineRelation().

◆ check_nested_generated()

static void check_nested_generated ( ParseState pstate,
Node node 
)
static

Definition at line 3222 of file heap.c.

3223{
3224 check_nested_generated_walker(node, pstate);
3225}
static bool check_nested_generated_walker(Node *node, void *context)
Definition: heap.c:3180

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

3181{
3182 ParseState *pstate = context;
3183
3184 if (node == NULL)
3185 return false;
3186 else if (IsA(node, Var))
3187 {
3188 Var *var = (Var *) node;
3189 Oid relid;
3191
3192 relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
3193 if (!OidIsValid(relid))
3194 return false; /* XXX shouldn't we raise an error? */
3195
3196 attnum = var->varattno;
3197
3198 if (attnum > 0 && get_attgenerated(relid, attnum))
3199 ereport(ERROR,
3200 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3201 errmsg("cannot use generated column \"%s\" in column generation expression",
3202 get_attname(relid, attnum, false)),
3203 errdetail("A generated column cannot reference another generated column."),
3204 parser_errposition(pstate, var->location)));
3205 /* A whole-row Var is necessarily self-referential, so forbid it */
3206 if (attnum == 0)
3207 ereport(ERROR,
3208 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3209 errmsg("cannot use whole-row variable in column generation expression"),
3210 errdetail("This would cause the generated column to depend on its own value."),
3211 parser_errposition(pstate, var->location)));
3212 /* System columns were already checked in the parser */
3213
3214 return false;
3215 }
3216 else
3218 context);
3219}
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:981
#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:196
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().

◆ check_virtual_generated_security()

static void check_virtual_generated_security ( ParseState pstate,
Node node 
)
static

Definition at line 3302 of file heap.c.

3303{
3305}
static bool check_virtual_generated_security_walker(Node *node, void *context)
Definition: heap.c:3265

References check_virtual_generated_security_walker().

Referenced by cookDefault().

◆ check_virtual_generated_security_walker()

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

Definition at line 3265 of file heap.c.

3266{
3267 ParseState *pstate = context;
3268
3269 if (node == NULL)
3270 return false;
3271
3272 if (!IsA(node, List))
3273 {
3275 ereport(ERROR,
3276 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3277 errmsg("generation expression uses user-defined function"),
3278 errdetail("Virtual generated columns that make use of user-defined functions are not yet supported."),
3279 parser_errposition(pstate, exprLocation(node)));
3280
3281 /*
3282 * check_functions_in_node() doesn't check some node types (see
3283 * comment there). We handle CoerceToDomain and MinMaxExpr by
3284 * checking for built-in types. The other listed node types cannot
3285 * call user-definable SQL-visible functions.
3286 *
3287 * We furthermore need this type check to handle built-in, immutable
3288 * polymorphic functions such as array_eq().
3289 */
3290 if (exprType(node) >= FirstUnpinnedObjectId)
3291 ereport(ERROR,
3292 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3293 errmsg("generation expression uses user-defined type"),
3294 errdetail("Virtual generated columns that make use of user-defined types are not yet supported."),
3295 parser_errposition(pstate, exprLocation(node)));
3296 }
3297
3299}
static bool contains_user_functions_checker(Oid func_id, void *context)
Definition: heap.c:3254
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
bool check_functions_in_node(Node *node, check_function_callback checker, void *context)
Definition: nodeFuncs.c:1910
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1388
#define FirstUnpinnedObjectId
Definition: transam.h:196

References check_functions_in_node(), check_virtual_generated_security_walker(), contains_user_functions_checker(), ereport, errcode(), errdetail(), errmsg(), ERROR, expression_tree_walker, exprLocation(), exprType(), FirstUnpinnedObjectId, IsA, and parser_errposition().

Referenced by check_virtual_generated_security(), and check_virtual_generated_security_walker().

◆ CheckAttributeNamesTypes()

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

Definition at line 452 of file heap.c.

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

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

◆ contains_user_functions_checker()

static bool contains_user_functions_checker ( Oid  func_id,
void *  context 
)
static

Definition at line 3254 of file heap.c.

3255{
3256 return (func_id >= FirstUnpinnedObjectId);
3257}

References FirstUnpinnedObjectId.

Referenced by check_virtual_generated_security_walker().

◆ cookConstraint()

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

Definition at line 3401 of file heap.c.

3404{
3405 Node *expr;
3406
3407 /*
3408 * Transform raw parsetree to executable expression.
3409 */
3410 expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
3411
3412 /*
3413 * Make sure it yields a boolean result.
3414 */
3415 expr = coerce_to_boolean(pstate, expr, "CHECK");
3416
3417 /*
3418 * Take care of collations.
3419 */
3420 assign_expr_collations(pstate, expr);
3421
3422 /*
3423 * Make sure no outside relations are referred to (this is probably dead
3424 * code now that add_missing_from is history).
3425 */
3426 if (list_length(pstate->p_rtable) != 1)
3427 ereport(ERROR,
3428 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3429 errmsg("only table \"%s\" can be referenced in check constraint",
3430 relname)));
3431
3432 return expr;
3433}
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:117
@ 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 3320 of file heap.c.

3326{
3327 Node *expr;
3328
3329 Assert(raw_default != NULL);
3330
3331 /*
3332 * Transform raw parsetree to executable expression.
3333 */
3334 expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3335
3336 if (attgenerated)
3337 {
3338 /* Disallow refs to other generated columns */
3339 check_nested_generated(pstate, expr);
3340
3341 /* Disallow mutable functions */
3343 ereport(ERROR,
3344 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3345 errmsg("generation expression is not immutable")));
3346
3347 /* Check security of expressions for virtual generated column */
3348 if (attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
3350 }
3351 else
3352 {
3353 /*
3354 * For a default expression, transformExpr() should have rejected
3355 * column references.
3356 */
3357 Assert(!contain_var_clause(expr));
3358 }
3359
3360 /*
3361 * Coerce the expression to the correct type and typmod, if given. This
3362 * should match the parser's processing of non-defaulted expressions ---
3363 * see transformAssignedExpr().
3364 */
3365 if (OidIsValid(atttypid))
3366 {
3367 Oid type_id = exprType(expr);
3368
3369 expr = coerce_to_target_type(pstate, expr, type_id,
3370 atttypid, atttypmod,
3373 -1);
3374 if (expr == NULL)
3375 ereport(ERROR,
3376 (errcode(ERRCODE_DATATYPE_MISMATCH),
3377 errmsg("column \"%s\" is of type %s"
3378 " but default expression is of type %s",
3379 attname,
3380 format_type_be(atttypid),
3381 format_type_be(type_id)),
3382 errhint("You will need to rewrite or cast the expression.")));
3383 }
3384
3385 /*
3386 * Finally, take care of collations in the finished expression.
3387 */
3388 assign_expr_collations(pstate, expr);
3389
3390 return expr;
3391}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:494
static void check_virtual_generated_security(ParseState *pstate, Node *node)
Definition: heap.c:3302
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3222
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:755
@ COERCION_ASSIGNMENT
Definition: primnodes.h:734
bool contain_var_clause(Node *node)
Definition: var.c:406

References Assert(), assign_expr_collations(), attname, check_nested_generated(), check_virtual_generated_security(), 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 3439 of file heap.c.

3440{
3441 HeapTuple tup;
3442 SysScanDesc scan;
3443 ScanKeyData key[1];
3444 Relation statrel;
3445 CatalogIndexState indstate = NULL;
3446
3447 statrel = table_open(StatisticRelationId, RowExclusiveLock);
3448
3449 /* Now search for stat records */
3450 ScanKeyInit(&key[0],
3451 Anum_pg_statistic_starelid,
3452 BTEqualStrategyNumber, F_OIDEQ,
3453 ObjectIdGetDatum(fromrelid));
3454
3455 scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3456 true, NULL, 1, key);
3457
3458 while (HeapTupleIsValid((tup = systable_getnext(scan))))
3459 {
3460 Form_pg_statistic statform;
3461
3462 /* make a modifiable copy */
3463 tup = heap_copytuple(tup);
3464 statform = (Form_pg_statistic) GETSTRUCT(tup);
3465
3466 /* update the copy of the tuple and insert it */
3467 statform->starelid = torelid;
3468
3469 /* fetch index information when we know we need it */
3470 if (indstate == NULL)
3471 indstate = CatalogOpenIndexes(statrel);
3472
3473 CatalogTupleInsertWithInfo(statrel, tup, indstate);
3474
3475 heap_freetuple(tup);
3476 }
3477
3478 systable_endscan(scan);
3479
3480 if (indstate != NULL)
3481 CatalogCloseIndexes(indstate);
3482 table_close(statrel, RowExclusiveLock);
3483}
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
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:262
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 1605 of file heap.c.

1606{
1607 Relation attrel;
1608 SysScanDesc scan;
1609 ScanKeyData key[1];
1610 HeapTuple atttup;
1611
1612 /* Grab an appropriate lock on the pg_attribute relation */
1613 attrel = table_open(AttributeRelationId, RowExclusiveLock);
1614
1615 /* Use the index to scan only attributes of the target relation */
1616 ScanKeyInit(&key[0],
1617 Anum_pg_attribute_attrelid,
1618 BTEqualStrategyNumber, F_OIDEQ,
1619 ObjectIdGetDatum(relid));
1620
1621 scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1622 NULL, 1, key);
1623
1624 /* Delete all the matching tuples */
1625 while ((atttup = systable_getnext(scan)) != NULL)
1626 CatalogTupleDelete(attrel, &atttup->t_self);
1627
1628 /* Clean up after the scan */
1629 systable_endscan(scan);
1631}
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 1576 of file heap.c.

1577{
1578 Relation pg_class_desc;
1579 HeapTuple tup;
1580
1581 /* Grab an appropriate lock on the pg_class relation */
1582 pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
1583
1584 tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
1585 if (!HeapTupleIsValid(tup))
1586 elog(ERROR, "cache lookup failed for relation %u", relid);
1587
1588 /* delete the relation tuple from pg_class, and finish up */
1589 CatalogTupleDelete(pg_class_desc, &tup->t_self);
1590
1591 ReleaseSysCache(tup);
1592
1593 table_close(pg_class_desc, RowExclusiveLock);
1594}
#define elog(elevel,...)
Definition: elog.h:226
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

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

1643{
1644 Relation attrel;
1645 SysScanDesc scan;
1646 ScanKeyData key[2];
1647 HeapTuple atttup;
1648
1649 /* Grab an appropriate lock on the pg_attribute relation */
1650 attrel = table_open(AttributeRelationId, RowExclusiveLock);
1651
1652 /* Use the index to scan only system attributes of the target relation */
1653 ScanKeyInit(&key[0],
1654 Anum_pg_attribute_attrelid,
1655 BTEqualStrategyNumber, F_OIDEQ,
1656 ObjectIdGetDatum(relid));
1657 ScanKeyInit(&key[1],
1658 Anum_pg_attribute_attnum,
1659 BTLessEqualStrategyNumber, F_INT2LE,
1660 Int16GetDatum(0));
1661
1662 scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1663 NULL, 2, key);
1664
1665 /* Delete all the matching tuples */
1666 while ((atttup = systable_getnext(scan)) != NULL)
1667 CatalogTupleDelete(attrel, &atttup->t_self);
1668
1669 /* Clean up after the scan */
1670 systable_endscan(scan);
1672}
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:182
#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 285 of file heap.c.

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

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

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

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

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

3588{
3589 List *relations = NIL;
3590 ListCell *cell;
3591
3592 /* Open relations for processing, and grab exclusive access on each */
3593 foreach(cell, relids)
3594 {
3595 Oid rid = lfirst_oid(cell);
3596 Relation rel;
3597
3598 rel = table_open(rid, AccessExclusiveLock);
3599 relations = lappend(relations, rel);
3600 }
3601
3602 /* Don't allow truncate on tables that are referenced by foreign keys */
3603 heap_truncate_check_FKs(relations, true);
3604
3605 /* OK to do it */
3606 foreach(cell, relations)
3607 {
3608 Relation rel = lfirst(cell);
3609
3610 /* Truncate the relation */
3612
3613 /* Close the relation, but keep exclusive lock on it until commit */
3614 table_close(rel, NoLock);
3615 }
3616}
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3672
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3628
#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 3672 of file heap.c.

3673{
3674 List *oids = NIL;
3675 List *dependents;
3676 ListCell *cell;
3677
3678 /*
3679 * Build a list of OIDs of the interesting relations.
3680 *
3681 * If a relation has no triggers, then it can neither have FKs nor be
3682 * referenced by a FK from another table, so we can ignore it. For
3683 * partitioned tables, FKs have no triggers, so we must include them
3684 * anyway.
3685 */
3686 foreach(cell, relations)
3687 {
3688 Relation rel = lfirst(cell);
3689
3690 if (rel->rd_rel->relhastriggers ||
3691 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3692 oids = lappend_oid(oids, RelationGetRelid(rel));
3693 }
3694
3695 /*
3696 * Fast path: if no relation has triggers, none has FKs either.
3697 */
3698 if (oids == NIL)
3699 return;
3700
3701 /*
3702 * Otherwise, must scan pg_constraint. We make one pass with all the
3703 * relations considered; if this finds nothing, then all is well.
3704 */
3705 dependents = heap_truncate_find_FKs(oids);
3706 if (dependents == NIL)
3707 return;
3708
3709 /*
3710 * Otherwise we repeat the scan once per relation to identify a particular
3711 * pair of relations to complain about. This is pretty slow, but
3712 * performance shouldn't matter much in a failure path. The reason for
3713 * doing things this way is to ensure that the message produced is not
3714 * dependent on chance row locations within pg_constraint.
3715 */
3716 foreach(cell, oids)
3717 {
3718 Oid relid = lfirst_oid(cell);
3719 ListCell *cell2;
3720
3721 dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3722
3723 foreach(cell2, dependents)
3724 {
3725 Oid relid2 = lfirst_oid(cell2);
3726
3727 if (!list_member_oid(oids, relid2))
3728 {
3729 char *relname = get_rel_name(relid);
3730 char *relname2 = get_rel_name(relid2);
3731
3732 if (tempTables)
3733 ereport(ERROR,
3734 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3735 errmsg("unsupported ON COMMIT and foreign key combination"),
3736 errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3737 relname2, relname)));
3738 else
3739 ereport(ERROR,
3740 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3741 errmsg("cannot truncate a table referenced in a foreign key constraint"),
3742 errdetail("Table \"%s\" references \"%s\".",
3743 relname2, relname),
3744 errhint("Truncate table \"%s\" at the same time, "
3745 "or use TRUNCATE ... CASCADE.",
3746 relname2)));
3747 }
3748 }
3749 }
3750}
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3767
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
#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 3767 of file heap.c.

3768{
3769 List *result = NIL;
3770 List *oids;
3771 List *parent_cons;
3772 ListCell *cell;
3774 Relation fkeyRel;
3775 SysScanDesc fkeyScan;
3776 HeapTuple tuple;
3777 bool restart;
3778
3779 oids = list_copy(relationIds);
3780
3781 /*
3782 * Must scan pg_constraint. Right now, it is a seqscan because there is
3783 * no available index on confrelid.
3784 */
3785 fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3786
3787restart:
3788 restart = false;
3789 parent_cons = NIL;
3790
3791 fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3792 NULL, 0, NULL);
3793
3794 while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3795 {
3797
3798 /* Not a foreign key */
3799 if (con->contype != CONSTRAINT_FOREIGN)
3800 continue;
3801
3802 /* Not referencing one of our list of tables */
3803 if (!list_member_oid(oids, con->confrelid))
3804 continue;
3805
3806 /*
3807 * If this constraint has a parent constraint which we have not seen
3808 * yet, keep track of it for the second loop, below. Tracking parent
3809 * constraints allows us to climb up to the top-level constraint and
3810 * look for all possible relations referencing the partitioned table.
3811 */
3812 if (OidIsValid(con->conparentid) &&
3813 !list_member_oid(parent_cons, con->conparentid))
3814 parent_cons = lappend_oid(parent_cons, con->conparentid);
3815
3816 /*
3817 * Add referencer to result, unless present in input list. (Don't
3818 * worry about dupes: we'll fix that below).
3819 */
3820 if (!list_member_oid(relationIds, con->conrelid))
3821 result = lappend_oid(result, con->conrelid);
3822 }
3823
3824 systable_endscan(fkeyScan);
3825
3826 /*
3827 * Process each parent constraint we found to add the list of referenced
3828 * relations by them to the oids list. If we do add any new such
3829 * relations, redo the first loop above. Also, if we see that the parent
3830 * constraint in turn has a parent, add that so that we process all
3831 * relations in a single additional pass.
3832 */
3833 foreach(cell, parent_cons)
3834 {
3835 Oid parent = lfirst_oid(cell);
3836
3838 Anum_pg_constraint_oid,
3839 BTEqualStrategyNumber, F_OIDEQ,
3840 ObjectIdGetDatum(parent));
3841
3842 fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3843 true, NULL, 1, &key);
3844
3845 tuple = systable_getnext(fkeyScan);
3846 if (HeapTupleIsValid(tuple))
3847 {
3849
3850 /*
3851 * pg_constraint rows always appear for partitioned hierarchies
3852 * this way: on the each side of the constraint, one row appears
3853 * for each partition that points to the top-most table on the
3854 * other side.
3855 *
3856 * Because of this arrangement, we can correctly catch all
3857 * relevant relations by adding to 'parent_cons' all rows with
3858 * valid conparentid, and to the 'oids' list all rows with a zero
3859 * conparentid. If any oids are added to 'oids', redo the first
3860 * loop above by setting 'restart'.
3861 */
3862 if (OidIsValid(con->conparentid))
3863 parent_cons = list_append_unique_oid(parent_cons,
3864 con->conparentid);
3865 else if (!list_member_oid(oids, con->confrelid))
3866 {
3867 oids = lappend_oid(oids, con->confrelid);
3868 restart = true;
3869 }
3870 }
3871
3872 systable_endscan(fkeyScan);
3873 }
3874
3875 list_free(parent_cons);
3876 if (restart)
3877 goto restart;
3878
3879 table_close(fkeyRel, AccessShareLock);
3880 list_free(oids);
3881
3882 /* Now sort and de-duplicate the result list */
3883 list_sort(result, list_oid_cmp);
3884 list_deduplicate_oid(result);
3885
3886 return result;
3887}
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 3628 of file heap.c.

3629{
3630 Oid toastrelid;
3631
3632 /*
3633 * Truncate the relation. Partitioned tables have no storage, so there is
3634 * nothing to do for them here.
3635 */
3636 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3637 return;
3638
3639 /* Truncate the underlying relation */
3641
3642 /* If the relation has indexes, truncate the indexes too */
3644
3645 /* If there is a toast table, truncate that too */
3646 toastrelid = rel->rd_rel->reltoastrelid;
3647 if (OidIsValid(toastrelid))
3648 {
3649 Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3650
3652 RelationTruncateIndexes(toastrel);
3653 /* keep the lock... */
3654 table_close(toastrel, NoLock);
3655 }
3656}
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3539
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1608

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

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

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

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

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

2716{
2717 bool found;
2718 Relation conDesc;
2719 SysScanDesc conscan;
2720 ScanKeyData skey[3];
2721 HeapTuple tup;
2722
2723 /* Search for a pg_constraint entry with same name and relation */
2724 conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
2725
2726 found = false;
2727
2728 ScanKeyInit(&skey[0],
2729 Anum_pg_constraint_conrelid,
2730 BTEqualStrategyNumber, F_OIDEQ,
2732 ScanKeyInit(&skey[1],
2733 Anum_pg_constraint_contypid,
2734 BTEqualStrategyNumber, F_OIDEQ,
2736 ScanKeyInit(&skey[2],
2737 Anum_pg_constraint_conname,
2738 BTEqualStrategyNumber, F_NAMEEQ,
2739 CStringGetDatum(ccname));
2740
2741 conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
2742 NULL, 3, skey);
2743
2744 /* There can be at most one matching row */
2745 if (HeapTupleIsValid(tup = systable_getnext(conscan)))
2746 {
2748
2749 /* Found it. Conflicts if not identical check constraint */
2750 if (con->contype == CONSTRAINT_CHECK)
2751 {
2752 Datum val;
2753 bool isnull;
2754
2755 val = fastgetattr(tup,
2756 Anum_pg_constraint_conbin,
2757 conDesc->rd_att, &isnull);
2758 if (isnull)
2759 elog(ERROR, "null conbin for rel %s",
2762 found = true;
2763 }
2764
2765 /*
2766 * If the existing constraint is purely inherited (no local
2767 * definition) then interpret addition of a local constraint as a
2768 * legal merge. This allows ALTER ADD CONSTRAINT on parent and child
2769 * tables to be given in either order with same end state. However if
2770 * the relation is a partition, all inherited constraints are always
2771 * non-local, including those that were merged.
2772 */
2773 if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
2774 allow_merge = true;
2775
2776 if (!found || !allow_merge)
2777 ereport(ERROR,
2779 errmsg("constraint \"%s\" for relation \"%s\" already exists",
2780 ccname, RelationGetRelationName(rel))));
2781
2782 /* If the child constraint is "no inherit" then cannot merge */
2783 if (con->connoinherit)
2784 ereport(ERROR,
2785 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2786 errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
2787 ccname, RelationGetRelationName(rel))));
2788
2789 /*
2790 * Must not change an existing inherited constraint to "no inherit"
2791 * status. That's because inherited constraints should be able to
2792 * propagate to lower-level children.
2793 */
2794 if (con->coninhcount > 0 && is_no_inherit)
2795 ereport(ERROR,
2796 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2797 errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
2798 ccname, RelationGetRelationName(rel))));
2799
2800 /*
2801 * If the child constraint is "not valid" then cannot merge with a
2802 * valid parent constraint.
2803 */
2804 if (is_initially_valid && con->conenforced && !con->convalidated)
2805 ereport(ERROR,
2806 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2807 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
2808 ccname, RelationGetRelationName(rel))));
2809
2810 /*
2811 * A non-enforced child constraint cannot be merged with an enforced
2812 * parent constraint. However, the reverse is allowed, where the child
2813 * constraint is enforced.
2814 */
2815 if ((!is_local && is_enforced && !con->conenforced) ||
2816 (is_local && !is_enforced && con->conenforced))
2817 ereport(ERROR,
2818 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2819 errmsg("constraint \"%s\" conflicts with NOT ENFORCED constraint on relation \"%s\"",
2820 ccname, RelationGetRelationName(rel))));
2821
2822 /* OK to update the tuple */
2824 (errmsg("merging constraint \"%s\" with inherited definition",
2825 ccname)));
2826
2827 tup = heap_copytuple(tup);
2828 con = (Form_pg_constraint) GETSTRUCT(tup);
2829
2830 /*
2831 * In case of partitions, an inherited constraint must be inherited
2832 * only once since it cannot have multiple parents and it is never
2833 * considered local.
2834 */
2835 if (rel->rd_rel->relispartition)
2836 {
2837 con->coninhcount = 1;
2838 con->conislocal = false;
2839 }
2840 else
2841 {
2842 if (is_local)
2843 con->conislocal = true;
2844 else if (pg_add_s16_overflow(con->coninhcount, 1,
2845 &con->coninhcount))
2846 ereport(ERROR,
2847 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2848 errmsg("too many inheritance parents"));
2849 }
2850
2851 if (is_no_inherit)
2852 {
2853 Assert(is_local);
2854 con->connoinherit = true;
2855 }
2856
2857 /*
2858 * If the child constraint is required to be enforced while the parent
2859 * constraint is not, this should be allowed by marking the child
2860 * constraint as enforced. In the reverse case, an error would have
2861 * already been thrown before reaching this point.
2862 */
2863 if (is_enforced && !con->conenforced)
2864 {
2865 Assert(is_local);
2866 con->conenforced = true;
2867 con->convalidated = true;
2868 }
2869
2870 CatalogTupleUpdate(conDesc, &tup->t_self, tup);
2871 }
2872
2873 systable_endscan(conscan);
2874 table_close(conDesc, RowExclusiveLock);
2875
2876 return found;
2877}
#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:861
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 1964 of file heap.c.

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

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

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

◆ RelationRemoveInheritance()

static void RelationRemoveInheritance ( Oid  relid)
static

Definition at line 1543 of file heap.c.

1544{
1545 Relation catalogRelation;
1546 SysScanDesc scan;
1548 HeapTuple tuple;
1549
1550 catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
1551
1553 Anum_pg_inherits_inhrelid,
1554 BTEqualStrategyNumber, F_OIDEQ,
1555 ObjectIdGetDatum(relid));
1556
1557 scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1558 NULL, 1, &key);
1559
1560 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1561 CatalogTupleDelete(catalogRelation, &tuple->t_self);
1562
1563 systable_endscan(scan);
1564 table_close(catalogRelation, RowExclusiveLock);
1565}

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

3540{
3541 ListCell *indlist;
3542
3543 /* Ask the relcache to produce a list of the indexes of the rel */
3544 foreach(indlist, RelationGetIndexList(heapRelation))
3545 {
3546 Oid indexId = lfirst_oid(indlist);
3547 Relation currentIndex;
3548 IndexInfo *indexInfo;
3549
3550 /* Open the index relation; use exclusive lock, just to be sure */
3551 currentIndex = index_open(indexId, AccessExclusiveLock);
3552
3553 /*
3554 * Fetch info needed for index_build. Since we know there are no
3555 * tuples that actually need indexing, we can use a dummy IndexInfo.
3556 * This is slightly cheaper to build, but the real point is to avoid
3557 * possibly running user-defined code in index expressions or
3558 * predicates. We might be getting invoked during ON COMMIT
3559 * processing, and we don't want to run any such code then.
3560 */
3561 indexInfo = BuildDummyIndexInfo(currentIndex);
3562
3563 /*
3564 * Now truncate the actual file (and discard buffers).
3565 */
3566 RelationTruncate(currentIndex, 0);
3567
3568 /* Initialize the index and rebuild */
3569 /* Note: we do not need to re-establish pkey setting */
3570 index_build(heapRelation, currentIndex, indexInfo, true, false);
3571
3572 /* We're done with this index */
3573 index_close(currentIndex, NoLock);
3574 }
3575}
IndexInfo * BuildDummyIndexInfo(Relation index)
Definition: index.c:2488
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isreindex, bool parallel)
Definition: index.c:3002
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:4836
void RelationTruncate(Relation rel, BlockNumber nblocks)
Definition: storage.c:289

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

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

4020{
4021 Relation rel;
4022 HeapTuple tuple;
4023
4024 rel = table_open(PartitionedRelationId, RowExclusiveLock);
4025
4026 tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
4027 if (!HeapTupleIsValid(tuple))
4028 elog(ERROR, "cache lookup failed for partition key of relation %u",
4029 relid);
4030
4031 CatalogTupleDelete(rel, &tuple->t_self);
4032
4033 ReleaseSysCache(tuple);
4035}

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

3493{
3494 Relation pgstatistic;
3495 SysScanDesc scan;
3496 ScanKeyData key[2];
3497 int nkeys;
3498 HeapTuple tuple;
3499
3500 pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3501
3502 ScanKeyInit(&key[0],
3503 Anum_pg_statistic_starelid,
3504 BTEqualStrategyNumber, F_OIDEQ,
3505 ObjectIdGetDatum(relid));
3506
3507 if (attnum == 0)
3508 nkeys = 1;
3509 else
3510 {
3511 ScanKeyInit(&key[1],
3512 Anum_pg_statistic_staattnum,
3513 BTEqualStrategyNumber, F_INT2EQ,
3515 nkeys = 2;
3516 }
3517
3518 scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3519 NULL, nkeys, key);
3520
3521 /* we must loop even when attnum != 0, in case of inherited stats */
3522 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3523 CatalogTupleDelete(pgstatistic, &tuple->t_self);
3524
3525 systable_endscan(scan);
3526
3527 table_close(pgstatistic, RowExclusiveLock);
3528}

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

2087{
2088 Datum valuesAtt[Natts_pg_attribute] = {0};
2089 bool nullsAtt[Natts_pg_attribute] = {0};
2090 bool replacesAtt[Natts_pg_attribute] = {0};
2091 Datum missingval;
2092 Form_pg_attribute attStruct;
2093 Relation attrrel,
2094 tablerel;
2095 HeapTuple atttup,
2096 newtup;
2097
2098 /* lock the table the attribute belongs to */
2099 tablerel = table_open(relid, AccessExclusiveLock);
2100
2101 /* Don't do anything unless it's a plain table */
2102 if (tablerel->rd_rel->relkind != RELKIND_RELATION)
2103 {
2105 return;
2106 }
2107
2108 /* Lock the attribute row and get the data */
2109 attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2110 atttup = SearchSysCacheAttName(relid, attname);
2111 if (!HeapTupleIsValid(atttup))
2112 elog(ERROR, "cache lookup failed for attribute %s of relation %u",
2113 attname, relid);
2114 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2115
2116 /* get an array value from the value string */
2117 missingval = OidFunctionCall3(F_ARRAY_IN,
2119 ObjectIdGetDatum(attStruct->atttypid),
2120 Int32GetDatum(attStruct->atttypmod));
2121
2122 /* update the tuple - set atthasmissing and attmissingval */
2123 valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
2124 replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2125 valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2126 replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2127
2128 newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2129 valuesAtt, nullsAtt, replacesAtt);
2130 CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
2131
2132 /* clean up */
2133 ReleaseSysCache(atttup);
2134 table_close(attrrel, RowExclusiveLock);
2136}
#define OidFunctionCall3(functionId, arg1, arg2, arg3)
Definition: fmgr.h:724
static struct @166 value
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:475

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

3147{
3148 Relation relrel;
3149 HeapTuple reltup;
3150 Form_pg_class relStruct;
3151
3152 relrel = table_open(RelationRelationId, RowExclusiveLock);
3153 reltup = SearchSysCacheCopy1(RELOID,
3155 if (!HeapTupleIsValid(reltup))
3156 elog(ERROR, "cache lookup failed for relation %u",
3157 RelationGetRelid(rel));
3158 relStruct = (Form_pg_class) GETSTRUCT(reltup);
3159
3160 if (relStruct->relchecks != numchecks)
3161 {
3162 relStruct->relchecks = numchecks;
3163
3164 CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
3165 }
3166 else
3167 {
3168 /* Skip the disk update, but force relcache inval anyway */
3170 }
3171
3172 heap_freetuple(reltup);
3174}
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1631
#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().

◆ StoreAttrMissingVal()

void StoreAttrMissingVal ( Relation  rel,
AttrNumber  attnum,
Datum  missingval 
)

Definition at line 2030 of file heap.c.

2031{
2032 Datum valuesAtt[Natts_pg_attribute] = {0};
2033 bool nullsAtt[Natts_pg_attribute] = {0};
2034 bool replacesAtt[Natts_pg_attribute] = {0};
2035 Relation attrrel;
2036 Form_pg_attribute attStruct;
2037 HeapTuple atttup,
2038 newtup;
2039
2040 /* This is only supported for plain tables */
2041 Assert(rel->rd_rel->relkind == RELKIND_RELATION);
2042
2043 /* Fetch the pg_attribute row */
2044 attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2045
2046 atttup = SearchSysCache2(ATTNUM,
2049 if (!HeapTupleIsValid(atttup)) /* shouldn't happen */
2050 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2051 attnum, RelationGetRelid(rel));
2052 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2053
2054 /* Make a one-element array containing the value */
2055 missingval = PointerGetDatum(construct_array(&missingval,
2056 1,
2057 attStruct->atttypid,
2058 attStruct->attlen,
2059 attStruct->attbyval,
2060 attStruct->attalign));
2061
2062 /* Update the pg_attribute row */
2063 valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
2064 replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2065
2066 valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2067 replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2068
2069 newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2070 valuesAtt, nullsAtt, replacesAtt);
2071 CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
2072
2073 /* clean up */
2074 ReleaseSysCache(atttup);
2075 table_close(attrrel, RowExclusiveLock);
2076}
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3361

References Assert(), attnum, BoolGetDatum(), CatalogTupleUpdate(), construct_array(), elog, ERROR, GETSTRUCT(), heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), ObjectIdGetDatum(), PointerGetDatum(), RelationData::rd_rel, RelationGetDescr, RelationGetRelid, ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecAddColumn().

◆ StoreConstraints()

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

Definition at line 2310 of file heap.c.

2311{
2312 int numchecks = 0;
2313 ListCell *lc;
2314
2315 if (cooked_constraints == NIL)
2316 return; /* nothing to do */
2317
2318 /*
2319 * Deparsing of constraint expressions will fail unless the just-created
2320 * pg_attribute tuples for this relation are made visible. So, bump the
2321 * command counter. CAUTION: this will cause a relcache entry rebuild.
2322 */
2324
2325 foreach(lc, cooked_constraints)
2326 {
2328
2329 switch (con->contype)
2330 {
2331 case CONSTR_DEFAULT:
2332 con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
2333 is_internal);
2334 break;
2335 case CONSTR_CHECK:
2336 con->conoid =
2337 StoreRelCheck(rel, con->name, con->expr,
2338 con->is_enforced, !con->skip_validation,
2339 con->is_local, con->inhcount,
2340 con->is_no_inherit, is_internal);
2341 numchecks++;
2342 break;
2343
2344 default:
2345 elog(ERROR, "unrecognized constraint type: %d",
2346 (int) con->contype);
2347 }
2348 }
2349
2350 if (numchecks > 0)
2351 SetRelationNumChecks(rel, numchecks);
2352}
void CommandCounterIncrement(void)
Definition: xact.c:1100

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

4051{
4052 Relation classRel;
4053 HeapTuple tuple,
4054 newtuple;
4055 Datum new_val[Natts_pg_class];
4056 bool new_null[Natts_pg_class],
4057 new_repl[Natts_pg_class];
4058 Oid defaultPartOid;
4059
4060 /* Update pg_class tuple */
4061 classRel = table_open(RelationRelationId, RowExclusiveLock);
4062 tuple = SearchSysCacheCopy1(RELOID,
4064 if (!HeapTupleIsValid(tuple))
4065 elog(ERROR, "cache lookup failed for relation %u",
4066 RelationGetRelid(rel));
4067
4068#ifdef USE_ASSERT_CHECKING
4069 {
4070 Form_pg_class classForm;
4071 bool isnull;
4072
4073 classForm = (Form_pg_class) GETSTRUCT(tuple);
4074 Assert(!classForm->relispartition);
4075 (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
4076 &isnull);
4077 Assert(isnull);
4078 }
4079#endif
4080
4081 /* Fill in relpartbound value */
4082 memset(new_val, 0, sizeof(new_val));
4083 memset(new_null, false, sizeof(new_null));
4084 memset(new_repl, false, sizeof(new_repl));
4085 new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
4086 new_null[Anum_pg_class_relpartbound - 1] = false;
4087 new_repl[Anum_pg_class_relpartbound - 1] = true;
4088 newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
4089 new_val, new_null, new_repl);
4090 /* Also set the flag */
4091 ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
4092
4093 /*
4094 * We already checked for no inheritance children, but reset
4095 * relhassubclass in case it was left over.
4096 */
4097 if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
4098 ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
4099
4100 CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
4101 heap_freetuple(newtuple);
4102 table_close(classRel, RowExclusiveLock);
4103
4104 /*
4105 * If we're storing bounds for the default partition, update
4106 * pg_partitioned_table too.
4107 */
4108 if (bound->is_default)
4110 RelationGetRelid(rel));
4111
4112 /* Make these updates visible */
4114
4115 /*
4116 * The partition constraint for the default partition depends on the
4117 * partition bounds of every other partition, so we must invalidate the
4118 * relcache entry for that partition every time a partition is added or
4119 * removed.
4120 */
4121 defaultPartOid =
4123 if (OidIsValid(defaultPartOid))
4124 CacheInvalidateRelcacheByRelid(defaultPartOid);
4125
4127}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
char * nodeToString(const void *obj)
Definition: outfuncs.c:805
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:595

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

3901{
3902 int i;
3903 int2vector *partattrs_vec;
3904 oidvector *partopclass_vec;
3905 oidvector *partcollation_vec;
3906 Datum partexprDatum;
3907 Relation pg_partitioned_table;
3908 HeapTuple tuple;
3909 Datum values[Natts_pg_partitioned_table];
3910 bool nulls[Natts_pg_partitioned_table] = {0};
3911 ObjectAddress myself;
3912 ObjectAddress referenced;
3913 ObjectAddresses *addrs;
3914
3915 Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3916
3917 /* Copy the partition attribute numbers, opclass OIDs into arrays */
3918 partattrs_vec = buildint2vector(partattrs, partnatts);
3919 partopclass_vec = buildoidvector(partopclass, partnatts);
3920 partcollation_vec = buildoidvector(partcollation, partnatts);
3921
3922 /* Convert the expressions (if any) to a text datum */
3923 if (partexprs)
3924 {
3925 char *exprString;
3926
3927 exprString = nodeToString(partexprs);
3928 partexprDatum = CStringGetTextDatum(exprString);
3929 pfree(exprString);
3930 }
3931 else
3932 partexprDatum = (Datum) 0;
3933
3934 pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3935
3936 /* Only this can ever be NULL */
3937 if (!partexprDatum)
3938 nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3939
3940 values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3941 values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3942 values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3943 values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3944 values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3945 values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3946 values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3947 values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3948
3949 tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3950
3951 CatalogTupleInsert(pg_partitioned_table, tuple);
3952 table_close(pg_partitioned_table, RowExclusiveLock);
3953
3954 /* Mark this relation as dependent on a few things as follows */
3955 addrs = new_object_addresses();
3956 ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3957
3958 /* Operator class and collation per key column */
3959 for (i = 0; i < partnatts; i++)
3960 {
3961 ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3962 add_exact_object_address(&referenced, addrs);
3963
3964 /* The default collation is pinned, so don't bother recording it */
3965 if (OidIsValid(partcollation[i]) &&
3966 partcollation[i] != DEFAULT_COLLATION_OID)
3967 {
3968 ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3969 add_exact_object_address(&referenced, addrs);
3970 }
3971 }
3972
3974 free_object_addresses(addrs);
3975
3976 /*
3977 * The partitioning columns are made internally dependent on the table,
3978 * because we cannot drop any of them without dropping the whole table.
3979 * (ATExecDropColumn independently enforces that, but it's not bulletproof
3980 * so we need the dependencies too.)
3981 */
3982 for (i = 0; i < partnatts; i++)
3983 {
3984 if (partattrs[i] == 0)
3985 continue; /* ignore expressions here */
3986
3987 ObjectAddressSubSet(referenced, RelationRelationId,
3988 RelationGetRelid(rel), partattrs[i]);
3989 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3990 }
3991
3992 /*
3993 * Also consider anything mentioned in partition expressions. External
3994 * references (e.g. functions) get NORMAL dependencies. Table columns
3995 * mentioned in the expressions are handled the same as plain partitioning
3996 * columns, i.e. they become internally dependent on the whole table.
3997 */
3998 if (partexprs)
4000 (Node *) partexprs,
4001 RelationGetRelid(rel),
4004 true /* reverse the self-deps */ );
4005
4006 /*
4007 * We must invalidate the relcache so that the next
4008 * CommandCounterIncrement() will cause the same to be rebuilt using the
4009 * information in just created catalog entry.
4010 */
4012}
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:721
Definition: c.h:732

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

2150{
2151 char *ccbin;
2152 List *varList;
2153 int keycount;
2154 int16 *attNos;
2155 Oid constrOid;
2156
2157 /*
2158 * Flatten expression to string form for storage.
2159 */
2160 ccbin = nodeToString(expr);
2161
2162 /*
2163 * Find columns of rel that are used in expr
2164 *
2165 * NB: pull_var_clause is okay here only because we don't allow subselects
2166 * in check constraints; it would fail to examine the contents of
2167 * subselects.
2168 */
2169 varList = pull_var_clause(expr, 0);
2170 keycount = list_length(varList);
2171
2172 if (keycount > 0)
2173 {
2174 ListCell *vl;
2175 int i = 0;
2176
2177 attNos = (int16 *) palloc(keycount * sizeof(int16));
2178 foreach(vl, varList)
2179 {
2180 Var *var = (Var *) lfirst(vl);
2181 int j;
2182
2183 for (j = 0; j < i; j++)
2184 if (attNos[j] == var->varattno)
2185 break;
2186 if (j == i)
2187 attNos[i++] = var->varattno;
2188 }
2189 keycount = i;
2190 }
2191 else
2192 attNos = NULL;
2193
2194 /*
2195 * Partitioned tables do not contain any rows themselves, so a NO INHERIT
2196 * constraint makes no sense.
2197 */
2198 if (is_no_inherit &&
2199 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2200 ereport(ERROR,
2201 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2202 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
2204
2205 /*
2206 * Create the Check Constraint
2207 */
2208 constrOid =
2209 CreateConstraintEntry(ccname, /* Constraint Name */
2210 RelationGetNamespace(rel), /* namespace */
2211 CONSTRAINT_CHECK, /* Constraint Type */
2212 false, /* Is Deferrable */
2213 false, /* Is Deferred */
2214 is_enforced, /* Is Enforced */
2215 is_validated,
2216 InvalidOid, /* no parent constraint */
2217 RelationGetRelid(rel), /* relation */
2218 attNos, /* attrs in the constraint */
2219 keycount, /* # key attrs in the constraint */
2220 keycount, /* # total attrs in the constraint */
2221 InvalidOid, /* not a domain constraint */
2222 InvalidOid, /* no associated index */
2223 InvalidOid, /* Foreign key fields */
2224 NULL,
2225 NULL,
2226 NULL,
2227 NULL,
2228 0,
2229 ' ',
2230 ' ',
2231 NULL,
2232 0,
2233 ' ',
2234 NULL, /* not an exclusion constraint */
2235 expr, /* Tree form of check constraint */
2236 ccbin, /* Binary form of check constraint */
2237 is_local, /* conislocal */
2238 inhcount, /* coninhcount */
2239 is_no_inherit, /* connoinherit */
2240 false, /* conperiod */
2241 is_internal); /* internally constructed? */
2242
2243 pfree(ccbin);
2244
2245 return constrOid;
2246}
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 2254 of file heap.c.

2257{
2258 Oid constrOid;
2259
2261
2262 constrOid =
2263 CreateConstraintEntry(nnname,
2265 CONSTRAINT_NOTNULL,
2266 false,
2267 false,
2268 true, /* Is Enforced */
2269 is_validated,
2270 InvalidOid,
2271 RelationGetRelid(rel),
2272 &attnum,
2273 1,
2274 1,
2275 InvalidOid, /* not a domain constraint */
2276 InvalidOid, /* no associated index */
2277 InvalidOid, /* Foreign key fields */
2278 NULL,
2279 NULL,
2280 NULL,
2281 NULL,
2282 0,
2283 ' ',
2284 ' ',
2285 NULL,
2286 0,
2287 ' ',
2288 NULL, /* not an exclusion constraint */
2289 NULL,
2290 NULL,
2291 is_local,
2292 inhcount,
2293 is_no_inherit,
2294 false,
2295 false);
2296 return constrOid;
2297}

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

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

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

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

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:123
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

Definition at line 144 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 157 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:672
#define MinCommandIdAttributeNumber
Definition: sysattr.h:23

Definition at line 170 of file heap.c.

◆ a4

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

Definition at line 183 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 196 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 215 of file heap.c.

◆ binary_upgrade_next_heap_pg_class_oid

Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid

Definition at line 81 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 84 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 228 of file heap.c.

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