PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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, List *existing_constraints)
 
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 
)
extern

Definition at line 2401 of file heap.c.

2408{
2412 int numoldchecks;
2413 ParseState *pstate;
2415 int numchecks;
2417 List *nnnames;
2418 Node *expr;
2420
2421 /*
2422 * Get info about existing constraints.
2423 */
2425 oldconstr = tupleDesc->constr;
2426 if (oldconstr)
2427 numoldchecks = oldconstr->num_check;
2428 else
2429 numoldchecks = 0;
2430
2431 /*
2432 * Create a dummy ParseState and insert the target relation as its sole
2433 * rangetable entry. We need a ParseState for transformExpr.
2434 */
2435 pstate = make_parsestate(NULL);
2436 pstate->p_sourcetext = queryString;
2438 rel,
2440 NULL,
2441 false,
2442 true);
2443 addNSItemToQuery(pstate, nsitem, true, true, true);
2444
2445 /*
2446 * Process column default expressions.
2447 */
2449 {
2450 Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
2451 Oid defOid;
2452
2453 expr = cookDefault(pstate, colDef->raw_default,
2454 atp->atttypid, atp->atttypmod,
2455 NameStr(atp->attname),
2456 atp->attgenerated);
2457
2458 /*
2459 * If the expression is just a NULL constant, we do not bother to make
2460 * an explicit pg_attrdef entry, since the default behavior is
2461 * equivalent. This applies to column defaults, but not for
2462 * generation expressions.
2463 *
2464 * Note a nonobvious property of this test: if the column is of a
2465 * domain type, what we'll get is not a bare null Const but a
2466 * CoerceToDomain expr, so we will not discard the default. This is
2467 * critical because the column default needs to be retained to
2468 * override any default that the domain might have.
2469 */
2470 if (expr == NULL ||
2471 (!colDef->generated &&
2472 IsA(expr, Const) &&
2473 castNode(Const, expr)->constisnull))
2474 continue;
2475
2476 defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal);
2477
2479 cooked->contype = CONSTR_DEFAULT;
2480 cooked->conoid = defOid;
2481 cooked->name = NULL;
2482 cooked->attnum = colDef->attnum;
2483 cooked->expr = expr;
2484 cooked->is_enforced = true;
2485 cooked->skip_validation = false;
2486 cooked->is_local = is_local;
2487 cooked->inhcount = is_local ? 0 : 1;
2488 cooked->is_no_inherit = false;
2490 }
2491
2492 /*
2493 * Process constraint expressions.
2494 */
2496 checknames = NIL;
2497 nnnames = NIL;
2499 {
2500 Oid constrOid;
2501
2502 if (cdef->contype == CONSTR_CHECK)
2503 {
2504 char *ccname;
2505
2506 if (cdef->raw_expr != NULL)
2507 {
2508 Assert(cdef->cooked_expr == NULL);
2509
2510 /*
2511 * Transform raw parsetree to executable expression, and
2512 * verify it's valid as a CHECK constraint.
2513 */
2514 expr = cookConstraint(pstate, cdef->raw_expr,
2516 }
2517 else
2518 {
2519 Assert(cdef->cooked_expr != NULL);
2520
2521 /*
2522 * Here, we assume the parser will only pass us valid CHECK
2523 * expressions, so we do no particular checking.
2524 */
2525 expr = stringToNode(cdef->cooked_expr);
2526 }
2527
2528 /*
2529 * Check name uniqueness, or generate a name if none was given.
2530 */
2531 if (cdef->conname != NULL)
2532 {
2533 ccname = cdef->conname;
2534 /* Check against other new constraints */
2535 /* Needed because we don't do CommandCounterIncrement in loop */
2537 {
2538 if (strcmp(chkname, ccname) == 0)
2539 ereport(ERROR,
2541 errmsg("check constraint \"%s\" already exists",
2542 ccname)));
2543 }
2544
2545 /* save name for future checks */
2546 checknames = lappend(checknames, ccname);
2547
2548 /*
2549 * Check against pre-existing constraints. If we are allowed
2550 * to merge with an existing constraint, there's no more to do
2551 * here. (We omit the duplicate constraint from the result,
2552 * which is what ATAddCheckNNConstraint wants.)
2553 */
2554 if (MergeWithExistingConstraint(rel, ccname, expr,
2555 allow_merge, is_local,
2556 cdef->is_enforced,
2557 cdef->initially_valid,
2558 cdef->is_no_inherit))
2559 continue;
2560 }
2561 else
2562 {
2563 /*
2564 * When generating a name, we want to create "tab_col_check"
2565 * for a column constraint and "tab_check" for a table
2566 * constraint. We no longer have any info about the syntactic
2567 * positioning of the constraint phrase, so we approximate
2568 * this by seeing whether the expression references more than
2569 * one column. (If the user played by the rules, the result
2570 * is the same...)
2571 *
2572 * Note: pull_var_clause() doesn't descend into sublinks, but
2573 * we eliminated those above; and anyway this only needs to be
2574 * an approximate answer.
2575 */
2576 List *vars;
2577 char *colname;
2578
2579 vars = pull_var_clause(expr, 0);
2580
2581 /* eliminate duplicates */
2582 vars = list_union(NIL, vars);
2583
2584 if (list_length(vars) == 1)
2585 colname = get_attname(RelationGetRelid(rel),
2586 ((Var *) linitial(vars))->varattno,
2587 true);
2588 else
2589 colname = NULL;
2590
2592 colname,
2593 "check",
2595 checknames);
2596
2597 /* save name for future checks */
2598 checknames = lappend(checknames, ccname);
2599 }
2600
2601 /*
2602 * OK, store it.
2603 */
2604 constrOid =
2605 StoreRelCheck(rel, ccname, expr, cdef->is_enforced,
2606 cdef->initially_valid, is_local,
2607 is_local ? 0 : 1, cdef->is_no_inherit,
2608 is_internal);
2609
2610 numchecks++;
2611
2613 cooked->contype = CONSTR_CHECK;
2614 cooked->conoid = constrOid;
2615 cooked->name = ccname;
2616 cooked->attnum = 0;
2617 cooked->expr = expr;
2618 cooked->is_enforced = cdef->is_enforced;
2619 cooked->skip_validation = cdef->skip_validation;
2620 cooked->is_local = is_local;
2621 cooked->inhcount = is_local ? 0 : 1;
2622 cooked->is_no_inherit = cdef->is_no_inherit;
2624 }
2625 else if (cdef->contype == CONSTR_NOTNULL)
2626 {
2628 AttrNumber colnum;
2629 int16 inhcount = is_local ? 0 : 1;
2630 char *nnname;
2631
2632 /* Determine which column to modify */
2633 colnum = get_attnum(RelationGetRelid(rel), strVal(linitial(cdef->keys)));
2634 if (colnum == InvalidAttrNumber)
2635 ereport(ERROR,
2637 errmsg("column \"%s\" of relation \"%s\" does not exist",
2639 if (colnum < InvalidAttrNumber)
2640 ereport(ERROR,
2642 errmsg("cannot add not-null constraint on system column \"%s\"",
2643 strVal(linitial(cdef->keys))));
2644
2645 Assert(cdef->initially_valid != cdef->skip_validation);
2646
2647 /*
2648 * If the column already has a not-null constraint, we don't want
2649 * to add another one; adjust inheritance status as needed. This
2650 * also checks whether the existing constraint matches the
2651 * requested validity.
2652 */
2654 cdef->conname,
2655 is_local, cdef->is_no_inherit,
2656 cdef->skip_validation))
2657 continue;
2658
2659 /*
2660 * If a constraint name is specified, check that it isn't already
2661 * used. Otherwise, choose a non-conflicting one ourselves.
2662 */
2663 if (cdef->conname)
2664 {
2666 RelationGetRelid(rel),
2667 cdef->conname))
2668 ereport(ERROR,
2670 errmsg("constraint \"%s\" for relation \"%s\" already exists",
2671 cdef->conname, RelationGetRelationName(rel)));
2672 nnname = cdef->conname;
2673 }
2674 else
2676 strVal(linitial(cdef->keys)),
2677 "not_null",
2679 nnnames);
2681
2682 constrOid =
2683 StoreRelNotNull(rel, nnname, colnum,
2684 cdef->initially_valid,
2685 is_local,
2686 inhcount,
2687 cdef->is_no_inherit);
2688
2690 nncooked->contype = CONSTR_NOTNULL;
2691 nncooked->conoid = constrOid;
2692 nncooked->name = nnname;
2693 nncooked->attnum = colnum;
2694 nncooked->expr = NULL;
2695 nncooked->is_enforced = true;
2696 nncooked->skip_validation = cdef->skip_validation;
2697 nncooked->is_local = is_local;
2698 nncooked->inhcount = inhcount;
2699 nncooked->is_no_inherit = cdef->is_no_inherit;
2700
2702 }
2703 }
2704
2705 /*
2706 * Update the count of constraints in the relation's pg_class tuple. We do
2707 * this even if there was no change, in order to ensure that an SI update
2708 * message is sent out for the pg_class tuple, which will force other
2709 * backends to rebuild their relcache entries for the rel. (This is
2710 * critical if we added defaults but not constraints.)
2711 */
2713
2714 return cookedConstraints;
2715}
int16 AttrNumber
Definition attnum.h:21
#define InvalidAttrNumber
Definition attnum.h:23
#define NameStr(name)
Definition c.h:835
#define Assert(condition)
Definition c.h:943
int16_t int16
Definition c.h:619
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
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:2163
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:2728
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:2270
static void SetRelationNumChecks(Relation rel, int numchecks)
Definition heap.c:3165
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition heap.c:3339
static Node * cookConstraint(ParseState *pstate, Node *raw_constraint, char *relname)
Definition heap.c:3420
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:1015
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:984
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static char * errmsg
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
@ CONSTR_DEFAULT
@ CONSTR_NOTNULL
@ CONSTR_CHECK
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr, bool is_internal)
Definition pg_attrdef.c:37
FormData_pg_attribute * Form_pg_attribute
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
bool AdjustNotNullInheritance(Oid relid, AttrNumber attnum, const char *new_conname, bool is_local, bool is_no_inherit, bool is_notvalid)
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
@ 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:501
#define linitial(l)
Definition pg_list.h:178
#define foreach_node(type, var, lst)
Definition pg_list.h:528
unsigned int Oid
static int fb(int x)
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
Definition pg_list.h:54
Definition nodes.h:135
const char * p_sourcetext
Definition parse_node.h:214
TupleDesc rd_att
Definition rel.h:112
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
#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, castNode, ChooseConstraintName(), CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_NOTNULL, CONSTRAINT_RELATION, ConstraintNameIsUsed(), cookConstraint(), cookDefault(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), foreach_node, foreach_ptr, get_attname(), get_attnum(), InvalidAttrNumber, IsA, lappend(), linitial, list_length(), list_union(), make_parsestate(), MergeWithExistingConstraint(), NameStr, NIL, ParseState::p_sourcetext, palloc_object, pull_var_clause(), RelationData::rd_att, RelationGetDescr, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, SetRelationNumChecks(), StoreAttrDefault(), StoreRelCheck(), StoreRelNotNull(), stringToNode(), strVal, and TupleDescAttr().

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

