Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Functions

heap.h File Reference

#include "parser/parse_node.h"
#include "catalog/indexing.h"
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

Typedefs

typedef struct RawColumnDefault RawColumnDefault
typedef struct CookedConstraint CookedConstraint

Functions

Relation heap_create (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode, TupleDesc tupDesc, char relkind, char relpersistence, bool shared_relation, bool mapped_relation)
Oid heap_create_with_catalog (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool oidislocal, int oidinhcount, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal)
void heap_create_init_fork (Relation rel)
bool heap_is_matview_init_state (Relation rel)
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 InsertPgAttributeTuple (Relation pg_attribute_rel, Form_pg_attribute new_attribute, 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)
void StoreAttrDefault (Relation rel, AttrNumber attnum, Node *expr, bool is_internal)
NodecookDefault (ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, char *attname)
void DeleteRelationTuple (Oid relid)
void DeleteAttributeTuples (Oid relid)
void DeleteSystemAttributeTuples (Oid relid)
void RemoveAttributeById (Oid relid, AttrNumber attnum)
void RemoveAttrDefault (Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain, bool internal)
void RemoveAttrDefaultById (Oid attrdefId)
void RemoveStatistics (Oid relid, AttrNumber attnum)
Form_pg_attribute SystemAttributeDefinition (AttrNumber attno, bool relhasoids)
Form_pg_attribute SystemAttributeByName (const char *attname, bool relhasoids)
void CheckAttributeNamesTypes (TupleDesc tupdesc, char relkind, bool allow_system_table_mods)
void CheckAttributeType (const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, bool allow_system_table_mods)

Typedef Documentation


Function Documentation

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

Definition at line 2122 of file heap.c.

References addRangeTableEntryForRelation(), addRTEtoQuery(), Assert, CookedConstraint::attnum, RawColumnDefault::attnum, tupleDesc::attrs, ChooseConstraintName(), Constraint::conname, tupleDesc::constr, CONSTR_CHECK, Constraint::contype, CookedConstraint::contype, cookConstraint(), cookDefault(), Constraint::cooked_expr, ereport, errcode(), errmsg(), ERROR, CookedConstraint::expr, get_attname(), CookedConstraint::inhcount, CookedConstraint::is_local, Constraint::is_no_inherit, CookedConstraint::is_no_inherit, IsA, lappend(), lfirst, linitial, list_length(), list_union(), make_parsestate(), MergeWithExistingConstraint(), CookedConstraint::name, NameStr, NIL, NULL, tupleConstr::num_check, palloc(), pull_var_clause(), PVC_REJECT_AGGREGATES, PVC_REJECT_PLACEHOLDERS, RawColumnDefault::raw_default, Constraint::raw_expr, RelationData::rd_att, RelationGetDescr, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, SetRelationNumChecks(), Constraint::skip_validation, CookedConstraint::skip_validation, StoreAttrDefault(), StoreRelCheck(), and stringToNode().

Referenced by ATAddCheckConstraint(), ATExecAddColumn(), ATExecColumnDefault(), and DefineRelation().

{
    List       *cookedConstraints = NIL;
    TupleDesc   tupleDesc;
    TupleConstr *oldconstr;
    int         numoldchecks;
    ParseState *pstate;
    RangeTblEntry *rte;
    int         numchecks;
    List       *checknames;
    ListCell   *cell;
    Node       *expr;
    CookedConstraint *cooked;

    /*
     * Get info about existing constraints.
     */
    tupleDesc = RelationGetDescr(rel);
    oldconstr = tupleDesc->constr;
    if (oldconstr)
        numoldchecks = oldconstr->num_check;
    else
        numoldchecks = 0;

    /*
     * Create a dummy ParseState and insert the target relation as its sole
     * rangetable entry.  We need a ParseState for transformExpr.
     */
    pstate = make_parsestate(NULL);
    rte = addRangeTableEntryForRelation(pstate,
                                        rel,
                                        NULL,
                                        false,
                                        true);
    addRTEtoQuery(pstate, rte, true, true, true);

    /*
     * Process column default expressions.
     */
    foreach(cell, newColDefaults)
    {
        RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
        Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];

        expr = cookDefault(pstate, colDef->raw_default,
                           atp->atttypid, atp->atttypmod,
                           NameStr(atp->attname));

        /*
         * If the expression is just a NULL constant, we do not bother to make
         * an explicit pg_attrdef entry, since the default behavior is
         * equivalent.
         *
         * Note a nonobvious property of this test: if the column is of a
         * domain type, what we'll get is not a bare null Const but a
         * CoerceToDomain expr, so we will not discard the default.  This is
         * critical because the column default needs to be retained to
         * override any default that the domain might have.
         */
        if (expr == NULL ||
            (IsA(expr, Const) &&((Const *) expr)->constisnull))
            continue;

        StoreAttrDefault(rel, colDef->attnum, expr, is_internal);

        cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
        cooked->contype = CONSTR_DEFAULT;
        cooked->name = NULL;
        cooked->attnum = colDef->attnum;
        cooked->expr = expr;
        cooked->skip_validation = false;
        cooked->is_local = is_local;
        cooked->inhcount = is_local ? 0 : 1;
        cooked->is_no_inherit = false;
        cookedConstraints = lappend(cookedConstraints, cooked);
    }

    /*
     * Process constraint expressions.
     */
    numchecks = numoldchecks;
    checknames = NIL;
    foreach(cell, newConstraints)
    {
        Constraint *cdef = (Constraint *) lfirst(cell);
        char       *ccname;

        if (cdef->contype != CONSTR_CHECK)
            continue;

        if (cdef->raw_expr != NULL)
        {
            Assert(cdef->cooked_expr == NULL);

            /*
             * Transform raw parsetree to executable expression, and verify
             * it's valid as a CHECK constraint.
             */
            expr = cookConstraint(pstate, cdef->raw_expr,
                                  RelationGetRelationName(rel));
        }
        else
        {
            Assert(cdef->cooked_expr != NULL);

            /*
             * Here, we assume the parser will only pass us valid CHECK
             * expressions, so we do no particular checking.
             */
            expr = stringToNode(cdef->cooked_expr);
        }

        /*
         * Check name uniqueness, or generate a name if none was given.
         */
        if (cdef->conname != NULL)
        {
            ListCell   *cell2;

            ccname = cdef->conname;
            /* Check against other new constraints */
            /* Needed because we don't do CommandCounterIncrement in loop */
            foreach(cell2, checknames)
            {
                if (strcmp((char *) lfirst(cell2), ccname) == 0)
                    ereport(ERROR,
                            (errcode(ERRCODE_DUPLICATE_OBJECT),
                             errmsg("check constraint \"%s\" already exists",
                                    ccname)));
            }

            /* save name for future checks */
            checknames = lappend(checknames, ccname);

            /*
             * Check against pre-existing constraints.  If we are allowed to
             * merge with an existing constraint, there's no more to do here.
             * (We omit the duplicate constraint from the result, which is
             * what ATAddCheckConstraint wants.)
             */
            if (MergeWithExistingConstraint(rel, ccname, expr,
                                            allow_merge, is_local,
                                            cdef->is_no_inherit))
                continue;
        }
        else
        {
            /*
             * When generating a name, we want to create "tab_col_check" for a
             * column constraint and "tab_check" for a table constraint.  We
             * no longer have any info about the syntactic positioning of the
             * constraint phrase, so we approximate this by seeing whether the
             * expression references more than one column.  (If the user
             * played by the rules, the result is the same...)
             *
             * Note: pull_var_clause() doesn't descend into sublinks, but we
             * eliminated those above; and anyway this only needs to be an
             * approximate answer.
             */
            List       *vars;
            char       *colname;

            vars = pull_var_clause(expr,
                                   PVC_REJECT_AGGREGATES,
                                   PVC_REJECT_PLACEHOLDERS);

            /* eliminate duplicates */
            vars = list_union(NIL, vars);

            if (list_length(vars) == 1)
                colname = get_attname(RelationGetRelid(rel),
                                      ((Var *) linitial(vars))->varattno);
            else
                colname = NULL;

            ccname = ChooseConstraintName(RelationGetRelationName(rel),
                                          colname,
                                          "check",
                                          RelationGetNamespace(rel),
                                          checknames);

            /* save name for future checks */
            checknames = lappend(checknames, ccname);
        }

        /*
         * OK, store it.
         */
        StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local,
                      is_local ? 0 : 1, cdef->is_no_inherit, is_internal);

        numchecks++;

        cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
        cooked->contype = CONSTR_CHECK;
        cooked->name = ccname;
        cooked->attnum = 0;
        cooked->expr = expr;
        cooked->skip_validation = cdef->skip_validation;
        cooked->is_local = is_local;
        cooked->inhcount = is_local ? 0 : 1;
        cooked->is_no_inherit = cdef->is_no_inherit;
        cookedConstraints = lappend(cookedConstraints, cooked);
    }

    /*
     * Update the count of constraints in the relation's pg_class tuple. We do
     * this even if there was no change, in order to ensure that an SI update
     * message is sent out for the pg_class tuple, which will force other
     * backends to rebuild their relcache entries for the rel. (This is
     * critical if we added defaults but not constraints.)
     */
    SetRelationNumChecks(rel, numchecks);

    return cookedConstraints;
}

