PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
heap.h File Reference
Include dependency graph for heap.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  RawColumnDefault
 
struct  CookedConstraint
 

Macros

#define CHKATYPE_ANYARRAY   0x01 /* allow ANYARRAY */
 
#define CHKATYPE_ANYRECORD   0x02 /* allow RECORD and RECORD[] */
 
#define CHKATYPE_IS_PARTKEY   0x04 /* attname is part key # not column */
 
#define CHKATYPE_IS_VIRTUAL   0x08 /* is virtual generated column */
 

Typedefs

typedef struct RawColumnDefault RawColumnDefault
 
typedef struct CookedConstraint CookedConstraint
 

Functions

Relation heap_create (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, RelFileNumber relfilenumber, Oid accessmtd, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool allow_system_table_mods, TransactionId *relfrozenxid, MultiXactId *relminmxid, bool create_storage)
 
Oid heap_create_with_catalog (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
 
void heap_drop_with_catalog (Oid relid)
 
void heap_truncate (List *relids)
 
void heap_truncate_one_rel (Relation rel)
 
void heap_truncate_check_FKs (List *relations, bool tempTables)
 
Listheap_truncate_find_FKs (List *relationIds)
 
void InsertPgAttributeTuples (Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
 
void InsertPgClassTuple (Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
 
ListAddRelationNewConstraints (Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
 
ListAddRelationNotNullConstraints (Relation rel, List *constraints, List *old_notnulls)
 
void RelationClearMissing (Relation rel)
 
void StoreAttrMissingVal (Relation rel, AttrNumber attnum, Datum missingval)
 
void SetAttrMissing (Oid relid, char *attname, char *value)
 
NodecookDefault (ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
 
void DeleteRelationTuple (Oid relid)
 
void DeleteAttributeTuples (Oid relid)
 
void DeleteSystemAttributeTuples (Oid relid)
 
void RemoveAttributeById (Oid relid, AttrNumber attnum)
 
void CopyStatistics (Oid fromrelid, Oid torelid)
 
void RemoveStatistics (Oid relid, AttrNumber attnum)
 
const FormData_pg_attributeSystemAttributeDefinition (AttrNumber attno)
 
const FormData_pg_attributeSystemAttributeByName (const char *attname)
 
void CheckAttributeNamesTypes (TupleDesc tupdesc, char relkind, int flags)
 
void CheckAttributeType (const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
 
void StorePartitionKey (Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
 
void RemovePartitionKeyByRelId (Oid relid)
 
void StorePartitionBound (Relation rel, Relation parent, PartitionBoundSpec *bound)
 

Macro Definition Documentation

◆ CHKATYPE_ANYARRAY

#define CHKATYPE_ANYARRAY   0x01 /* allow ANYARRAY */

Definition at line 23 of file heap.h.

◆ CHKATYPE_ANYRECORD

#define CHKATYPE_ANYRECORD   0x02 /* allow RECORD and RECORD[] */

Definition at line 24 of file heap.h.

◆ CHKATYPE_IS_PARTKEY

#define CHKATYPE_IS_PARTKEY   0x04 /* attname is part key # not column */

Definition at line 25 of file heap.h.

◆ CHKATYPE_IS_VIRTUAL

#define CHKATYPE_IS_VIRTUAL   0x08 /* is virtual generated column */

Definition at line 26 of file heap.h.

Typedef Documentation

◆ CookedConstraint

◆ RawColumnDefault

Function Documentation

◆ AddRelationNewConstraints()

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

Definition at line 2375 of file heap.c.

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

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

◆ AddRelationNotNullConstraints()

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

Definition at line 2884 of file heap.c.

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

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

Referenced by DefineRelation().

◆ 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:75
int i
Definition: isn.c:74
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 * This might not be strictly invalid per SQL standard, but it is pretty
669 * useless, and it cannot be dumped, so we must disallow it.
670 */
671 if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
672 {
673 if (flags & CHKATYPE_IS_PARTKEY)
675 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
676 /* translator: first %s is an integer not a name */
677 errmsg("no collation was derived for partition key column %s with collatable type %s",
678 attname, format_type_be(atttypid)),
679 errhint("Use the COLLATE clause to set the collation explicitly.")));
680 else
682 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
683 errmsg("no collation was derived for column \"%s\" with collatable type %s",
684 attname, format_type_be(atttypid)),
685 errhint("Use the COLLATE clause to set the collation explicitly.")));
686 }
687}
#define OidIsValid(objectId)
Definition: c.h:746
int errhint(const char *fmt,...)
Definition: elog.c:1317
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
#define CHKATYPE_ANYRECORD
Definition: heap.h:24
#define CHKATYPE_ANYARRAY
Definition: heap.h:23
#define CHKATYPE_IS_PARTKEY
Definition: heap.h:25
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_delete_last(List *list)
Definition: list.c:957
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
Oid get_range_subtype(Oid rangeOid)
Definition: lsyscache.c:3490
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2842
Oid get_range_collation(Oid rangeOid)
Definition: lsyscache.c:3516
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3164
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2814
char get_typtype(Oid typid)
Definition: lsyscache.c:2712
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2604
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
void check_stack_depth(void)
Definition: stack_depth.c:95

References AccessShareLock, attname, check_stack_depth(), CheckAttributeType(), CHKATYPE_ANYARRAY, CHKATYPE_ANYRECORD, CHKATYPE_IS_PARTKEY, CHKATYPE_IS_VIRTUAL, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_element_type(), get_range_collation(), get_range_subtype(), get_typ_typrelid(), get_typtype(), getBaseType(), i, lappend_oid(), list_delete_last(), list_member_oid(), NameStr, TupleDescData::natts, OidIsValid, relation_close(), relation_open(), RelationGetDescr, TupleDescAttr(), and type_is_collatable().

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

◆ cookDefault()

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

Definition at line 3235 of file heap.c.

3241{
3242 Node *expr;
3243
3244 Assert(raw_default != NULL);
3245
3246 /*
3247 * Transform raw parsetree to executable expression.
3248 */
3249 expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3250
3251 if (attgenerated)
3252 {
3253 /* Disallow refs to other generated columns */
3254 check_nested_generated(pstate, expr);
3255
3256 /* Disallow mutable functions */
3258 ereport(ERROR,
3259 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3260 errmsg("generation expression is not immutable")));
3261 }
3262 else
3263 {
3264 /*
3265 * For a default expression, transformExpr() should have rejected
3266 * column references.
3267 */
3268 Assert(!contain_var_clause(expr));
3269 }
3270
3271 /*
3272 * Coerce the expression to the correct type and typmod, if given. This
3273 * should match the parser's processing of non-defaulted expressions ---
3274 * see transformAssignedExpr().
3275 */
3276 if (OidIsValid(atttypid))
3277 {
3278 Oid type_id = exprType(expr);
3279
3280 expr = coerce_to_target_type(pstate, expr, type_id,
3281 atttypid, atttypmod,
3284 -1);
3285 if (expr == NULL)
3286 ereport(ERROR,
3287 (errcode(ERRCODE_DATATYPE_MISMATCH),
3288 errmsg("column \"%s\" is of type %s"
3289 " but default expression is of type %s",
3290 attname,
3291 format_type_be(atttypid),
3292 format_type_be(type_id)),
3293 errhint("You will need to rewrite or cast the expression.")));
3294 }
3295
3296 /*
3297 * Finally, take care of collations in the finished expression.
3298 */
3299 assign_expr_collations(pstate, expr);
3300
3301 return expr;
3302}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:489
static void check_nested_generated(ParseState *pstate, Node *node)
Definition: heap.c:3217
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:118
@ EXPR_KIND_COLUMN_DEFAULT
Definition: parse_node.h:70
@ EXPR_KIND_GENERATED_COLUMN
Definition: parse_node.h:83
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
bool contain_var_clause(Node *node)
Definition: var.c:406

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

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

◆ CopyStatistics()

void CopyStatistics ( Oid  fromrelid,
Oid  torelid 
)

Definition at line 3350 of file heap.c.

3351{
3352 HeapTuple tup;
3353 SysScanDesc scan;
3354 ScanKeyData key[1];
3355 Relation statrel;
3356 CatalogIndexState indstate = NULL;
3357
3358 statrel = table_open(StatisticRelationId, RowExclusiveLock);
3359
3360 /* Now search for stat records */
3361 ScanKeyInit(&key[0],
3362 Anum_pg_statistic_starelid,
3363 BTEqualStrategyNumber, F_OIDEQ,
3364 ObjectIdGetDatum(fromrelid));
3365
3366 scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId,
3367 true, NULL, 1, key);
3368
3369 while (HeapTupleIsValid((tup = systable_getnext(scan))))
3370 {
3371 Form_pg_statistic statform;
3372
3373 /* make a modifiable copy */
3374 tup = heap_copytuple(tup);
3375 statform = (Form_pg_statistic) GETSTRUCT(tup);
3376
3377 /* update the copy of the tuple and insert it */
3378 statform->starelid = torelid;
3379
3380 /* fetch index information when we know we need it */
3381 if (indstate == NULL)
3382 indstate = CatalogOpenIndexes(statrel);
3383
3384 CatalogTupleInsertWithInfo(statrel, tup, indstate);
3385
3386 heap_freetuple(tup);
3387 }
3388
3389 systable_endscan(scan);
3390
3391 if (indstate != NULL)
3392 CatalogCloseIndexes(indstate);
3393 table_close(statrel, RowExclusiveLock);
3394}
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
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_statistic * Form_pg_statistic
Definition: pg_statistic.h:135
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

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