◆ AddRelationNotNullConstraints()

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

Definition at line 2913 of file heap.c.

2915{
2917 List *nnnames;
2918 List *nncols = NIL;
2919
2920 /*
2921 * We track two lists of names: nnnames keeps all the constraint names,
2922 * givennames tracks user-generated names. The distinction is important,
2923 * because we must raise error for user-generated name conflicts, but for
2924 * system-generated name conflicts we just generate another.
2925 */
2926 nnnames = list_copy(existing_constraints); /* don't scribble on input */
2927 givennames = NIL;
2928
2929 /*
2930 * First, create all not-null constraints that are directly specified by
2931 * the user. Note that inheritance might have given us another source for
2932 * each, so we must scan the old_notnulls list and increment inhcount for
2933 * each element with identical attnum. We delete from there any element
2934 * that we process.
2935 *
2936 * We don't use foreach() here because we have two nested loops over the
2937 * constraint list, with possible element deletions in the inner one. If
2938 * we used foreach_delete_current() it could only fix up the state of one
2939 * of the loops, so it seems cleaner to use looping over list indexes for
2940 * both loops. Note that any deletion will happen beyond where the outer
2941 * loop is, so its index never needs adjustment.
2942 */
2943 for (int outerpos = 0; outerpos < list_length(constraints); outerpos++)
2944 {
2945 Constraint *constr;
2947 char *conname;
2948 int inhcount = 0;
2949
2950 constr = list_nth_node(Constraint, constraints, outerpos);
2951
2952 Assert(constr->contype == CONSTR_NOTNULL);
2953
2955 strVal(linitial(constr->keys)));
2957 ereport(ERROR,
2959 errmsg("column \"%s\" of relation \"%s\" does not exist",
2960 strVal(linitial(constr->keys)),
2963 ereport(ERROR,
2965 errmsg("cannot add not-null constraint on system column \"%s\"",
2966 strVal(linitial(constr->keys))));
2967
2968 /*
2969 * A column can only have one not-null constraint, so discard any
2970 * additional ones that appear for columns we already saw; but check
2971 * that the NO INHERIT flags match.
2972 */
2973 for (int restpos = outerpos + 1; restpos < list_length(constraints);)
2974 {
2976
2977 other = list_nth_node(Constraint, constraints, restpos);
2978 if (strcmp(strVal(linitial(constr->keys)),
2979 strVal(linitial(other->keys))) == 0)
2980 {
2981 if (other->is_no_inherit != constr->is_no_inherit)
2982 ereport(ERROR,
2984 errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
2985 strVal(linitial(constr->keys))));
2986
2987 /*
2988 * Preserve constraint name if one is specified, but raise an
2989 * error if conflicting ones are specified.
2990 */
2991 if (other->conname)
2992 {
2993 if (!constr->conname)
2994 constr->conname = pstrdup(other->conname);
2995 else if (strcmp(constr->conname, other->conname) != 0)
2996 ereport(ERROR,
2998 errmsg("conflicting not-null constraint names \"%s\" and \"%s\"",
2999 constr->conname, other->conname));
3000 }
3001
3002 /* XXX do we need to verify any other fields? */
3003 constraints = list_delete_nth_cell(constraints, restpos);
3004 }
3005 else
3006 restpos++;
3007 }
3008
3009 /*
3010 * Search in the list of inherited constraints for any entries on the
3011 * same column; determine an inheritance count from that. Also, if at
3012 * least one parent has a constraint for this column, then we must not
3013 * accept a user specification for a NO INHERIT one. Any constraint
3014 * from parents that we process here is deleted from the list: we no
3015 * longer need to process it in the loop below.
3016 */
3018 {
3019 if (old->attnum == attnum)
3020 {
3021 /*
3022 * If we get a constraint from the parent, having a local NO
3023 * INHERIT one doesn't work.
3024 */
3025 if (constr->is_no_inherit)
3026 ereport(ERROR,
3028 errmsg("cannot define not-null constraint with NO INHERIT on column \"%s\"",
3029 strVal(linitial(constr->keys))),
3030 errdetail("The column has an inherited not-null constraint.")));
3031
3032 inhcount++;
3034 }
3035 }
3036
3037 /*
3038 * Determine a constraint name, which may have been specified by the
3039 * user, or raise an error if a conflict exists with another
3040 * user-specified name.
3041 */
3042 if (constr->conname)
3043 {
3045 {
3046 if (strcmp(thisname, constr->conname) == 0)
3047 ereport(ERROR,
3049 errmsg("constraint \"%s\" for relation \"%s\" already exists",
3050 constr->conname,
3052 }
3053
3054 conname = constr->conname;
3055 givennames = lappend(givennames, conname);
3056 }
3057 else
3060 attnum, false),
3061 "not_null",
3063 nnnames);
3064 nnnames = lappend(nnnames, conname);
3065
3066 StoreRelNotNull(rel, conname,
3067 attnum, true, true,
3068 inhcount, constr->is_no_inherit);
3069
3071 }
3072
3073 /*
3074 * If any column remains in the old_notnulls list, we must create a not-
3075 * null constraint marked not-local for that column. Because multiple
3076 * parents could specify a not-null constraint for the same column, we
3077 * must count how many there are and set an appropriate inhcount
3078 * accordingly, deleting elements we've already processed.
3079 *
3080 * We don't use foreach() here because we have two nested loops over the
3081 * constraint list, with possible element deletions in the inner one. If
3082 * we used foreach_delete_current() it could only fix up the state of one
3083 * of the loops, so it seems cleaner to use looping over list indexes for
3084 * both loops. Note that any deletion will happen beyond where the outer
3085 * loop is, so its index never needs adjustment.
3086 */
3088 {
3090 char *conname = NULL;
3091 int inhcount = 1;
3092
3094 Assert(cooked->contype == CONSTR_NOTNULL);
3095 Assert(cooked->name);
3096
3097 /*
3098 * Preserve the first non-conflicting constraint name we come across.
3099 */
3100 if (conname == NULL)
3101 conname = cooked->name;
3102
3103 for (int restpos = outerpos + 1; restpos < list_length(old_notnulls);)
3104 {
3106
3108 Assert(other->name);
3109 if (other->attnum == cooked->attnum)
3110 {
3111 if (conname == NULL)
3112 conname = other->name;
3113
3114 inhcount++;
3116 }
3117 else
3118 restpos++;
3119 }
3120
3121 /* If we got a name, make sure it isn't one we've already used */
3122 if (conname != NULL)
3123 {
3125 {
3126 if (strcmp(thisname, conname) == 0)
3127 {
3128 conname = NULL;
3129 break;
3130 }
3131 }
3132 }
3133
3134 /* and choose a name, if needed */
3135 if (conname == NULL)
3138 cooked->attnum, false),
3139 "not_null",
3141 nnnames);
3142 nnnames = lappend(nnnames, conname);
3143
3144 /* ignore the origin constraint's is_local and inhcount */
3145 StoreRelNotNull(rel, conname, cooked->attnum, true,
3146 false, inhcount, false);
3147
3148 nncols = lappend_int(nncols, cooked->attnum);
3149 }
3150
3151 return nncols;
3152}
int errdetail(const char *fmt,...) pg_attribute_printf(1
List * list_delete_nth_cell(List *list, int n)
Definition list.c:767
List * list_copy(const List *oldlist)
Definition list.c:1573
List * lappend_int(List *list, int datum)
Definition list.c:357
char * pstrdup(const char *in)
Definition mcxt.c:1910
int16 attnum
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:423
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define list_nth_node(type, list, n)
Definition pg_list.h:359
List * keys
ConstrType contype
bool is_no_inherit
char * conname

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

Referenced by DefineRelation().

◆ CheckAttributeNamesTypes()

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

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 */
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)
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)
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 {
507 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
508
509 if (attr->attisdropped)
510 continue;
511 CheckAttributeType(NameStr(attr->attname),
512 attr->atttypid,
513 attr->attcollation,
514 NIL, /* assume we're creating a new rowtype */
515 flags | (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL ? CHKATYPE_IS_VIRTUAL : 0));
516 }
517}
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition heap.c:548
const FormData_pg_attribute * SystemAttributeByName(const char *attname)
Definition heap.c:248
#define CHKATYPE_IS_VIRTUAL
Definition heap.h:26
#define MaxHeapAttributeNumber
int j
Definition isn.c:78
int i
Definition isn.c:77
NameData attname