void CheckAttributeNamesTypes ( TupleDesc  tupdesc,
char  relkind,
bool  allow_system_table_mods 
)

Definition at line 379 of file heap.c.

References tupleDesc::attrs, CheckAttributeType(), ereport, errcode(), errmsg(), ERROR, i, MaxHeapAttributeNumber, NameStr, tupleDesc::natts, NIL, NULL, RELKIND_COMPOSITE_TYPE, RELKIND_VIEW, SystemAttributeByName(), and tupleDesc::tdhasoid.

Referenced by heap_create_with_catalog(), and transformRangeFunction().

{
    int         i;
    int         j;
    int         natts = tupdesc->natts;

    /* Sanity check on column count */
    if (natts < 0 || natts > MaxHeapAttributeNumber)
        ereport(ERROR,
                (errcode(ERRCODE_TOO_MANY_COLUMNS),
                 errmsg("tables can have at most %d columns",
                        MaxHeapAttributeNumber)));

    /*
     * first check for collision with system attribute names
     *
     * Skip this for a view or type relation, since those don't have system
     * attributes.
     */
    if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
    {
        for (i = 0; i < natts; i++)
        {
            if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname),
                                      tupdesc->tdhasoid) != NULL)
                ereport(ERROR,
                        (errcode(ERRCODE_DUPLICATE_COLUMN),
                         errmsg("column name \"%s\" conflicts with a system column name",
                                NameStr(tupdesc->attrs[i]->attname))));
        }
    }

    /*
     * next check for repeated attribute names
     */
    for (i = 1; i < natts; i++)
    {
        for (j = 0; j < i; j++)
        {
            if (strcmp(NameStr(tupdesc->attrs[j]->attname),
                       NameStr(tupdesc->attrs[i]->attname)) == 0)
                ereport(ERROR,
                        (errcode(ERRCODE_DUPLICATE_COLUMN),
                         errmsg("column name \"%s\" specified more than once",
                                NameStr(tupdesc->attrs[j]->attname))));
        }
    }

    /*
     * next check the attribute types
     */
    for (i = 0; i < natts; i++)
    {
        CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
                           tupdesc->attrs[i]->atttypid,
                           tupdesc->attrs[i]->attcollation,
                           NIL, /* assume we're creating a new rowtype */
                           allow_system_table_mods);
    }
}

void CheckAttributeType ( const char *  attname,
Oid  atttypid,
Oid  attcollation,
List containing_rowtypes,
bool  allow_system_table_mods 
)

Definition at line 457 of file heap.c.

References AccessShareLock, ANYARRAYOID, tupleDesc::attrs, CheckAttributeType(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, format_type_be(), get_element_type(), get_typ_typrelid(), get_typtype(), getBaseType(), i, lcons_oid(), list_delete_first(), list_member_oid(), NameStr, tupleDesc::natts, OidIsValid, relation_close(), relation_open(), RelationGetDescr, type_is_collatable(), TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, TYPTYPE_PSEUDO, UNKNOWNOID, and WARNING.

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

{
    char        att_typtype = get_typtype(atttypid);
    Oid         att_typelem;

    if (atttypid == UNKNOWNOID)
    {
        /*
         * Warn user, but don't fail, if column to be created has UNKNOWN type
         * (usually as a result of a 'retrieve into' - jolly)
         */
        ereport(WARNING,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("column \"%s\" has type \"unknown\"", attname),
                 errdetail("Proceeding with relation creation anyway.")));
    }
    else if (att_typtype == TYPTYPE_PSEUDO)
    {
        /*
         * Refuse any attempt to create a pseudo-type column, except for a
         * special hack for pg_statistic: allow ANYARRAY when modifying system
         * catalogs (this allows creating pg_statistic and cloning it during
         * VACUUM FULL)
         */
        if (atttypid != ANYARRAYOID || !allow_system_table_mods)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                     errmsg("column \"%s\" has pseudo-type %s",
                            attname, format_type_be(atttypid))));
    }
    else if (att_typtype == TYPTYPE_DOMAIN)
    {
        /*
         * If it's a domain, recurse to check its base type.
         */
        CheckAttributeType(attname, getBaseType(atttypid), attcollation,
                           containing_rowtypes,
                           allow_system_table_mods);
    }
    else if (att_typtype == TYPTYPE_COMPOSITE)
    {
        /*
         * For a composite type, recurse into its attributes.
         */
        Relation    relation;
        TupleDesc   tupdesc;
        int         i;

        /*
         * Check for self-containment.  Eventually we might be able to allow
         * this (just return without complaint, if so) but it's not clear how
         * many other places would require anti-recursion defenses before it
         * would be safe to allow tables to contain their own rowtype.
         */
        if (list_member_oid(containing_rowtypes, atttypid))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                errmsg("composite type %s cannot be made a member of itself",
                       format_type_be(atttypid))));

        containing_rowtypes = lcons_oid(atttypid, containing_rowtypes);

        relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);

        tupdesc = RelationGetDescr(relation);

        for (i = 0; i < tupdesc->natts; i++)
        {
            Form_pg_attribute attr = tupdesc->attrs[i];

            if (attr->attisdropped)
                continue;
            CheckAttributeType(NameStr(attr->attname),
                               attr->atttypid, attr->attcollation,
                               containing_rowtypes,
                               allow_system_table_mods);
        }

        relation_close(relation, AccessShareLock);

        containing_rowtypes = list_delete_first(containing_rowtypes);
    }
    else if (OidIsValid((att_typelem = get_element_type(atttypid))))
    {
        /*
         * Must recurse into array types, too, in case they are composite.
         */
        CheckAttributeType(attname, att_typelem, attcollation,
                           containing_rowtypes,
                           allow_system_table_mods);
    }

    /*
     * This might not be strictly invalid per SQL standard, but it is pretty
     * useless, and it cannot be dumped, so we must disallow it.
     */
    if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("no collation was derived for column \"%s\" with collatable type %s",
                        attname, format_type_be(atttypid)),
        errhint("Use the COLLATE clause to set the collation explicitly.")));
}

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