Referenced by index_concurrently_swap().

◆ DeleteAttributeTuples()

void DeleteAttributeTuples ( Oid  relid)

Definition at line 1595 of file heap.c.

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

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

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteSystemAttributeTuples()

void DeleteSystemAttributeTuples ( Oid  relid)

Definition at line 1632 of file heap.c.

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

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

◆ heap_create()

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

Definition at line 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:230
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
Oid MyDatabaseTableSpace
Definition: globals.c:95
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
#define IsNormalProcessingMode()
Definition: miscadmin.h:478
#define InvalidMultiXactId
Definition: multixact.h:24
NameData relname
Definition: pg_class.h:38
void recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace)
Definition: pg_shdepend.c:370
void pgstat_create_relation(Relation rel)
#define InvalidOid
Definition: postgres_ext.h:35
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:3475
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition: storage.c:121
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111
static void table_relation_set_new_filelocator(Relation rel, const RelFileLocator *newrlocator, char persistence, TransactionId *freezeXid, MultiXactId *minmulti)
Definition: tableam.h:1591
#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 1112 of file heap.c.

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

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

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

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)

Definition at line 1774 of file heap.c.

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

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

3499{
3500 List *relations = NIL;
3501 ListCell *cell;
3502
3503 /* Open relations for processing, and grab exclusive access on each */
3504 foreach(cell, relids)
3505 {
3506 Oid rid = lfirst_oid(cell);
3507 Relation rel;
3508
3509 rel = table_open(rid, AccessExclusiveLock);
3510 relations = lappend(relations, rel);
3511 }
3512
3513 /* Don't allow truncate on tables that are referenced by foreign keys */
3514 heap_truncate_check_FKs(relations, true);
3515
3516 /* OK to do it */
3517 foreach(cell, relations)
3518 {
3519 Relation rel = lfirst(cell);
3520
3521 /* Truncate the relation */
3523
3524 /* Close the relation, but keep exclusive lock on it until commit */
3525 table_close(rel, NoLock);
3526 }
3527}
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3583
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3539
#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 3583 of file heap.c.