References attname, CheckAttributeType(), CHKATYPE_IS_VIRTUAL, ereport, errcode(), errmsg, ERROR, fb(), 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 
)
extern

Definition at line 548 of file heap.c.

552{
555
556 /* since this function recurses, it could be driven to stack overflow */
558
560 {
561 /*
562 * We disallow pseudo-type columns, with the exception of ANYARRAY,
563 * RECORD, and RECORD[] when the caller says that those are OK.
564 *
565 * We don't need to worry about recursive containment for RECORD and
566 * RECORD[] because (a) no named composite type should be allowed to
567 * contain those, and (b) two "anonymous" record types couldn't be
568 * considered to be the same type, so infinite recursion isn't
569 * possible.
570 */
571 if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
572 (atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
573 (atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
574 {
575 if (flags & CHKATYPE_IS_PARTKEY)
578 /* translator: first %s is an integer not a name */
579 errmsg("partition key column %s has pseudo-type %s",
581 else
584 errmsg("column \"%s\" has pseudo-type %s",
586 }
587 }
588 else if (att_typtype == TYPTYPE_DOMAIN)
589 {
590 /*
591 * Prevent virtual generated columns from having a domain type. We
592 * would have to enforce domain constraints when columns underlying
593 * the generated column change. This could possibly be implemented,
594 * but it's not.
595 */
596 if (flags & CHKATYPE_IS_VIRTUAL)
599 errmsg("virtual generated column \"%s\" cannot have a domain type", attname));
600
601 /*
602 * If it's a domain, recurse to check its base type.
603 */
606 flags);
607 }
608 else if (att_typtype == TYPTYPE_COMPOSITE)
609 {
610 /*
611 * For a composite type, recurse into its attributes.
612 */
613 Relation relation;
614 TupleDesc tupdesc;
615 int i;
616
617 /*
618 * Check for self-containment. Eventually we might be able to allow
619 * this (just return without complaint, if so) but it's not clear how
620 * many other places would require anti-recursion defenses before it
621 * would be safe to allow tables to contain their own rowtype.
622 */
626 errmsg("composite type %s cannot be made a member of itself",
628
630
632
633 tupdesc = RelationGetDescr(relation);
634
635 for (i = 0; i < tupdesc->natts; i++)
636 {
637 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
638
639 if (attr->attisdropped)
640 continue;
641 CheckAttributeType(NameStr(attr->attname),
642 attr->atttypid, attr->attcollation,
644 flags & ~CHKATYPE_IS_PARTKEY);
645 }
646
648
650 }
651 else if (att_typtype == TYPTYPE_RANGE)
652 {
653 /*
654 * If it's a range, recurse to check its subtype.
655 */
659 flags);
660 }
662 {
663 /*
664 * If it's a multirange, recurse to check its plain range type.
665 */
667 InvalidOid, /* range types are not collatable */
669 flags);
670 }
672 {
673 /*
674 * Must recurse into array types, too, in case they are composite.
675 */
678 flags);
679 }
680
681 /*
682 * For consistency with check_virtual_generated_security().
683 */
687 errmsg("virtual generated column \"%s\" cannot have a user-defined type", attname),
688 errdetail("Virtual generated columns that make use of user-defined types are not yet supported."));
689
690 /*
691 * This might not be strictly invalid per SQL standard, but it is pretty
692 * useless, and it cannot be dumped, so we must disallow it.
693 */
694 if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
695 {
696 if (flags & CHKATYPE_IS_PARTKEY)
699 /* translator: first %s is an integer not a name */
700 errmsg("no collation was derived for partition key column %s with collatable type %s",
702 errhint("Use the COLLATE clause to set the collation explicitly.")));
703 else
706 errmsg("no collation was derived for column \"%s\" with collatable type %s",
708 errhint("Use the COLLATE clause to set the collation explicitly.")));
709 }
710}
#define OidIsValid(objectId)
Definition c.h:858
int errhint(const char *fmt,...) pg_attribute_printf(1
char * format_type_be(Oid type_oid)
#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:3660
Oid get_element_type(Oid typid)
Definition lsyscache.c:2992
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3761
Oid get_range_collation(Oid rangeOid)
Definition lsyscache.c:3686
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3314
Oid get_typ_typrelid(Oid typid)
Definition lsyscache.c:2964
char get_typtype(Oid typid)
Definition lsyscache.c:2862
Oid getBaseType(Oid typid)
Definition lsyscache.c:2754
#define InvalidOid
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
void check_stack_depth(void)
Definition stack_depth.c:95
#define FirstUnpinnedObjectId
Definition transam.h:196

References AccessShareLock, attname, check_stack_depth(), CheckAttributeType(), CHKATYPE_ANYARRAY, CHKATYPE_ANYRECORD, CHKATYPE_IS_PARTKEY, CHKATYPE_IS_VIRTUAL, ereport, errcode(), errdetail(), errhint(), errmsg, ERROR, fb(), FirstUnpinnedObjectId, format_type_be(), get_element_type(), get_multirange_range(), get_range_collation(), get_range_subtype(), get_typ_typrelid(), get_typtype(), getBaseType(), i, InvalidOid, 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 
)
extern