Definition at line 2502 of file heap.c.

References Assert, assign_expr_collations(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, contain_var_clause(), ereport, errcode(), errhint(), errmsg(), ERROR, EXPR_KIND_COLUMN_DEFAULT, expression_returns_set(), exprType(), format_type_be(), NULL, OidIsValid, and transformExpr().

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

{
    Node       *expr;

    Assert(raw_default != NULL);

    /*
     * Transform raw parsetree to executable expression.
     */
    expr = transformExpr(pstate, raw_default, EXPR_KIND_COLUMN_DEFAULT);

    /*
     * Make sure default expr does not refer to any vars (we need this check
     * since the pstate includes the target table).
     */
    if (contain_var_clause(expr))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
              errmsg("cannot use column references in default expression")));

    /*
     * transformExpr() should have already rejected subqueries, aggregates,
     * and window functions, based on the EXPR_KIND_ for a default expression.
     *
     * It can't return a set either.
     */
    if (expression_returns_set(expr))
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("default expression must not return a set")));

    /*
     * Coerce the expression to the correct type and typmod, if given. This
     * should match the parser's processing of non-defaulted expressions ---
     * see transformAssignedExpr().
     */
    if (OidIsValid(atttypid))
    {
        Oid         type_id = exprType(expr);

        expr = coerce_to_target_type(pstate, expr, type_id,
                                     atttypid, atttypmod,
                                     COERCION_ASSIGNMENT,
                                     COERCE_IMPLICIT_CAST,
                                     -1);
        if (expr == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                     errmsg("column \"%s\" is of type %s"
                            " but default expression is of type %s",
                            attname,
                            format_type_be(atttypid),
                            format_type_be(type_id)),
               errhint("You will need to rewrite or cast the expression.")));
    }

    /*
     * Finally, take care of collations in the finished expression.
     */
    assign_expr_collations(pstate, expr);

    return expr;
}

void DeleteAttributeTuples ( Oid  relid  ) 

Definition at line 1440 of file heap.c.

References Anum_pg_attribute_attrelid, AttributeRelationId, AttributeRelidNumIndexId, BTEqualStrategyNumber, heap_close, heap_open(), NULL, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by heap_drop_with_catalog(), and index_drop().

{
    Relation    attrel;
    SysScanDesc scan;
    ScanKeyData key[1];
    HeapTuple   atttup;

    /* Grab an appropriate lock on the pg_attribute relation */
    attrel = heap_open(AttributeRelationId, RowExclusiveLock);

    /* Use the index to scan only attributes of the target relation */
    ScanKeyInit(&key[0],
                Anum_pg_attribute_attrelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(relid));

    scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
                              SnapshotNow, 1, key);

    /* Delete all the matching tuples */
    while ((atttup = systable_getnext(scan)) != NULL)
        simple_heap_delete(attrel, &atttup->t_self);

    /* Clean up after the scan */
    systable_endscan(scan);
    heap_close(attrel, RowExclusiveLock);
}

void DeleteRelationTuple ( Oid  relid  ) 

Definition at line 1411 of file heap.c.

References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RelationRelationId, ReleaseSysCache(), RELOID, RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.

Referenced by heap_drop_with_catalog(), and index_drop().

{
    Relation    pg_class_desc;
    HeapTuple   tup;

    /* Grab an appropriate lock on the pg_class relation */
    pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);

    tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    if (!HeapTupleIsValid(tup))
        elog(ERROR, "cache lookup failed for relation %u", relid);

    /* delete the relation tuple from pg_class, and finish up */
    simple_heap_delete(pg_class_desc, &tup->t_self);

    ReleaseSysCache(tup);

    heap_close(pg_class_desc, RowExclusiveLock);
}

void DeleteSystemAttributeTuples ( Oid  relid  ) 

Definition at line 1477 of file heap.c.

References Anum_pg_attribute_attnum, Anum_pg_attribute_attrelid, AttributeRelationId, AttributeRelidNumIndexId, BTEqualStrategyNumber, BTLessEqualStrategyNumber, heap_close, heap_open(), Int16GetDatum, NULL, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by DefineQueryRewrite().

{
    Relation    attrel;
    SysScanDesc scan;
    ScanKeyData key[2];
    HeapTuple   atttup;

    /* Grab an appropriate lock on the pg_attribute relation */
    attrel = heap_open(AttributeRelationId, RowExclusiveLock);

    /* Use the index to scan only system attributes of the target relation */
    ScanKeyInit(&key[0],
                Anum_pg_attribute_attrelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(relid));
    ScanKeyInit(&key[1],
                Anum_pg_attribute_attnum,
                BTLessEqualStrategyNumber, F_INT2LE,
                Int16GetDatum(0));

    scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
                              SnapshotNow, 2, key);

    /* Delete all the matching tuples */
    while ((atttup = systable_getnext(scan)) != NULL)
        simple_heap_delete(attrel, &atttup->t_self);

    /* Clean up after the scan */
    systable_endscan(scan);
    heap_close(attrel, RowExclusiveLock);
}

Relation heap_create ( const char *  relname,
Oid  relnamespace,
Oid  reltablespace,
Oid  relid,
Oid  relfilenode,
TupleDesc  tupDesc,
char  relkind,
char  relpersistence,
bool  shared_relation,
bool  mapped_relation 
)

Definition at line 240 of file heap.c.

References Assert, MyDatabaseTableSpace, OidIsValid, RelationData::rd_node, RelationBuildLocalRelation(), RelationCreateStorage(), RelationOpenSmgr, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_SEQUENCE, and RELKIND_VIEW.

Referenced by heap_create_with_catalog(), and index_create().

{
    bool        create_storage;
    Relation    rel;

    /* The caller must have provided an OID for the relation. */
    Assert(OidIsValid(relid));

    /*
     * Decide if we need storage or not, and handle a couple other special
     * cases for particular relkinds.
     */
    switch (relkind)
    {
        case RELKIND_VIEW:
        case RELKIND_COMPOSITE_TYPE:
        case RELKIND_FOREIGN_TABLE:
            create_storage = false;

            /*
             * Force reltablespace to zero if the relation has no physical
             * storage.  This is mainly just for cleanliness' sake.
             */
            reltablespace = InvalidOid;
            break;
        case RELKIND_SEQUENCE:
            create_storage = true;

            /*
             * Force reltablespace to zero for sequences, since we don't
             * support moving them around into different tablespaces.
             */
            reltablespace = InvalidOid;
            break;
        default:
            create_storage = true;
            break;
    }

    /*
     * Unless otherwise requested, the physical ID (relfilenode) is initially
     * the same as the logical ID (OID).  When the caller did specify a
     * relfilenode, it already exists; do not attempt to create it.
     */
    if (OidIsValid(relfilenode))
        create_storage = false;
    else
        relfilenode = relid;

    /*
     * Never allow a pg_class entry to explicitly specify the database's
     * default tablespace in reltablespace; force it to zero instead. This
     * ensures that if the database is cloned with a different default
     * tablespace, the pg_class entry will still match where CREATE DATABASE
     * will put the physically copied relation.
     *
     * Yes, this is a bit of a hack.
     */
    if (reltablespace == MyDatabaseTableSpace)
        reltablespace = InvalidOid;

    /*
     * build the relcache entry.
     */
    rel = RelationBuildLocalRelation(relname,
                                     relnamespace,
                                     tupDesc,
                                     relid,
                                     relfilenode,
                                     reltablespace,
                                     shared_relation,
                                     mapped_relation,
                                     relpersistence,
                                     relkind);

    /*
     * Have the storage manager create the relation's disk file, if needed.
     *
     * We only create the main fork here, other forks will be created on
     * demand.
     */
    if (create_storage)
    {
        RelationOpenSmgr(rel);
        RelationCreateStorage(rel->rd_node, relpersistence);
    }

    return rel;
}