3584{
3585 List *oids = NIL;
3586 List *dependents;
3587 ListCell *cell;
3588
3589 /*
3590 * Build a list of OIDs of the interesting relations.
3591 *
3592 * If a relation has no triggers, then it can neither have FKs nor be
3593 * referenced by a FK from another table, so we can ignore it. For
3594 * partitioned tables, FKs have no triggers, so we must include them
3595 * anyway.
3596 */
3597 foreach(cell, relations)
3598 {
3599 Relation rel = lfirst(cell);
3600
3601 if (rel->rd_rel->relhastriggers ||
3602 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3603 oids = lappend_oid(oids, RelationGetRelid(rel));
3604 }
3605
3606 /*
3607 * Fast path: if no relation has triggers, none has FKs either.
3608 */
3609 if (oids == NIL)
3610 return;
3611
3612 /*
3613 * Otherwise, must scan pg_constraint. We make one pass with all the
3614 * relations considered; if this finds nothing, then all is well.
3615 */
3616 dependents = heap_truncate_find_FKs(oids);
3617 if (dependents == NIL)
3618 return;
3619
3620 /*
3621 * Otherwise we repeat the scan once per relation to identify a particular
3622 * pair of relations to complain about. This is pretty slow, but
3623 * performance shouldn't matter much in a failure path. The reason for
3624 * doing things this way is to ensure that the message produced is not
3625 * dependent on chance row locations within pg_constraint.
3626 */
3627 foreach(cell, oids)
3628 {
3629 Oid relid = lfirst_oid(cell);
3630 ListCell *cell2;
3631
3632 dependents = heap_truncate_find_FKs(list_make1_oid(relid));
3633
3634 foreach(cell2, dependents)
3635 {
3636 Oid relid2 = lfirst_oid(cell2);
3637
3638 if (!list_member_oid(oids, relid2))
3639 {
3640 char *relname = get_rel_name(relid);
3641 char *relname2 = get_rel_name(relid2);
3642
3643 if (tempTables)
3644 ereport(ERROR,
3645 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3646 errmsg("unsupported ON COMMIT and foreign key combination"),
3647 errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
3648 relname2, relname)));
3649 else
3650 ereport(ERROR,
3651 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3652 errmsg("cannot truncate a table referenced in a foreign key constraint"),
3653 errdetail("Table \"%s\" references \"%s\".",
3654 relname2, relname),
3655 errhint("Truncate table \"%s\" at the same time, "
3656 "or use TRUNCATE ... CASCADE.",
3657 relname2)));
3658 }
3659 }
3660 }
3661}
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3678
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2011
#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 3678 of file heap.c.