Definition at line 3339 of file heap.c.

3345{
3346 Node *expr;
3347
3348 Assert(raw_default != NULL);
3349
3350 /*
3351 * Transform raw parsetree to executable expression.
3352 */
3353 expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
3354
3355 if (attgenerated)
3356 {
3357 /* Disallow refs to other generated columns */
3358 check_nested_generated(pstate, expr);
3359
3360 /* Disallow mutable functions */
3362 ereport(ERROR,
3364 errmsg("generation expression is not immutable")));
3365
3366 /* Check security of expressions for virtual generated column */
3367 if (attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
3369 }
3370 else
3371 {
3372 /*
3373 * For a default expression, transformExpr() should have rejected
3374 * column references.
3375 */
3376 Assert(!contain_var_clause(expr));
3377 }
3378
3379 /*
3380 * Coerce the expression to the correct type and typmod, if given. This
3381 * should match the parser's processing of non-defaulted expressions ---
3382 * see transformAssignedExpr().
3383 */
3384 if (OidIsValid(atttypid))
3385 {
3386 Oid type_id = exprType(expr);
3387
3388 expr = coerce_to_target_type(pstate, expr, type_id,
3389 atttypid, atttypmod,
3392 -1);
3393 if (expr == NULL)
3394 ereport(ERROR,
3396 errmsg("column \"%s\" is of type %s"
3397 " but default expression is of type %s",
3398 attname,
3400 format_type_be(type_id)),
3401 errhint("You will need to rewrite or cast the expression.")));
3402 }
3403
3404 /*
3405 * Finally, take care of collations in the finished expression.
3406 */
3407 assign_expr_collations(pstate, expr);
3408
3409 return expr;
3410}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition clauses.c:503
static void check_virtual_generated_security(ParseState *pstate, Node *node)
Definition heap.c:3321
static void check_nested_generated(ParseState *pstate, Node *node)
Definition heap.c:3241
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)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
@ EXPR_KIND_COLUMN_DEFAULT
Definition parse_node.h:71
@ EXPR_KIND_GENERATED_COLUMN
Definition parse_node.h:84
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCION_ASSIGNMENT
Definition primnodes.h:748
bool contain_var_clause(Node *node)
Definition var.c:406

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

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