void heap_create_init_fork ( Relation  rel  ) 
Oid heap_create_with_catalog ( const char *  relname,
Oid  relnamespace,
Oid  reltablespace,
Oid  relid,
Oid  reltypeid,
Oid  reloftypeid,
Oid  ownerid,
TupleDesc  tupdesc,
List cooked_constraints,
char  relkind,
char  relpersistence,
bool  shared_relation,
bool  mapped_relation,
bool  oidislocal,
int  oidinhcount,
OnCommitAction  oncommit,
Datum  reloptions,
bool  use_user_acl,
bool  allow_system_table_mods,
bool  is_internal 
)

Definition at line 986 of file heap.c.

References ACL_OBJECT_RELATION, ACL_OBJECT_SEQUENCE, aclmembers(), AddNewAttributeTuples(), AddNewRelationTuple(), AddNewRelationType(), Assert, AssignTypeArrayOid(), binary_upgrade_next_heap_pg_class_oid, binary_upgrade_next_toast_pg_class_oid, CheckAttributeNamesTypes(), ObjectAddress::classId, CStringGetDatum, DEFAULT_TYPDELIM, DEPENDENCY_NORMAL, elog, ereport, errcode(), errhint(), errmsg(), ERROR, get_relname_relid(), get_user_default_acl(), GetNewRelFileNode(), GetSysCacheOid2, GLOBALTABLESPACE_OID, heap_close, heap_create(), heap_create_init_fork(), heap_open(), InvalidOid, InvokeObjectPostCreateHookArg, IsBinaryUpgrade, IsBootstrapProcessingMode, IsNormalProcessingMode, IsUnderPostmaster, makeArrayTypeName(), moveArrayTypeName(), NoLock, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, ONCOMMIT_NOOP, pfree(), PointerGetDatum, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), register_on_commit_action(), RelationGetRelid, RelationRelationId, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, RELKIND_VIEW, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, RowExclusiveLock, StoreConstraints(), TYPCATEGORY_ARRAY, TypeCreate(), TYPENAMENSP, TYPTYPE_BASE, and updateAclDependencies().

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

{
    Relation    pg_class_desc;
    Relation    new_rel_desc;
    Acl        *relacl;
    Oid         existing_relid;
    Oid         old_type_oid;
    Oid         new_type_oid;
    Oid         new_array_oid = InvalidOid;

    pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);

    /*
     * sanity checks
     */
    Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());

    CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);

    /*
     * This would fail later on anyway, if the relation already exists.  But
     * by catching it here we can emit a nicer error message.
     */
    existing_relid = get_relname_relid(relname, relnamespace);
    if (existing_relid != InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_TABLE),
                 errmsg("relation \"%s\" already exists", relname)));

    /*
     * Since we are going to create a rowtype as well, also check for
     * collision with an existing type name.  If there is one and it's an
     * autogenerated array, we can rename it out of the way; otherwise we can
     * at least give a good error message.
     */
    old_type_oid = GetSysCacheOid2(TYPENAMENSP,
                                   CStringGetDatum(relname),
                                   ObjectIdGetDatum(relnamespace));
    if (OidIsValid(old_type_oid))
    {
        if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("type \"%s\" already exists", relname),
               errhint("A relation has an associated type of the same name, "
                       "so you must use a name that doesn't conflict "
                       "with any existing type.")));
    }

    /*
     * Shared relations must be in pg_global (last-ditch check)
     */
    if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
        elog(ERROR, "shared relations must be placed in pg_global tablespace");

    /*
     * Allocate an OID for the relation, unless we were told what to use.
     *
     * The OID will be the relfilenode as well, so make sure it doesn't
     * collide with either pg_class OIDs or existing physical files.
     */
    if (!OidIsValid(relid))
    {
        /*
         * Use binary-upgrade override for pg_class.oid/relfilenode, if
         * supplied.
         */
        if (IsBinaryUpgrade &&
            OidIsValid(binary_upgrade_next_heap_pg_class_oid) &&
            (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
             relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW ||
             relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE))
        {
            relid = binary_upgrade_next_heap_pg_class_oid;
            binary_upgrade_next_heap_pg_class_oid = InvalidOid;
        }
        else if (IsBinaryUpgrade &&
                 OidIsValid(binary_upgrade_next_toast_pg_class_oid) &&
                 relkind == RELKIND_TOASTVALUE)
        {
            relid = binary_upgrade_next_toast_pg_class_oid;
            binary_upgrade_next_toast_pg_class_oid = InvalidOid;
        }
        else
            relid = GetNewRelFileNode(reltablespace, pg_class_desc,
                                      relpersistence);
    }

    /*
     * Determine the relation's initial permissions.
     */
    if (use_user_acl)
    {
        switch (relkind)
        {
            case RELKIND_RELATION:
            case RELKIND_VIEW:
            case RELKIND_MATVIEW:
            case RELKIND_FOREIGN_TABLE:
                relacl = get_user_default_acl(ACL_OBJECT_RELATION, ownerid,
                                              relnamespace);
                break;
            case RELKIND_SEQUENCE:
                relacl = get_user_default_acl(ACL_OBJECT_SEQUENCE, ownerid,
                                              relnamespace);
                break;
            default:
                relacl = NULL;
                break;
        }
    }
    else
        relacl = NULL;

    /*
     * Create the relcache entry (mostly dummy at this point) and the physical
     * disk file.  (If we fail further down, it's the smgr's responsibility to
     * remove the disk file again.)
     */
    new_rel_desc = heap_create(relname,
                               relnamespace,
                               reltablespace,
                               relid,
                               InvalidOid,
                               tupdesc,
                               relkind,
                               relpersistence,
                               shared_relation,
                               mapped_relation);

    Assert(relid == RelationGetRelid(new_rel_desc));

    /*
     * Decide whether to create an array type over the relation's rowtype. We
     * do not create any array types for system catalogs (ie, those made
     * during initdb).  We create array types for regular relations, views,
     * composite types and foreign tables ... but not, eg, for toast tables or
     * sequences.
     */
    if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
                              relkind == RELKIND_VIEW ||
                              relkind == RELKIND_MATVIEW ||
                              relkind == RELKIND_FOREIGN_TABLE ||
                              relkind == RELKIND_COMPOSITE_TYPE))
        new_array_oid = AssignTypeArrayOid();

    /*
     * Since defining a relation also defines a complex type, we add a new
     * system type corresponding to the new relation.  The OID of the type can
     * be preselected by the caller, but if reltypeid is InvalidOid, we'll
     * generate a new OID for it.
     *
     * NOTE: we could get a unique-index failure here, in case someone else is
     * creating the same type name in parallel but hadn't committed yet when
     * we checked for a duplicate name above.
     */
    new_type_oid = AddNewRelationType(relname,
                                      relnamespace,
                                      relid,
                                      relkind,
                                      ownerid,
                                      reltypeid,
                                      new_array_oid);

    /*
     * Now make the array type if wanted.
     */
    if (OidIsValid(new_array_oid))
    {
        char       *relarrayname;

        relarrayname = makeArrayTypeName(relname, relnamespace);

        TypeCreate(new_array_oid,       /* force the type's OID to this */
                   relarrayname,    /* Array type name */
                   relnamespace,    /* Same namespace as parent */
                   InvalidOid,  /* Not composite, no relationOid */
                   0,           /* relkind, also N/A here */
                   ownerid,     /* owner's ID */
                   -1,          /* Internal size (varlena) */
                   TYPTYPE_BASE,    /* Not composite - typelem is */
                   TYPCATEGORY_ARRAY,   /* type-category (array) */
                   false,       /* array types are never preferred */
                   DEFAULT_TYPDELIM,    /* default array delimiter */
                   F_ARRAY_IN,  /* array input proc */
                   F_ARRAY_OUT, /* array output proc */
                   F_ARRAY_RECV,    /* array recv (bin) proc */
                   F_ARRAY_SEND,    /* array send (bin) proc */
                   InvalidOid,  /* typmodin procedure - none */
                   InvalidOid,  /* typmodout procedure - none */
                   F_ARRAY_TYPANALYZE,  /* array analyze procedure */
                   new_type_oid,    /* array element type - the rowtype */
                   true,        /* yes, this is an array type */
                   InvalidOid,  /* this has no array type */
                   InvalidOid,  /* domain base type - irrelevant */
                   NULL,        /* default value - none */
                   NULL,        /* default binary representation */
                   false,       /* passed by reference */
                   'd',         /* alignment - must be the largest! */
                   'x',         /* fully TOASTable */
                   -1,          /* typmod */
                   0,           /* array dimensions for typBaseType */
                   false,       /* Type NOT NULL */
                   InvalidOid); /* rowtypes never have a collation */

        pfree(relarrayname);
    }

    /*
     * now create an entry in pg_class for the relation.
     *
     * NOTE: we could get a unique-index failure here, in case someone else is
     * creating the same relation name in parallel but hadn't committed yet
     * when we checked for a duplicate name above.
     */
    AddNewRelationTuple(pg_class_desc,
                        new_rel_desc,
                        relid,
                        new_type_oid,
                        reloftypeid,
                        ownerid,
                        relkind,
                        PointerGetDatum(relacl),
                        reloptions);

    /*
     * now add tuples to pg_attribute for the attributes in our new relation.
     */
    AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
                          oidislocal, oidinhcount);

    /*
     * Make a dependency link to force the relation to be deleted if its
     * namespace is.  Also make a dependency link to its owner, as well as
     * dependencies for any roles mentioned in the default ACL.
     *
     * For composite types, these dependencies are tracked for the pg_type
     * entry, so we needn't record them here.  Likewise, TOAST tables don't
     * need a namespace dependency (they live in a pinned namespace) nor an
     * owner dependency (they depend indirectly through the parent table), nor
     * should they have any ACL entries.  The same applies for extension
     * dependencies.
     *
     * If it's a temp table, we do not make it an extension member; this
     * prevents the unintuitive result that deletion of the temp table at
     * session end would make the whole extension go away.
     *
     * Also, skip this in bootstrap mode, since we don't make dependencies
     * while bootstrapping.
     */
    if (relkind != RELKIND_COMPOSITE_TYPE &&
        relkind != RELKIND_TOASTVALUE &&
        !IsBootstrapProcessingMode())
    {
        ObjectAddress myself,
                    referenced;

        myself.classId = RelationRelationId;
        myself.objectId = relid;
        myself.objectSubId = 0;
        referenced.classId = NamespaceRelationId;
        referenced.objectId = relnamespace;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

        recordDependencyOnOwner(RelationRelationId, relid, ownerid);

        if (relpersistence != RELPERSISTENCE_TEMP)
            recordDependencyOnCurrentExtension(&myself, false);

        if (reloftypeid)
        {
            referenced.classId = TypeRelationId;
            referenced.objectId = reloftypeid;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }

        if (relacl != NULL)
        {
            int         nnewmembers;
            Oid        *newmembers;

            nnewmembers = aclmembers(relacl, &newmembers);
            updateAclDependencies(RelationRelationId, relid, 0,
                                  ownerid,
                                  0, NULL,
                                  nnewmembers, newmembers);
        }
    }

    /* Post creation hook for new relation */
    InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);

    /*
     * Store any supplied constraints and defaults.
     *
     * NB: this may do a CommandCounterIncrement and rebuild the relcache
     * entry, so the relation must be valid and self-consistent at this point.
     * In particular, there are not yet constraints and defaults anywhere.
     */
    StoreConstraints(new_rel_desc, cooked_constraints, is_internal);

    /*
     * If there's a special on-commit action, remember it
     */
    if (oncommit != ONCOMMIT_NOOP)
        register_on_commit_action(relid, oncommit);

    if (relpersistence == RELPERSISTENCE_UNLOGGED)
    {
        Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
               relkind == RELKIND_TOASTVALUE);
        heap_create_init_fork(new_rel_desc);
    }

    /*
     * ok, the relation has been cataloged, so close our relations and return
     * the OID of the newly created relation.
     */
    heap_close(new_rel_desc, NoLock);   /* do not unlock till end of xact */
    heap_close(pg_class_desc, RowExclusiveLock);

    return relid;
}