3679{
3680 List *result = NIL;
3681 List *oids;
3682 List *parent_cons;
3683 ListCell *cell;
3685 Relation fkeyRel;
3686 SysScanDesc fkeyScan;
3687 HeapTuple tuple;
3688 bool restart;
3689
3690 oids = list_copy(relationIds);
3691
3692 /*
3693 * Must scan pg_constraint. Right now, it is a seqscan because there is
3694 * no available index on confrelid.
3695 */
3696 fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
3697
3698restart:
3699 restart = false;
3700 parent_cons = NIL;
3701
3702 fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
3703 NULL, 0, NULL);
3704
3705 while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
3706 {
3708
3709 /* Not a foreign key */
3710 if (con->contype != CONSTRAINT_FOREIGN)
3711 continue;
3712
3713 /* Not referencing one of our list of tables */
3714 if (!list_member_oid(oids, con->confrelid))
3715 continue;
3716
3717 /*
3718 * If this constraint has a parent constraint which we have not seen
3719 * yet, keep track of it for the second loop, below. Tracking parent
3720 * constraints allows us to climb up to the top-level constraint and
3721 * look for all possible relations referencing the partitioned table.
3722 */
3723 if (OidIsValid(con->conparentid) &&
3724 !list_member_oid(parent_cons, con->conparentid))
3725 parent_cons = lappend_oid(parent_cons, con->conparentid);
3726
3727 /*
3728 * Add referencer to result, unless present in input list. (Don't
3729 * worry about dupes: we'll fix that below).
3730 */
3731 if (!list_member_oid(relationIds, con->conrelid))
3732 result = lappend_oid(result, con->conrelid);
3733 }
3734
3735 systable_endscan(fkeyScan);
3736
3737 /*
3738 * Process each parent constraint we found to add the list of referenced
3739 * relations by them to the oids list. If we do add any new such
3740 * relations, redo the first loop above. Also, if we see that the parent
3741 * constraint in turn has a parent, add that so that we process all
3742 * relations in a single additional pass.
3743 */
3744 foreach(cell, parent_cons)
3745 {
3746 Oid parent = lfirst_oid(cell);
3747
3749 Anum_pg_constraint_oid,
3750 BTEqualStrategyNumber, F_OIDEQ,
3751 ObjectIdGetDatum(parent));
3752
3753 fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId,
3754 true, NULL, 1, &key);
3755
3756 tuple = systable_getnext(fkeyScan);
3757 if (HeapTupleIsValid(tuple))
3758 {
3760
3761 /*
3762 * pg_constraint rows always appear for partitioned hierarchies
3763 * this way: on the each side of the constraint, one row appears
3764 * for each partition that points to the top-most table on the
3765 * other side.
3766 *
3767 * Because of this arrangement, we can correctly catch all
3768 * relevant relations by adding to 'parent_cons' all rows with
3769 * valid conparentid, and to the 'oids' list all rows with a zero
3770 * conparentid. If any oids are added to 'oids', redo the first
3771 * loop above by setting 'restart'.
3772 */
3773 if (OidIsValid(con->conparentid))
3774 parent_cons = list_append_unique_oid(parent_cons,
3775 con->conparentid);
3776 else if (!list_member_oid(oids, con->confrelid))
3777 {
3778 oids = lappend_oid(oids, con->confrelid);
3779 restart = true;
3780 }
3781 }
3782
3783 systable_endscan(fkeyScan);
3784 }
3785
3786 list_free(parent_cons);
3787 if (restart)
3788 goto restart;
3789
3790 table_close(fkeyRel, AccessShareLock);
3791 list_free(oids);
3792
3793 /* Now sort and de-duplicate the result list */
3794 list_sort(result, list_oid_cmp);
3795 list_deduplicate_oid(result);
3796
3797 return result;
3798}
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 3539 of file heap.c.