◆ CopyStatistics()

void CopyStatistics ( Oid  fromrelid,
Oid  torelid 
)
extern

Definition at line 3458 of file heap.c.

3459{
3460 HeapTuple tup;
3461 SysScanDesc scan;
3462 ScanKeyData key[1];
3465
3467
3468 /* Now search for stat records */
3469 ScanKeyInit(&key[0],
3473
3475 true, NULL, 1, key);
3476
3477 while (HeapTupleIsValid((tup = systable_getnext(scan))))
3478 {
3480
3481 /* make a modifiable copy */
3484
3485 /* update the copy of the tuple and insert it */
3486 statform->starelid = torelid;
3487
3488 /* fetch index information when we know we need it */
3489 if (indstate == NULL)
3491
3493
3495 }
3496
3497 systable_endscan(scan);
3498
3499 if (indstate != NULL)
3502}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:612
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:523
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:686
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
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
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
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(), fb(), GETSTRUCT(), heap_copytuple(), heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by index_concurrently_swap().

◆ DeleteAttributeTuples()

void DeleteAttributeTuples ( Oid  relid)
extern

Definition at line 1621 of file heap.c.

1622{
1624 SysScanDesc scan;
1625 ScanKeyData key[1];
1627
1628 /* Grab an appropriate lock on the pg_attribute relation */
1630
1631 /* Use the index to scan only attributes of the target relation */
1632 ScanKeyInit(&key[0],
1635 ObjectIdGetDatum(relid));
1636
1638 NULL, 1, key);
1639
1640 /* Delete all the matching tuples */
1641 while ((atttup = systable_getnext(scan)) != NULL)
1642 CatalogTupleDelete(attrel, &atttup->t_self);
1643
1644 /* Clean up after the scan */
1645 systable_endscan(scan);
1647}
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365

References BTEqualStrategyNumber, CatalogTupleDelete(), fb(), ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteRelationTuple()

void DeleteRelationTuple ( Oid  relid)
extern

Definition at line 1592 of file heap.c.

1593{
1595 HeapTuple tup;
1596
1597 /* Grab an appropriate lock on the pg_class relation */
1599
1601 if (!HeapTupleIsValid(tup))
1602 elog(ERROR, "cache lookup failed for relation %u", relid);
1603
1604 /* delete the relation tuple from pg_class, and finish up */
1606
1608
1610}
#define elog(elevel,...)
Definition elog.h:228
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

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

Referenced by heap_drop_with_catalog(), and index_drop().

◆ DeleteSystemAttributeTuples()

void DeleteSystemAttributeTuples ( Oid  relid)
extern

Definition at line 1658 of file heap.c.

1659{
1661 SysScanDesc scan;
1662 ScanKeyData key[2];
1664
1665 /* Grab an appropriate lock on the pg_attribute relation */
1667
1668 /* Use the index to scan only system attributes of the target relation */
1669 ScanKeyInit(&key[0],
1672 ObjectIdGetDatum(relid));
1673 ScanKeyInit(&key[1],
1676 Int16GetDatum(0));
1677
1679 NULL, 2, key);
1680
1681 /* Delete all the matching tuples */
1682 while ((atttup = systable_getnext(scan)) != NULL)
1683 CatalogTupleDelete(attrel, &atttup->t_self);
1684
1685 /* Clean up after the scan */
1686 systable_endscan(scan);
1688}
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
#define BTLessEqualStrategyNumber
Definition stratnum.h:30

References BTEqualStrategyNumber, BTLessEqualStrategyNumber, CatalogTupleDelete(), fb(), Int16GetDatum(), ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), 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 
)
extern

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 */
316 ((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
317 IsToastNamespace(relnamespace)) &&
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,
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)
401 reltablespace);
402
403 /* ensure that stats are dropped if transaction aborts */
405
406 return rel;
407}
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:261
bool IsCatalogNamespace(Oid namespaceId)
Definition catalog.c:243
Oid MyDatabaseTableSpace
Definition globals.c:98
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3599
#define IsNormalProcessingMode()
Definition miscadmin.h:497
#define InvalidMultiXactId
Definition multixact.h:25
NameData relname
Definition pg_class.h:40
void recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace)
void pgstat_create_relation(Relation rel)
Relation RelationBuildLocalRelation(const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid accessmtd, RelFileNumber relfilenumber, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
Definition relcache.c:3515
#define RelFileNumberIsValid(relnumber)
Definition relpath.h:27
SMgrRelation RelationCreateStorage(RelFileLocator rlocator, char relpersistence, bool register_delete)
Definition storage.c:122
RelFileLocator rd_locator
Definition rel.h:57
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:1687
#define InvalidTransactionId
Definition transam.h:31

References Assert, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), 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 
)
extern

Definition at line 1136 of file heap.c.

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

◆ heap_drop_with_catalog()

void heap_drop_with_catalog ( Oid  relid)
extern

Definition at line 1800 of file heap.c.

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

References AccessExclusiveLock, CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), CheckTableForSerializableConflictIn(), CheckTableNotInUse(), DeleteAttributeTuples(), DeleteRelationTuple(), elog, ERROR, fb(), 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(), table_close(), table_open(), and update_default_partition_oid().

Referenced by doDeletion().

◆ heap_truncate()

void heap_truncate ( List relids)
extern

Definition at line 3607 of file heap.c.

3608{
3609 List *relations = NIL;
3610 ListCell *cell;
3611
3612 /* Open relations for processing, and grab exclusive access on each */
3613 foreach(cell, relids)
3614 {
3615 Oid rid = lfirst_oid(cell);
3616 Relation rel;
3617
3618 rel = table_open(rid, AccessExclusiveLock);
3619 relations = lappend(relations, rel);
3620 }
3621
3622 /* Don't allow truncate on tables that are referenced by foreign keys */
3623 heap_truncate_check_FKs(relations, true);
3624
3625 /* OK to do it */
3626 foreach(cell, relations)
3627 {
3628 Relation rel = lfirst(cell);
3629
3630 /* Truncate the relation */
3632
3633 /* Close the relation, but keep exclusive lock on it until commit */
3634 table_close(rel, NoLock);
3635 }
3636}
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition heap.c:3692
void heap_truncate_one_rel(Relation rel)
Definition heap.c:3648
#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 
)
extern

Definition at line 3692 of file heap.c.

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

References ereport, errcode(), errdetail(), errhint(), errmsg, ERROR, fb(), 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)
extern

Definition at line 3787 of file heap.c.