void heap_drop_with_catalog ( Oid  relid  ) 

Definition at line 1739 of file heap.c.

References AccessExclusiveLock, CheckTableForSerializableConflictIn(), CheckTableNotInUse(), DeleteAttributeTuples(), DeleteRelationTuple(), elog, ERROR, FOREIGNTABLEREL, ForeignTableRelationId, heap_close, heap_open(), HeapTupleIsValid, NoLock, ObjectIdGetDatum, RelationData::rd_rel, relation_close(), relation_open(), RelationDropStorage(), RelationForgetRelation(), RelationRemoveInheritance(), ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_VIEW, remove_on_commit_action(), RemoveStatistics(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    rel;

    /*
     * Open and lock the relation.
     */
    rel = relation_open(relid, AccessExclusiveLock);

    /*
     * There can no longer be anyone *else* touching the relation, but we
     * might still have open queries or cursors, or pending trigger events, in
     * our own session.
     */
    CheckTableNotInUse(rel, "DROP TABLE");

    /*
     * This effectively deletes all rows in the table, and may be done in a
     * serializable transaction.  In that case we must record a rw-conflict in
     * to this transaction from each transaction holding a predicate lock on
     * the table.
     */
    CheckTableForSerializableConflictIn(rel);

    /*
     * Delete pg_foreign_table tuple first.
     */
    if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    {
        Relation    rel;
        HeapTuple   tuple;

        rel = heap_open(ForeignTableRelationId, RowExclusiveLock);

        tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
        if (!HeapTupleIsValid(tuple))
            elog(ERROR, "cache lookup failed for foreign table %u", relid);

        simple_heap_delete(rel, &tuple->t_self);

        ReleaseSysCache(tuple);
        heap_close(rel, RowExclusiveLock);
    }

    /*
     * Schedule unlinking of the relation's physical files at commit.
     */
    if (rel->rd_rel->relkind != RELKIND_VIEW &&
        rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
        rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
    {
        RelationDropStorage(rel);
    }

    /*
     * Close relcache entry, but *keep* AccessExclusiveLock on the relation
     * until transaction commit.  This ensures no one else will try to do
     * something with the doomed relation.
     */
    relation_close(rel, NoLock);

    /*
     * Forget any ON COMMIT action for the rel
     */
    remove_on_commit_action(relid);

    /*
     * Flush the relation from the relcache.  We want to do this before
     * starting to remove catalog entries, just to be certain that no relcache
     * entry rebuild will happen partway through.  (That should not really
     * matter, since we don't do CommandCounterIncrement here, but let's be
     * safe.)
     */
    RelationForgetRelation(relid);

    /*
     * remove inheritance information
     */
    RelationRemoveInheritance(relid);

    /*
     * delete statistics
     */
    RemoveStatistics(relid, 0);

    /*
     * delete attribute tuples
     */
    DeleteAttributeTuples(relid);

    /*
     * delete relation tuple
     */
    DeleteRelationTuple(relid);
}

bool heap_is_matview_init_state ( Relation  rel  ) 
void heap_truncate ( List relids  ) 

Definition at line 2708 of file heap.c.

References AccessExclusiveLock, heap_close, heap_open(), heap_truncate_check_FKs(), heap_truncate_one_rel(), lappend(), lfirst, lfirst_oid, and NoLock.

Referenced by PreCommit_on_commit_actions().

{
    List       *relations = NIL;
    ListCell   *cell;

    /* Open relations for processing, and grab exclusive access on each */
    foreach(cell, relids)
    {
        Oid         rid = lfirst_oid(cell);
        Relation    rel;

        rel = heap_open(rid, AccessExclusiveLock);
        relations = lappend(relations, rel);
    }

    /* Don't allow truncate on tables that are referenced by foreign keys */
    heap_truncate_check_FKs(relations, true);

    /* OK to do it */
    foreach(cell, relations)
    {
        Relation    rel = lfirst(cell);

        /* Truncate the relation */
        heap_truncate_one_rel(rel);

        /* Close the relation, but keep exclusive lock on it until commit */
        heap_close(rel, NoLock);
    }
}

void heap_truncate_check_FKs ( List relations,
bool  tempTables 
)

Definition at line 2786 of file heap.c.

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

Referenced by ExecuteTruncate(), and heap_truncate().

{
    List       *oids = NIL;
    List       *dependents;
    ListCell   *cell;

    /*
     * Build a list of OIDs of the interesting relations.
     *
     * If a relation has no triggers, then it can neither have FKs nor be
     * referenced by a FK from another table, so we can ignore it.
     */
    foreach(cell, relations)
    {
        Relation    rel = lfirst(cell);

        if (rel->rd_rel->relhastriggers)
            oids = lappend_oid(oids, RelationGetRelid(rel));
    }

    /*
     * Fast path: if no relation has triggers, none has FKs either.
     */
    if (oids == NIL)
        return;

    /*
     * Otherwise, must scan pg_constraint.  We make one pass with all the
     * relations considered; if this finds nothing, then all is well.
     */
    dependents = heap_truncate_find_FKs(oids);
    if (dependents == NIL)
        return;

    /*
     * Otherwise we repeat the scan once per relation to identify a particular
     * pair of relations to complain about.  This is pretty slow, but
     * performance shouldn't matter much in a failure path.  The reason for
     * doing things this way is to ensure that the message produced is not
     * dependent on chance row locations within pg_constraint.
     */
    foreach(cell, oids)
    {
        Oid         relid = lfirst_oid(cell);
        ListCell   *cell2;

        dependents = heap_truncate_find_FKs(list_make1_oid(relid));

        foreach(cell2, dependents)
        {
            Oid         relid2 = lfirst_oid(cell2);

            if (!list_member_oid(oids, relid2))
            {
                char       *relname = get_rel_name(relid);
                char       *relname2 = get_rel_name(relid2);

                if (tempTables)
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("unsupported ON COMMIT and foreign key combination"),
                             errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
                                       relname2, relname)));
                else
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("cannot truncate a table referenced in a foreign key constraint"),
                             errdetail("Table \"%s\" references \"%s\".",
                                       relname2, relname),
                           errhint("Truncate table \"%s\" at the same time, "
                                   "or use TRUNCATE ... CASCADE.",
                                   relname2)));
            }
        }
    }
}