3540{
3541 Oid toastrelid;
3542
3543 /*
3544 * Truncate the relation. Partitioned tables have no storage, so there is
3545 * nothing to do for them here.
3546 */
3547 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3548 return;
3549
3550 /* Truncate the underlying relation */
3552
3553 /* If the relation has indexes, truncate the indexes too */
3555
3556 /* If there is a toast table, truncate that too */
3557 toastrelid = rel->rd_rel->reltoastrelid;
3558 if (OidIsValid(toastrelid))
3559 {
3560 Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
3561
3563 RelationTruncateIndexes(toastrel);
3564 /* keep the lock... */
3565 table_close(toastrel, NoLock);
3566 }
3567}
static void RelationTruncateIndexes(Relation heapRelation)
Definition: heap.c:3450
static void table_relation_nontransactional_truncate(Relation rel)
Definition: tableam.h:1609

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

Referenced by ExecuteTruncateGuts(), and heap_truncate().

◆ InsertPgAttributeTuples()

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

Definition at line 708 of file heap.c.

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

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

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

Referenced by AddNewRelationTuple(), and index_create().

◆ RelationClearMissing()

void RelationClearMissing ( Relation  rel)

Definition at line 1954 of file heap.c.

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

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

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

◆ RemoveAttributeById()

void RemoveAttributeById ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 1673 of file heap.c.

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

3931{
3932 Relation rel;
3933 HeapTuple tuple;
3934
3935 rel = table_open(PartitionedRelationId, RowExclusiveLock);
3936
3937 tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
3938 if (!HeapTupleIsValid(tuple))
3939 elog(ERROR, "cache lookup failed for partition key of relation %u",
3940 relid);
3941
3942 CatalogTupleDelete(rel, &tuple->t_self);
3943
3944 ReleaseSysCache(tuple);
3946}

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

3404{
3405 Relation pgstatistic;
3406 SysScanDesc scan;
3407 ScanKeyData key[2];
3408 int nkeys;
3409 HeapTuple tuple;
3410
3411 pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
3412
3413 ScanKeyInit(&key[0],
3414 Anum_pg_statistic_starelid,
3415 BTEqualStrategyNumber, F_OIDEQ,
3416 ObjectIdGetDatum(relid));
3417
3418 if (attnum == 0)
3419 nkeys = 1;
3420 else
3421 {
3422 ScanKeyInit(&key[1],
3423 Anum_pg_statistic_staattnum,
3424 BTEqualStrategyNumber, F_INT2EQ,
3426 nkeys = 2;
3427 }
3428
3429 scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
3430 NULL, nkeys, key);
3431
3432 /* we must loop even when attnum != 0, in case of inherited stats */
3433 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3434 CatalogTupleDelete(pgstatistic, &tuple->t_self);
3435
3436 systable_endscan(scan);
3437
3438 table_close(pgstatistic, RowExclusiveLock);
3439}

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

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

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