3788{
3789 List *result = NIL;
3790 List *oids;
3792 ListCell *cell;
3796 HeapTuple tuple;
3797 bool restart;
3798
3799 oids = list_copy(relationIds);
3800
3801 /*
3802 * Must scan pg_constraint. Right now, it is a seqscan because there is
3803 * no available index on confrelid.
3804 */
3806
3807restart:
3808 restart = false;
3809 parent_cons = NIL;
3810
3812 NULL, 0, NULL);
3813
3815 {
3817
3818 /* Not a foreign key */
3819 if (con->contype != CONSTRAINT_FOREIGN)
3820 continue;
3821
3822 /* Not referencing one of our list of tables */
3823 if (!list_member_oid(oids, con->confrelid))
3824 continue;
3825
3826 /*
3827 * If this constraint has a parent constraint which we have not seen
3828 * yet, keep track of it for the second loop, below. Tracking parent
3829 * constraints allows us to climb up to the top-level constraint and
3830 * look for all possible relations referencing the partitioned table.
3831 */
3832 if (OidIsValid(con->conparentid) &&
3833 !list_member_oid(parent_cons, con->conparentid))
3834 parent_cons = lappend_oid(parent_cons, con->conparentid);
3835
3836 /*
3837 * Add referencer to result, unless present in input list. (Don't
3838 * worry about dupes: we'll fix that below).
3839 */
3840 if (!list_member_oid(relationIds, con->conrelid))
3841 result = lappend_oid(result, con->conrelid);
3842 }
3843
3845
3846 /*
3847 * Process each parent constraint we found to add the list of referenced
3848 * relations by them to the oids list. If we do add any new such
3849 * relations, redo the first loop above. Also, if we see that the parent
3850 * constraint in turn has a parent, add that so that we process all
3851 * relations in a single additional pass.
3852 */
3853 foreach(cell, parent_cons)
3854 {
3855 Oid parent = lfirst_oid(cell);
3856
3857 ScanKeyInit(&key,
3860 ObjectIdGetDatum(parent));
3861
3863 true, NULL, 1, &key);
3864
3865 tuple = systable_getnext(fkeyScan);
3866 if (HeapTupleIsValid(tuple))
3867 {
3869
3870 /*
3871 * pg_constraint rows always appear for partitioned hierarchies
3872 * this way: on the each side of the constraint, one row appears
3873 * for each partition that points to the top-most table on the
3874 * other side.
3875 *
3876 * Because of this arrangement, we can correctly catch all
3877 * relevant relations by adding to 'parent_cons' all rows with
3878 * valid conparentid, and to the 'oids' list all rows with a zero
3879 * conparentid. If any oids are added to 'oids', redo the first
3880 * loop above by setting 'restart'.
3881 */
3882 if (OidIsValid(con->conparentid))
3884 con->conparentid);
3885 else if (!list_member_oid(oids, con->confrelid))
3886 {
3887 oids = lappend_oid(oids, con->confrelid);
3888 restart = true;
3889 }
3890 }
3891
3893 }
3894
3896 if (restart)
3897 goto restart;
3898
3900 list_free(oids);
3901
3902 /* Now sort and de-duplicate the result list */
3905
3906 return result;
3907}
uint32 result
void list_sort(List *list, list_sort_comparator cmp)
Definition list.c:1674
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
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint

References AccessShareLock, BTEqualStrategyNumber, fb(), Form_pg_constraint, GETSTRUCT(), HeapTupleIsValid, InvalidOid, 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, result, 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)
extern

Definition at line 3648 of file heap.c.

3649{
3651
3652 /*
3653 * Truncate the relation. Partitioned tables have no storage, so there is
3654 * nothing to do for them here.
3655 */
3656 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3657 return;
3658
3659 /* Truncate the underlying relation */
3661
3662 /* If the relation has indexes, truncate the indexes too */
3664
3665 /* If there is a toast table, truncate that too */
3666 toastrelid = rel->rd_rel->reltoastrelid;
3668 {
3670
3673 /* keep the lock... */
3675 }
3676}
static void RelationTruncateIndexes(Relation heapRelation)
Definition heap.c:3558
static void table_relation_nontransactional_truncate(Relation rel)
Definition tableam.h:1705

References AccessExclusiveLock, fb(), 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 
)
extern

Definition at line 731 of file heap.c.

736{
737 TupleTableSlot **slot;
738 TupleDesc td;
739 int nslots;
740 int natts = 0;
741 int slotCount = 0;
742 bool close_index = false;
743
745
746 /* Initialize the number of slots to use */
747 nslots = Min(tupdesc->natts,
749 slot = palloc_array(TupleTableSlot *, nslots);
750 for (int i = 0; i < nslots; i++)
752
753 while (natts < tupdesc->natts)
754 {
755 Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts);
757
759
760 memset(slot[slotCount]->tts_isnull, false,
761 slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
762
763 if (new_rel_oid != InvalidOid)
765 else
767
787 if (attrs_extra)
788 {
789 slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.value;
790 slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.isnull;
791
792 slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.value;
793 slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull;
794 }
795 else
796 {
799 }
800
801 /*
802 * The remaining fields are not set for new columns.
803 */
807
809 slotCount++;
810
811 /*
812 * If slots are full or the end of processing has been reached, insert
813 * a batch of tuples.
814 */
815 if (slotCount == nslots || natts == tupdesc->natts - 1)
816 {
817 /* fetch index info only when we know we need it */
818 if (!indstate)
819 {
821 close_index = true;
822 }
823
824 /* insert the new tuples and update the indexes */
826 indstate);
827 slotCount = 0;
828 }
829
830 natts++;
831 }
832
833 if (close_index)
835 for (int i = 0; i < nslots; i++)
837 pfree(slot);
838}
#define Min(x, y)
Definition c.h:1091
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsHeapTuple
Definition execTuples.c:85
#define palloc_array(type, count)
Definition fe_memutils.h:91
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
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static Datum CharGetDatum(char X)
Definition postgres.h:132
bool * tts_isnull
Definition tuptable.h:133
Datum * tts_values
Definition tuptable.h:131
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476

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

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

◆ InsertPgClassTuple()

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

Definition at line 924 of file heap.c.