List* heap_truncate_find_FKs ( List relationIds  ) 

Definition at line 2878 of file heap.c.

References AccessShareLock, CONSTRAINT_FOREIGN, ConstraintRelationId, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, insert_ordered_unique_oid(), InvalidOid, list_member_oid(), NULL, SnapshotNow, systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by ExecuteTruncate(), and heap_truncate_check_FKs().

{
    List       *result = NIL;
    Relation    fkeyRel;
    SysScanDesc fkeyScan;
    HeapTuple   tuple;

    /*
     * Must scan pg_constraint.  Right now, it is a seqscan because there is
     * no available index on confrelid.
     */
    fkeyRel = heap_open(ConstraintRelationId, AccessShareLock);

    fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
                                  SnapshotNow, 0, NULL);

    while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
    {
        Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);

        /* Not a foreign key */
        if (con->contype != CONSTRAINT_FOREIGN)
            continue;

        /* Not referencing one of our list of tables */
        if (!list_member_oid(relationIds, con->confrelid))
            continue;

        /* Add referencer unless already in input or result list */
        if (!list_member_oid(relationIds, con->conrelid))
            result = insert_ordered_unique_oid(result, con->conrelid);
    }

    systable_endscan(fkeyScan);
    heap_close(fkeyRel, AccessShareLock);

    return result;
}

void heap_truncate_one_rel ( Relation  rel  ) 

Definition at line 2749 of file heap.c.

References AccessExclusiveLock, heap_close, heap_open(), NoLock, OidIsValid, RelationData::rd_rel, RelationTruncate(), and RelationTruncateIndexes().

Referenced by ExecuteTruncate(), and heap_truncate().

{
    Oid         toastrelid;

    /* Truncate the actual file (and discard buffers) */
    RelationTruncate(rel, 0);

    /* If the relation has indexes, truncate the indexes too */
    RelationTruncateIndexes(rel);

    /* If there is a toast table, truncate that too */
    toastrelid = rel->rd_rel->reltoastrelid;
    if (OidIsValid(toastrelid))
    {
        Relation    toastrel = heap_open(toastrelid, AccessExclusiveLock);

        RelationTruncate(toastrel, 0);
        RelationTruncateIndexes(toastrel);
        /* keep the lock... */
        heap_close(toastrel, NoLock);
    }
}

void InsertPgAttributeTuple ( Relation  pg_attribute_rel,
Form_pg_attribute  new_attribute,
CatalogIndexState  indstate 
)

Definition at line 577 of file heap.c.

References Anum_pg_attribute_attacl, Anum_pg_attribute_attalign, Anum_pg_attribute_attbyval, Anum_pg_attribute_attcacheoff, Anum_pg_attribute_attcollation, Anum_pg_attribute_attfdwoptions, Anum_pg_attribute_atthasdef, Anum_pg_attribute_attinhcount, Anum_pg_attribute_attisdropped, Anum_pg_attribute_attislocal, Anum_pg_attribute_attlen, Anum_pg_attribute_attname, Anum_pg_attribute_attndims, Anum_pg_attribute_attnotnull, Anum_pg_attribute_attnum, Anum_pg_attribute_attoptions, Anum_pg_attribute_attrelid, Anum_pg_attribute_attstattarget, Anum_pg_attribute_attstorage, Anum_pg_attribute_atttypid, Anum_pg_attribute_atttypmod, BoolGetDatum, CatalogIndexInsert(), CatalogUpdateIndexes(), CharGetDatum, heap_form_tuple(), heap_freetuple(), Int16GetDatum, Int32GetDatum, NameGetDatum, NULL, ObjectIdGetDatum, RelationGetDescr, simple_heap_insert(), and values.

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

{
    Datum       values[Natts_pg_attribute];
    bool        nulls[Natts_pg_attribute];
    HeapTuple   tup;

    /* This is a tad tedious, but way cleaner than what we used to do... */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid);
    values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname);
    values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid);
    values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget);
    values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen);
    values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum);
    values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims);
    values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(new_attribute->attcacheoff);
    values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod);
    values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval);
    values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage);
    values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign);
    values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull);
    values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef);
    values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
    values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
    values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
    values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation);

    /* start out with empty permissions and empty options */
    nulls[Anum_pg_attribute_attacl - 1] = true;
    nulls[Anum_pg_attribute_attoptions - 1] = true;
    nulls[Anum_pg_attribute_attfdwoptions - 1] = true;

    tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);

    /* finally insert the new tuple, update the indexes, and clean up */
    simple_heap_insert(pg_attribute_rel, tup);

    if (indstate != NULL)
        CatalogIndexInsert(indstate, tup);
    else
        CatalogUpdateIndexes(pg_attribute_rel, tup);

    heap_freetuple(tup);
}

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