Referenced by binary_upgrade_set_missing_value().

◆ StoreAttrMissingVal()

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

Definition at line 2020 of file heap.c.

2021{
2022 Datum valuesAtt[Natts_pg_attribute] = {0};
2023 bool nullsAtt[Natts_pg_attribute] = {0};
2024 bool replacesAtt[Natts_pg_attribute] = {0};
2025 Relation attrrel;
2026 Form_pg_attribute attStruct;
2027 HeapTuple atttup,
2028 newtup;
2029
2030 /* This is only supported for plain tables */
2031 Assert(rel->rd_rel->relkind == RELKIND_RELATION);
2032
2033 /* Fetch the pg_attribute row */
2034 attrrel = table_open(AttributeRelationId, RowExclusiveLock);
2035
2036 atttup = SearchSysCache2(ATTNUM,
2039 if (!HeapTupleIsValid(atttup)) /* shouldn't happen */
2040 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2041 attnum, RelationGetRelid(rel));
2042 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
2043
2044 /* Make a one-element array containing the value */
2045 missingval = PointerGetDatum(construct_array(&missingval,
2046 1,
2047 attStruct->atttypid,
2048 attStruct->attlen,
2049 attStruct->attbyval,
2050 attStruct->attalign));
2051
2052 /* Update the pg_attribute row */
2053 valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
2054 replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
2055
2056 valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
2057 replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
2058
2059 newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
2060 valuesAtt, nullsAtt, replacesAtt);
2061 CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
2062
2063 /* clean up */
2064 ReleaseSysCache(atttup);
2065 table_close(attrrel, RowExclusiveLock);
2066}
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().

◆ StorePartitionBound()

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

Definition at line 3961 of file heap.c.

3962{
3963 Relation classRel;
3964 HeapTuple tuple,
3965 newtuple;
3966 Datum new_val[Natts_pg_class];
3967 bool new_null[Natts_pg_class],
3968 new_repl[Natts_pg_class];
3969 Oid defaultPartOid;
3970
3971 /* Update pg_class tuple */
3972 classRel = table_open(RelationRelationId, RowExclusiveLock);
3973 tuple = SearchSysCacheCopy1(RELOID,
3975 if (!HeapTupleIsValid(tuple))
3976 elog(ERROR, "cache lookup failed for relation %u",
3977 RelationGetRelid(rel));
3978
3979#ifdef USE_ASSERT_CHECKING
3980 {
3981 Form_pg_class classForm;
3982 bool isnull;
3983
3984 classForm = (Form_pg_class) GETSTRUCT(tuple);
3985 Assert(!classForm->relispartition);
3986 (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
3987 &isnull);
3988 Assert(isnull);
3989 }
3990#endif
3991
3992 /* Fill in relpartbound value */
3993 memset(new_val, 0, sizeof(new_val));
3994 memset(new_null, false, sizeof(new_null));
3995 memset(new_repl, false, sizeof(new_repl));
3996 new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
3997 new_null[Anum_pg_class_relpartbound - 1] = false;
3998 new_repl[Anum_pg_class_relpartbound - 1] = true;
3999 newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
4000 new_val, new_null, new_repl);
4001 /* Also set the flag */
4002 ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
4003
4004 /*
4005 * We already checked for no inheritance children, but reset
4006 * relhassubclass in case it was left over.
4007 */
4008 if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
4009 ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
4010
4011 CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
4012 heap_freetuple(newtuple);
4013 table_close(classRel, RowExclusiveLock);
4014
4015 /*
4016 * If we're storing bounds for the default partition, update
4017 * pg_partitioned_table too.
4018 */
4019 if (bound->is_default)
4021 RelationGetRelid(rel));
4022
4023 /* Make these updates visible */
4025
4026 /*
4027 * The partition constraint for the default partition depends on the
4028 * partition bounds of every other partition, so we must invalidate the
4029 * relcache entry for that partition every time a partition is added or
4030 * removed.
4031 */
4032 defaultPartOid =
4034 if (OidIsValid(defaultPartOid))
4035 CacheInvalidateRelcacheByRelid(defaultPartOid);
4036
4038}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1621
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:501
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void CommandCounterIncrement(void)
Definition: xact.c:1100

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