929{
930 Form_pg_class rd_rel = new_rel_desc->rd_rel;
932 bool nulls[Natts_pg_class];
934
935 /* This is a tad tedious, but way cleaner than what we used to do... */
936 memset(values, 0, sizeof(values));
937 memset(nulls, false, sizeof(nulls));
938
940 values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
941 values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
942 values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
943 values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
944 values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
945 values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
946 values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
947 values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
948 values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
949 values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
950 values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
951 values[Anum_pg_class_relallfrozen - 1] = Int32GetDatum(rd_rel->relallfrozen);
952 values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
953 values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
954 values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
955 values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
956 values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
957 values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
958 values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
959 values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
960 values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
961 values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity);
962 values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity);
963 values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
964 values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
965 values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident);
966 values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition);
967 values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
968 values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
969 values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
970 if (relacl != (Datum) 0)
972 else
973 nulls[Anum_pg_class_relacl - 1] = true;
974 if (reloptions != (Datum) 0)
975 values[Anum_pg_class_reloptions - 1] = reloptions;
976 else
977 nulls[Anum_pg_class_reloptions - 1] = true;
978
979 /* relpartbound is set by updating this tuple, if necessary */
980 nulls[Anum_pg_class_relpartbound - 1] = true;
981
983
984 /* finally insert the new tuple, update the indexes, and clean up */
986
988}
static Datum values[MAXATTR]
Definition bootstrap.c:190
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
static Datum Float4GetDatum(float4 X)
Definition postgres.h:481
static Datum TransactionIdGetDatum(TransactionId X)
Definition postgres.h:292
static Datum MultiXactIdGetDatum(MultiXactId X)
Definition postgres.h:302
uint64_t Datum
Definition postgres.h:70

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

Referenced by AddNewRelationTuple(), and index_create().

◆ RelationClearMissing()

void RelationClearMissing ( Relation  rel)
extern

Definition at line 1980 of file heap.c.

1981{
1983 Oid relid = RelationGetRelid(rel);
1984 int natts = RelationGetNumberOfAttributes(rel);
1985 int attnum;
1990 HeapTuple tuple,
1991 newtuple;
1992
1993 memset(repl_val, 0, sizeof(repl_val));
1994 memset(repl_null, false, sizeof(repl_null));
1995 memset(repl_repl, false, sizeof(repl_repl));
1996
1999
2002
2003
2004 /* Get a lock on pg_attribute */
2006
2007 /* process each non-system attribute, including any dropped columns */
2008 for (attnum = 1; attnum <= natts; attnum++)
2009 {
2010 tuple = SearchSysCache2(ATTNUM,
2011 ObjectIdGetDatum(relid),
2013 if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
2014 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2015 attnum, relid);
2016
2018
2019 /* ignore any where atthasmissing is not true */
2020 if (attrtuple->atthasmissing)
2021 {
2022 newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
2024
2025 CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
2026
2027 heap_freetuple(newtuple);
2028 }
2029
2030 ReleaseSysCache(tuple);
2031 }
2032
2033 /*
2034 * Our update of the pg_attribute rows will force a relcache rebuild, so
2035 * there's nothing else to do here.
2036 */
2038}
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
#define RelationGetNumberOfAttributes(relation)
Definition rel.h:522
ItemPointerData t_self
Definition htup.h:65
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231

References attnum, BoolGetDatum(), CatalogTupleUpdate(), elog, ERROR, fb(), 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 
)
extern

Definition at line 1699 of file heap.c.

1700{
1701 Relation rel;
1703 HeapTuple tuple;
1705 char newattname[NAMEDATALEN];
1707 bool nullsAtt[Natts_pg_attribute] = {0};
1708 bool replacesAtt[Natts_pg_attribute] = {0};
1709
1710 /*
1711 * Grab an exclusive lock on the target table, which we will NOT release
1712 * until end of transaction. (In the simple case where we are directly
1713 * dropping this column, ATExecDropColumn already did this ... but when
1714 * cascading from a drop of some other object, we may not have any lock.)
1715 */
1716 rel = relation_open(relid, AccessExclusiveLock);
1717
1719
1721 ObjectIdGetDatum(relid),
1723 if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
1724 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1725 attnum, relid);
1727
1728 /* Mark the attribute as dropped */
1729 attStruct->attisdropped = true;
1730
1731 /*
1732 * Set the type OID to invalid. A dropped attribute's type link cannot be
1733 * relied on (once the attribute is dropped, the type might be too).
1734 * Fortunately we do not need the type row --- the only really essential
1735 * information is the type's typlen and typalign, which are preserved in
1736 * the attribute's attlen and attalign. We set atttypid to zero here as a
1737 * means of catching code that incorrectly expects it to be valid.
1738 */
1739 attStruct->atttypid = InvalidOid;
1740
1741 /* Remove any not-null constraint the column may have */
1742 attStruct->attnotnull = false;
1743
1744 /* Unset this so no one tries to look up the generation expression */
1745 attStruct->attgenerated = '\0';
1746
1747 /*
1748 * Change the column name to something that isn't likely to conflict
1749 */
1751 "........pg.dropped.%d........", attnum);
1752 namestrcpy(&(attStruct->attname), newattname);
1753
1754 /* Clear the missing value */
1755 attStruct->atthasmissing = false;
1758
1759 /*
1760 * Clear the other nullable fields. This saves some space in pg_attribute
1761 * and removes no longer useful information.
1762 */
1771
1774
1775 CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
1776
1777 /*
1778 * Because updating the pg_attribute row will trigger a relcache flush for
1779 * the target relation, we need not do anything else to notify other
1780 * backends of the change.
1781 */
1782
1784
1785 RemoveStatistics(relid, attnum);
1786
1787 relation_close(rel, NoLock);
1788}
void namestrcpy(Name name, const char *str)
Definition name.c:233
#define NAMEDATALEN
#define snprintf
Definition port.h:261
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition syscache.h:93

References AccessExclusiveLock, attnum, CatalogTupleUpdate(), elog, ERROR, fb(), 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)
extern

Definition at line 4039 of file heap.c.

4040{
4041 Relation rel;
4042 HeapTuple tuple;
4043
4045
4047 if (!HeapTupleIsValid(tuple))
4048 elog(ERROR, "cache lookup failed for partition key of relation %u",
4049 relid);
4050
4051 CatalogTupleDelete(rel, &tuple->t_self);
4052
4053 ReleaseSysCache(tuple);
4055}

References CatalogTupleDelete(), elog, ERROR, fb(), 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 
)
extern

Definition at line 3511 of file heap.c.

3512{
3514 SysScanDesc scan;
3515 ScanKeyData key[2];
3516 int nkeys;
3517 HeapTuple tuple;
3518
3520
3521 ScanKeyInit(&key[0],
3524 ObjectIdGetDatum(relid));
3525
3526 if (attnum == 0)
3527 nkeys = 1;
3528 else
3529 {
3530 ScanKeyInit(&key[1],
3534 nkeys = 2;
3535 }
3536
3538 NULL, nkeys, key);
3539
3540 /* we must loop even when attnum != 0, in case of inherited stats */
3541 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
3543
3544 systable_endscan(scan);
3545
3547}

References attnum, BTEqualStrategyNumber, CatalogTupleDelete(), fb(), HeapTupleIsValid, Int16GetDatum(), 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 
)
extern

Definition at line 2102 of file heap.c.