Definition at line 744 of file heap.c.

References Anum_pg_class_relacl, Anum_pg_class_relallvisible, Anum_pg_class_relam, Anum_pg_class_relchecks, Anum_pg_class_relfilenode, Anum_pg_class_relfrozenxid, Anum_pg_class_relhasindex, Anum_pg_class_relhasoids, Anum_pg_class_relhaspkey, Anum_pg_class_relhasrules, Anum_pg_class_relhassubclass, Anum_pg_class_relhastriggers, Anum_pg_class_relisshared, Anum_pg_class_relkind, Anum_pg_class_relminmxid, Anum_pg_class_relname, Anum_pg_class_relnamespace, Anum_pg_class_relnatts, Anum_pg_class_reloftype, Anum_pg_class_reloptions, Anum_pg_class_relowner, Anum_pg_class_relpages, Anum_pg_class_relpersistence, Anum_pg_class_reltablespace, Anum_pg_class_reltoastidxid, Anum_pg_class_reltoastrelid, Anum_pg_class_reltuples, Anum_pg_class_reltype, BoolGetDatum, CatalogUpdateIndexes(), CharGetDatum, Float4GetDatum(), heap_form_tuple(), heap_freetuple(), HeapTupleSetOid, Int16GetDatum, Int32GetDatum, MultiXactIdGetDatum, NameGetDatum, ObjectIdGetDatum, RelationData::rd_rel, RelationGetDescr, simple_heap_insert(), TransactionIdGetDatum, and values.

Referenced by AddNewRelationTuple(), and index_create().

{
    Form_pg_class rd_rel = new_rel_desc->rd_rel;
    Datum       values[Natts_pg_class];
    bool        nulls[Natts_pg_class];
    HeapTuple   tup;

    /* This is a tad tedious, but way cleaner than what we used to do... */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
    values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
    values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
    values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
    values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
    values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
    values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
    values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
    values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
    values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
    values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
    values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
    values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
    values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
    values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
    values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
    values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
    values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
    values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
    values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids);
    values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey);
    values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
    values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
    values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
    values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
    values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
    if (relacl != (Datum) 0)
        values[Anum_pg_class_relacl - 1] = relacl;
    else
        nulls[Anum_pg_class_relacl - 1] = true;
    if (reloptions != (Datum) 0)
        values[Anum_pg_class_reloptions - 1] = reloptions;
    else
        nulls[Anum_pg_class_reloptions - 1] = true;

    tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls);

    /*
     * The new tuple must have the oid already chosen for the rel.  Sure would
     * be embarrassing to do this sort of thing in polite company.
     */
    HeapTupleSetOid(tup, new_rel_oid);

    /* finally insert the new tuple, update the indexes, and clean up */
    simple_heap_insert(pg_class_desc, tup);

    CatalogUpdateIndexes(pg_class_desc, tup);

    heap_freetuple(tup);
}

void RemoveAttrDefault ( Oid  relid,
AttrNumber  attnum,
DropBehavior  behavior,
bool  complain,
bool  internal 
)

Definition at line 1609 of file heap.c.

References Anum_pg_attrdef_adnum, Anum_pg_attrdef_adrelid, AttrDefaultIndexId, AttrDefaultRelationId, BTEqualStrategyNumber, ObjectAddress::classId, elog, ERROR, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, Int16GetDatum, ObjectAddressStack::object, ObjectIdGetDatum, PERFORM_DELETION_INTERNAL, performDeletion(), RowExclusiveLock, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by ATExecAlterColumnType(), and ATExecColumnDefault().

{
    Relation    attrdef_rel;
    ScanKeyData scankeys[2];
    SysScanDesc scan;
    HeapTuple   tuple;
    bool        found = false;

    attrdef_rel = heap_open(AttrDefaultRelationId, RowExclusiveLock);

    ScanKeyInit(&scankeys[0],
                Anum_pg_attrdef_adrelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(relid));
    ScanKeyInit(&scankeys[1],
                Anum_pg_attrdef_adnum,
                BTEqualStrategyNumber, F_INT2EQ,
                Int16GetDatum(attnum));

    scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
                              SnapshotNow, 2, scankeys);

    /* There should be at most one matching tuple, but we loop anyway */
    while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    {
        ObjectAddress object;

        object.classId = AttrDefaultRelationId;
        object.objectId = HeapTupleGetOid(tuple);
        object.objectSubId = 0;

        performDeletion(&object, behavior,
                        internal ? PERFORM_DELETION_INTERNAL : 0);

        found = true;
    }

    systable_endscan(scan);
    heap_close(attrdef_rel, RowExclusiveLock);

    if (complain && !found)
        elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
             relid, attnum);
}

void RemoveAttrDefaultById ( Oid  attrdefId  ) 

Definition at line 1663 of file heap.c.

References AccessExclusiveLock, ATTNUM, AttrDefaultOidIndexId, AttrDefaultRelationId, AttributeRelationId, BTEqualStrategyNumber, CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, Int16GetDatum, NoLock, ObjectIdAttributeNumber, ObjectIdGetDatum, relation_close(), relation_open(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy2, simple_heap_delete(), simple_heap_update(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    attrdef_rel;
    Relation    attr_rel;
    Relation    myrel;
    ScanKeyData scankeys[1];
    SysScanDesc scan;
    HeapTuple   tuple;
    Oid         myrelid;
    AttrNumber  myattnum;

    /* Grab an appropriate lock on the pg_attrdef relation */
    attrdef_rel = heap_open(AttrDefaultRelationId, RowExclusiveLock);

    /* Find the pg_attrdef tuple */
    ScanKeyInit(&scankeys[0],
                ObjectIdAttributeNumber,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(attrdefId));

    scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
                              SnapshotNow, 1, scankeys);

    tuple = systable_getnext(scan);
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for attrdef %u", attrdefId);

    myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
    myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;

    /* Get an exclusive lock on the relation owning the attribute */
    myrel = relation_open(myrelid, AccessExclusiveLock);

    /* Now we can delete the pg_attrdef row */
    simple_heap_delete(attrdef_rel, &tuple->t_self);

    systable_endscan(scan);
    heap_close(attrdef_rel, RowExclusiveLock);

    /* Fix the pg_attribute row */
    attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);

    tuple = SearchSysCacheCopy2(ATTNUM,
                                ObjectIdGetDatum(myrelid),
                                Int16GetDatum(myattnum));
    if (!HeapTupleIsValid(tuple))       /* shouldn't happen */
        elog(ERROR, "cache lookup failed for attribute %d of relation %u",
             myattnum, myrelid);

    ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;

    simple_heap_update(attr_rel, &tuple->t_self, tuple);

    /* keep the system catalog indexes current */
    CatalogUpdateIndexes(attr_rel, tuple);

    /*
     * Our update of the pg_attribute row will force a relcache rebuild, so
     * there's nothing else to do here.
     */
    heap_close(attr_rel, RowExclusiveLock);

    /* Keep lock on attribute's rel until end of xact */
    relation_close(myrel, NoLock);
}

void RemoveAttributeById ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 1518 of file heap.c.