3812{
3813 int i;
3814 int2vector *partattrs_vec;
3815 oidvector *partopclass_vec;
3816 oidvector *partcollation_vec;
3817 Datum partexprDatum;
3818 Relation pg_partitioned_table;
3819 HeapTuple tuple;
3820 Datum values[Natts_pg_partitioned_table];
3821 bool nulls[Natts_pg_partitioned_table] = {0};
3822 ObjectAddress myself;
3823 ObjectAddress referenced;
3824 ObjectAddresses *addrs;
3825
3826 Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3827
3828 /* Copy the partition attribute numbers, opclass OIDs into arrays */
3829 partattrs_vec = buildint2vector(partattrs, partnatts);
3830 partopclass_vec = buildoidvector(partopclass, partnatts);
3831 partcollation_vec = buildoidvector(partcollation, partnatts);
3832
3833 /* Convert the expressions (if any) to a text datum */
3834 if (partexprs)
3835 {
3836 char *exprString;
3837
3838 exprString = nodeToString(partexprs);
3839 partexprDatum = CStringGetTextDatum(exprString);
3840 pfree(exprString);
3841 }
3842 else
3843 partexprDatum = (Datum) 0;
3844
3845 pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
3846
3847 /* Only this can ever be NULL */
3848 if (!partexprDatum)
3849 nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3850
3851 values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
3852 values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
3853 values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
3854 values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
3855 values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
3856 values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
3857 values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
3858 values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
3859
3860 tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
3861
3862 CatalogTupleInsert(pg_partitioned_table, tuple);
3863 table_close(pg_partitioned_table, RowExclusiveLock);
3864
3865 /* Mark this relation as dependent on a few things as follows */
3866 addrs = new_object_addresses();
3867 ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
3868
3869 /* Operator class and collation per key column */
3870 for (i = 0; i < partnatts; i++)
3871 {
3872 ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
3873 add_exact_object_address(&referenced, addrs);
3874
3875 /* The default collation is pinned, so don't bother recording it */
3876 if (OidIsValid(partcollation[i]) &&
3877 partcollation[i] != DEFAULT_COLLATION_OID)
3878 {
3879 ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
3880 add_exact_object_address(&referenced, addrs);
3881 }
3882 }
3883
3885 free_object_addresses(addrs);
3886
3887 /*
3888 * The partitioning columns are made internally dependent on the table,
3889 * because we cannot drop any of them without dropping the whole table.
3890 * (ATExecDropColumn independently enforces that, but it's not bulletproof
3891 * so we need the dependencies too.)
3892 */
3893 for (i = 0; i < partnatts; i++)
3894 {
3895 if (partattrs[i] == 0)
3896 continue; /* ignore expressions here */
3897
3898 ObjectAddressSubSet(referenced, RelationRelationId,
3899 RelationGetRelid(rel), partattrs[i]);
3900 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
3901 }
3902
3903 /*
3904 * Also consider anything mentioned in partition expressions. External
3905 * references (e.g. functions) get NORMAL dependencies. Table columns
3906 * mentioned in the expressions are handled the same as plain partitioning
3907 * columns, i.e. they become internally dependent on the whole table.
3908 */
3909 if (partexprs)
3911 (Node *) partexprs,
3912 RelationGetRelid(rel),
3915 true /* reverse the self-deps */ );
3916
3917 /*
3918 * We must invalidate the relcache so that the next
3919 * CommandCounterIncrement() will cause the same to be rebuilt using the
3920 * information in just created catalog entry.
3921 */
3923}
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
Definition: c.h:686
Definition: c.h:697

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

Referenced by DefineRelation().

◆ SystemAttributeByName()

const FormData_pg_attribute * SystemAttributeByName ( const char *  attname)

Definition at line 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}
#define lengthof(array)
Definition: c.h:759
static const FormData_pg_attribute *const SysAtt[]
Definition: heap.c:228

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