2103{
2105 bool nullsAtt[Natts_pg_attribute] = {0};
2106 bool replacesAtt[Natts_pg_attribute] = {0};
2110 tablerel;
2112 newtup;
2113
2114 /* lock the table the attribute belongs to */
2116
2117 /* Don't do anything unless it's a plain table */
2118 if (tablerel->rd_rel->relkind != RELKIND_RELATION)
2119 {
2121 return;
2122 }
2123
2124 /* Lock the attribute row and get the data */
2128 elog(ERROR, "cache lookup failed for attribute %s of relation %u",
2129 attname, relid);
2131
2132 /* get an array value from the value string */
2135 ObjectIdGetDatum(attStruct->atttypid),
2136 Int32GetDatum(attStruct->atttypmod));
2137
2138 /* update the tuple - set atthasmissing and attmissingval */
2143
2147
2148 /* clean up */
2152}
#define OidFunctionCall3(functionId, arg1, arg2, arg3)
Definition fmgr.h:726
static struct @177 value
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:476

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

Referenced by binary_upgrade_set_missing_value().

◆ StoreAttrMissingVal()

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

Definition at line 2046 of file heap.c.

2047{
2049 bool nullsAtt[Natts_pg_attribute] = {0};
2050 bool replacesAtt[Natts_pg_attribute] = {0};
2054 newtup;
2055
2056 /* This is only supported for plain tables */
2057 Assert(rel->rd_rel->relkind == RELKIND_RELATION);
2058
2059 /* Fetch the pg_attribute row */
2061
2065 if (!HeapTupleIsValid(atttup)) /* shouldn't happen */
2066 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
2067 attnum, RelationGetRelid(rel));
2069
2070 /* Make a one-element array containing the value */
2072 1,
2073 attStruct->atttypid,
2074 attStruct->attlen,
2075 attStruct->attbyval,
2076 attStruct->attalign));
2077
2078 /* Update the pg_attribute row */
2081
2084
2088
2089 /* clean up */
2092}
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)

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

Referenced by ATExecAddColumn().

◆ StorePartitionBound()

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

Definition at line 4070 of file heap.c.

4071{
4073 HeapTuple tuple,
4074 newtuple;
4079
4080 /* Update pg_class tuple */
4084 if (!HeapTupleIsValid(tuple))
4085 elog(ERROR, "cache lookup failed for relation %u",
4086 RelationGetRelid(rel));
4087
4088#ifdef USE_ASSERT_CHECKING
4089 {
4091 bool isnull;
4092
4094 Assert(!classForm->relispartition);
4096 &isnull);
4097 Assert(isnull);
4098 }
4099#endif
4100
4101 /* Fill in relpartbound value */
4102 memset(new_val, 0, sizeof(new_val));
4103 memset(new_null, false, sizeof(new_null));
4104 memset(new_repl, false, sizeof(new_repl));
4108 newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
4110 /* Also set the flag */
4111 ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
4112
4113 /*
4114 * We already checked for no inheritance children, but reset
4115 * relhassubclass in case it was left over.
4116 */
4117 if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass)
4118 ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false;
4119
4120 CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
4121 heap_freetuple(newtuple);
4123
4124 /*
4125 * If we're storing bounds for the default partition, update
4126 * pg_partitioned_table too.
4127 */
4128 if (bound->is_default)
4130 RelationGetRelid(rel));
4131
4132 /* Make these updates visible */
4134
4135 /*
4136 * The partition constraint for the default partition depends on the
4137 * partition bounds of every other partition, so we must invalidate the
4138 * relcache entry for that partition every time a partition is added or
4139 * removed.
4140 */
4145
4147}
#define CStringGetTextDatum(s)
Definition builtins.h:98
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1635
char * nodeToString(const void *obj)
Definition outfuncs.c:811
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(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void CommandCounterIncrement(void)
Definition xact.c:1130

References Assert, CacheInvalidateRelcache(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CommandCounterIncrement(), CStringGetTextDatum, elog, ERROR, fb(), 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 attachPartitionTable(), and DefineRelation().

◆ StorePartitionKey()

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

Definition at line 3914 of file heap.c.

3921{
3922 int i;
3928 HeapTuple tuple;
3930 bool nulls[Natts_pg_partitioned_table] = {0};
3933 ObjectAddresses *addrs;
3934
3935 Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3936
3937 /* Copy the partition attribute numbers, opclass OIDs into arrays */
3938 partattrs_vec = buildint2vector(partattrs, partnatts);
3940 partcollation_vec = buildoidvector(partcollation, partnatts);
3941
3942 /* Convert the expressions (if any) to a text datum */
3943 if (partexprs)
3944 {
3945 char *exprString;
3946
3947 exprString = nodeToString(partexprs);
3950 }
3951 else
3952 partexprDatum = (Datum) 0;
3953
3955
3956 /* Only this can ever be NULL */
3957 if (!partexprDatum)
3958 nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
3959
3968
3970
3973
3974 /* Mark this relation as dependent on a few things as follows */
3975 addrs = new_object_addresses();
3977
3978 /* Operator class and collation per key column */
3979 for (i = 0; i < partnatts; i++)
3980 {
3983
3984 /* The default collation is pinned, so don't bother recording it */
3985 if (OidIsValid(partcollation[i]) &&
3986 partcollation[i] != DEFAULT_COLLATION_OID)
3987 {
3990 }
3991 }
3992
3994 free_object_addresses(addrs);
3995
3996 /*
3997 * The partitioning columns are made internally dependent on the table,
3998 * because we cannot drop any of them without dropping the whole table.
3999 * (ATExecDropColumn independently enforces that, but it's not bulletproof
4000 * so we need the dependencies too.)
4001 */
4002 for (i = 0; i < partnatts; i++)
4003 {
4004 if (partattrs[i] == 0)
4005 continue; /* ignore expressions here */
4006
4008 RelationGetRelid(rel), partattrs[i]);
4010 }
4011
4012 /*
4013 * Also consider anything mentioned in partition expressions. External
4014 * references (e.g. functions) get NORMAL dependencies. Table columns
4015 * mentioned in the expressions are handled the same as plain partitioning
4016 * columns, i.e. they become internally dependent on the whole table.
4017 */
4018 if (partexprs)
4020 (Node *) partexprs,
4021 RelationGetRelid(rel),
4024 true /* reverse the self-deps */ );
4025
4026 /*
4027 * We must invalidate the relcache so that the next
4028 * CommandCounterIncrement() will cause the same to be rebuilt using the
4029 * information in just created catalog entry.
4030 */
4032}
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
@ 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)
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:47
Definition c.h:815

References add_exact_object_address(), Assert, buildint2vector(), buildoidvector(), CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), CStringGetTextDatum, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, fb(), 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)
extern

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:873
static const FormData_pg_attribute *const SysAtt[]
Definition heap.c:228

References attname, fb(), 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)
extern

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