References AccessExclusiveLock, ATTNUM, AttributeRelationId, CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, Int16GetDatum, namestrcpy(), NoLock, ObjectIdGetDatum, relation_close(), relation_open(), RemoveStatistics(), RowExclusiveLock, SearchSysCacheCopy2, simple_heap_delete(), simple_heap_update(), snprintf(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    rel;
    Relation    attr_rel;
    HeapTuple   tuple;
    Form_pg_attribute attStruct;
    char        newattname[NAMEDATALEN];

    /*
     * Grab an exclusive lock on the target table, which we will NOT release
     * until end of transaction.  (In the simple case where we are directly
     * dropping this column, AlterTableDropColumn already did this ... but
     * when cascading from a drop of some other object, we may not have any
     * lock.)
     */
    rel = relation_open(relid, AccessExclusiveLock);

    attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);

    tuple = SearchSysCacheCopy2(ATTNUM,
                                ObjectIdGetDatum(relid),
                                Int16GetDatum(attnum));
    if (!HeapTupleIsValid(tuple))       /* shouldn't happen */
        elog(ERROR, "cache lookup failed for attribute %d of relation %u",
             attnum, relid);
    attStruct = (Form_pg_attribute) GETSTRUCT(tuple);

    if (attnum < 0)
    {
        /* System attribute (probably OID) ... just delete the row */

        simple_heap_delete(attr_rel, &tuple->t_self);
    }
    else
    {
        /* Dropping user attributes is lots harder */

        /* Mark the attribute as dropped */
        attStruct->attisdropped = true;

        /*
         * Set the type OID to invalid.  A dropped attribute's type link
         * cannot be relied on (once the attribute is dropped, the type might
         * be too). Fortunately we do not need the type row --- the only
         * really essential information is the type's typlen and typalign,
         * which are preserved in the attribute's attlen and attalign.  We set
         * atttypid to zero here as a means of catching code that incorrectly
         * expects it to be valid.
         */
        attStruct->atttypid = InvalidOid;

        /* Remove any NOT NULL constraint the column may have */
        attStruct->attnotnull = false;

        /* We don't want to keep stats for it anymore */
        attStruct->attstattarget = 0;

        /*
         * Change the column name to something that isn't likely to conflict
         */
        snprintf(newattname, sizeof(newattname),
                 "........pg.dropped.%d........", attnum);
        namestrcpy(&(attStruct->attname), newattname);

        simple_heap_update(attr_rel, &tuple->t_self, tuple);

        /* keep the system catalog indexes current */
        CatalogUpdateIndexes(attr_rel, tuple);
    }

    /*
     * Because updating the pg_attribute row will trigger a relcache flush for
     * the target relation, we need not do anything else to notify other
     * backends of the change.
     */

    heap_close(attr_rel, RowExclusiveLock);

    if (attnum > 0)
        RemoveStatistics(relid, attnum);

    relation_close(rel, NoLock);
}

void RemoveStatistics ( Oid  relid,
AttrNumber  attnum 
)
void StoreAttrDefault ( Relation  rel,
AttrNumber  attnum,
Node expr,
bool  is_internal 
)

Definition at line 1840 of file heap.c.

References Anum_pg_attrdef_adbin, Anum_pg_attrdef_adnum, Anum_pg_attrdef_adrelid, Anum_pg_attrdef_adsrc, ATTNUM, AttrDefaultRelationId, AttributeRelationId, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetTextDatum, DatumGetPointer, deparse_context_for(), deparse_expression(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ERROR, GETSTRUCT, heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleIsValid, Int16GetDatum, InvokeObjectPostCreateHookArg, NIL, nodeToString(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, pfree(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnExpr(), RelationGetRelationName, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy2, simple_heap_insert(), simple_heap_update(), HeapTupleData::t_self, and values.

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

{
    char       *adbin;
    char       *adsrc;
    Relation    adrel;
    HeapTuple   tuple;
    Datum       values[4];
    static bool nulls[4] = {false, false, false, false};
    Relation    attrrel;
    HeapTuple   atttup;
    Form_pg_attribute attStruct;
    Oid         attrdefOid;
    ObjectAddress colobject,
                defobject;

    /*
     * Flatten expression to string form for storage.
     */
    adbin = nodeToString(expr);

    /*
     * Also deparse it to form the mostly-obsolete adsrc field.
     */
    adsrc = deparse_expression(expr,
                            deparse_context_for(RelationGetRelationName(rel),
                                                RelationGetRelid(rel)),
                               false, false);

    /*
     * Make the pg_attrdef entry.
     */
    values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
    values[Anum_pg_attrdef_adnum - 1] = attnum;
    values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
    values[Anum_pg_attrdef_adsrc - 1] = CStringGetTextDatum(adsrc);

    adrel = heap_open(AttrDefaultRelationId, RowExclusiveLock);

    tuple = heap_form_tuple(adrel->rd_att, values, nulls);
    attrdefOid = simple_heap_insert(adrel, tuple);

    CatalogUpdateIndexes(adrel, tuple);

    defobject.classId = AttrDefaultRelationId;
    defobject.objectId = attrdefOid;
    defobject.objectSubId = 0;

    heap_close(adrel, RowExclusiveLock);

    /* now can free some of the stuff allocated above */
    pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
    pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
    heap_freetuple(tuple);
    pfree(adbin);
    pfree(adsrc);

    /*
     * Update the pg_attribute entry for the column to show that a default
     * exists.
     */
    attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
    atttup = SearchSysCacheCopy2(ATTNUM,
                                 ObjectIdGetDatum(RelationGetRelid(rel)),
                                 Int16GetDatum(attnum));
    if (!HeapTupleIsValid(atttup))
        elog(ERROR, "cache lookup failed for attribute %d of relation %u",
             attnum, RelationGetRelid(rel));
    attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
    if (!attStruct->atthasdef)
    {
        attStruct->atthasdef = true;
        simple_heap_update(attrrel, &atttup->t_self, atttup);
        /* keep catalog indexes current */
        CatalogUpdateIndexes(attrrel, atttup);
    }
    heap_close(attrrel, RowExclusiveLock);
    heap_freetuple(atttup);

    /*
     * Make a dependency so that the pg_attrdef entry goes away if the column
     * (or whole table) is deleted.
     */
    colobject.classId = RelationRelationId;
    colobject.objectId = RelationGetRelid(rel);
    colobject.objectSubId = attnum;

    recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);

    /*
     * Record dependencies on objects used in the expression, too.
     */
    recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);

    /*
     * Post creation hook for attribute defaults.
     *
     * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented
     * with a couple of deletion/creation of the attribute's default entry,
     * so the callee should check existence of an older version of this
     * entry if it needs to distinguish.
     */
    InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
                                  RelationGetRelid(rel), attnum, is_internal);
}

Form_pg_attribute SystemAttributeByName ( const char *  attname,
bool  relhasoids 
)

Definition at line 204 of file heap.c.

References lengthof, NameStr, and ObjectIdAttributeNumber.

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

{
    int         j;

    for (j = 0; j < (int) lengthof(SysAtt); j++)
    {
        Form_pg_attribute att = SysAtt[j];

        if (relhasoids || att->attnum != ObjectIdAttributeNumber)
        {
            if (strcmp(NameStr(att->attname), attname) == 0)
                return att;
        }
    }

    return NULL;
}

Form_pg_attribute SystemAttributeDefinition ( AttrNumber  attno,
bool  relhasoids 
)

Definition at line 190 of file heap.c.

References elog, ERROR, lengthof, and ObjectIdAttributeNumber.

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

{
    if (attno >= 0 || attno < -(int) lengthof(SysAtt))
        elog(ERROR, "invalid system attribute number %d", attno);
    if (attno == ObjectIdAttributeNumber && !relhasoids)
        elog(ERROR, "invalid system attribute number %d", attno);
    return SysAtt[-attno - 1];
}