Header And Logo

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

Functions | Variables

heap.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "catalog/pg_type_fn.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for heap.c:

Go to the source code of this file.

Functions

static void AddNewRelationTuple (Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions)
static Oid AddNewRelationType (const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid, Oid new_row_type, Oid new_array_type)
static void RelationRemoveInheritance (Oid relid)
static void StoreRelCheck (Relation rel, char *ccname, Node *expr, bool is_validated, bool is_local, int inhcount, bool is_no_inherit, bool is_internal)
static void StoreConstraints (Relation rel, List *cooked_constraints, bool is_internal)
static bool MergeWithExistingConstraint (Relation rel, char *ccname, Node *expr, bool allow_merge, bool is_local, bool is_no_inherit)
static void SetRelationNumChecks (Relation rel, int numchecks)
static NodecookConstraint (ParseState *pstate, Node *raw_constraint, char *relname)
static Listinsert_ordered_unique_oid (List *list, Oid datum)
Form_pg_attribute SystemAttributeDefinition (AttrNumber attno, bool relhasoids)
Form_pg_attribute SystemAttributeByName (const char *attname, bool relhasoids)
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)
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)
void InsertPgAttributeTuple (Relation pg_attribute_rel, Form_pg_attribute new_attribute, CatalogIndexState indstate)
static void AddNewAttributeTuples (Oid new_rel_oid, TupleDesc tupdesc, char relkind, bool oidislocal, int oidinhcount)
void InsertPgClassTuple (Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Datum relacl, Datum reloptions)
Oid heap_create_with_catalog (const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, 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 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 heap_drop_with_catalog (Oid relid)
void StoreAttrDefault (Relation rel, AttrNumber attnum, Node *expr, bool is_internal)
ListAddRelationNewConstraints (Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
NodecookDefault (ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, char *attname)
void RemoveStatistics (Oid relid, AttrNumber attnum)
static void RelationTruncateIndexes (Relation heapRelation)
void heap_truncate (List *relids)
void heap_truncate_one_rel (Relation rel)
void heap_truncate_check_FKs (List *relations, bool tempTables)
Listheap_truncate_find_FKs (List *relationIds)

Variables

Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid
Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid
static FormData_pg_attribute a1
static FormData_pg_attribute a2
static FormData_pg_attribute a3
static FormData_pg_attribute a4
static FormData_pg_attribute a5
static FormData_pg_attribute a6
static FormData_pg_attribute a7
static const Form_pg_attribute SysAtt [] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}

Function Documentation

static void AddNewAttributeTuples ( Oid  new_rel_oid,
TupleDesc  tupdesc,
char  relkind,
bool  oidislocal,
int  oidinhcount 
) [static]

Definition at line 634 of file heap.c.

References AttributeRelationId, tupleDesc::attrs, CatalogCloseIndexes(), CatalogOpenIndexes(), ObjectAddress::classId, DEFAULT_COLLATION_OID, DEPENDENCY_NORMAL, FormData_pg_attribute, heap_close, heap_open(), i, InsertPgAttributeTuple(), lengthof, tupleDesc::natts, ObjectAddress::objectId, ObjectIdAttributeNumber, ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), RELKIND_COMPOSITE_TYPE, RELKIND_VIEW, RowExclusiveLock, and tupleDesc::tdhasoid.

Referenced by heap_create_with_catalog().

{
    Form_pg_attribute attr;
    int         i;
    Relation    rel;
    CatalogIndexState indstate;
    int         natts = tupdesc->natts;
    ObjectAddress myself,
                referenced;

    /*
     * open pg_attribute and its indexes.
     */
    rel = heap_open(AttributeRelationId, RowExclusiveLock);

    indstate = CatalogOpenIndexes(rel);

    /*
     * First we add the user attributes.  This is also a convenient place to
     * add dependencies on their datatypes and collations.
     */
    for (i = 0; i < natts; i++)
    {
        attr = tupdesc->attrs[i];
        /* Fill in the correct relation OID */
        attr->attrelid = new_rel_oid;
        /* Make sure these are OK, too */
        attr->attstattarget = -1;
        attr->attcacheoff = -1;

        InsertPgAttributeTuple(rel, attr, indstate);

        /* Add dependency info */
        myself.classId = RelationRelationId;
        myself.objectId = new_rel_oid;
        myself.objectSubId = i + 1;
        referenced.classId = TypeRelationId;
        referenced.objectId = attr->atttypid;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

        /* The default collation is pinned, so don't bother recording it */
        if (OidIsValid(attr->attcollation) &&
            attr->attcollation != DEFAULT_COLLATION_OID)
        {
            referenced.classId = CollationRelationId;
            referenced.objectId = attr->attcollation;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
    }

    /*
     * Next we add the system attributes.  Skip OID if rel has no OIDs. Skip
     * all for a view or type relation.  We don't bother with making datatype
     * dependencies here, since presumably all these types are pinned.
     */
    if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
    {
        for (i = 0; i < (int) lengthof(SysAtt); i++)
        {
            FormData_pg_attribute attStruct;

            /* skip OID where appropriate */
            if (!tupdesc->tdhasoid &&
                SysAtt[i]->attnum == ObjectIdAttributeNumber)
                continue;

            memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute));

            /* Fill in the correct relation OID in the copied tuple */
            attStruct.attrelid = new_rel_oid;

            /* Fill in correct inheritance info for the OID column */
            if (attStruct.attnum == ObjectIdAttributeNumber)
            {
                attStruct.attislocal = oidislocal;
                attStruct.attinhcount = oidinhcount;
            }

            InsertPgAttributeTuple(rel, &attStruct, indstate);
        }
    }

    /*
     * clean up
     */
    CatalogCloseIndexes(indstate);

    heap_close(rel, RowExclusiveLock);
}

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,
Datum  relacl,
Datum  reloptions 
) [static]

Definition at line 818 of file heap.c.

References GetOldestMultiXactId(), InsertPgClassTuple(), RelationData::rd_att, RelationData::rd_rel, RecentXmin, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, and tupleDesc::tdtypeid.

Referenced by heap_create_with_catalog().

{
    Form_pg_class new_rel_reltup;

    /*
     * first we update some of the information in our uncataloged relation's
     * relation descriptor.
     */
    new_rel_reltup = new_rel_desc->rd_rel;

    switch (relkind)
    {
        case RELKIND_RELATION:
        case RELKIND_MATVIEW:
        case RELKIND_INDEX:
        case RELKIND_TOASTVALUE:
            /* The relation is real, but as yet empty */
            new_rel_reltup->relpages = 0;
            new_rel_reltup->reltuples = 0;
            new_rel_reltup->relallvisible = 0;
            break;
        case RELKIND_SEQUENCE:
            /* Sequences always have a known size */
            new_rel_reltup->relpages = 1;
            new_rel_reltup->reltuples = 1;
            new_rel_reltup->relallvisible = 0;
            break;
        default:
            /* Views, etc, have no disk storage */
            new_rel_reltup->relpages = 0;
            new_rel_reltup->reltuples = 0;
            new_rel_reltup->relallvisible = 0;
            break;
    }

    /* Initialize relfrozenxid and relminmxid */
    if (relkind == RELKIND_RELATION ||
        relkind == RELKIND_MATVIEW ||
        relkind == RELKIND_TOASTVALUE)
    {
        /*
         * Initialize to the minimum XID that could put tuples in the table.
         * We know that no xacts older than RecentXmin are still running, so
         * that will do.
         */
        new_rel_reltup->relfrozenxid = RecentXmin;
        /*
         * Similarly, initialize the minimum Multixact to the first value that
         * could possibly be stored in tuples in the table.  Running
         * transactions could reuse values from their local cache, so we are
         * careful to consider all currently running multis.
         *
         * XXX this could be refined further, but is it worth the hassle?
         */
        new_rel_reltup->relminmxid = GetOldestMultiXactId();
    }
    else
    {
        /*
         * Other relation types will not contain XIDs, so set relfrozenxid to
         * InvalidTransactionId.  (Note: a sequence does contain a tuple, but
         * we force its xmin to be FrozenTransactionId always; see
         * commands/sequence.c.)
         */
        new_rel_reltup->relfrozenxid = InvalidTransactionId;
        new_rel_reltup->relfrozenxid = InvalidMultiXactId;
    }

    new_rel_reltup->relowner = relowner;
    new_rel_reltup->reltype = new_type_oid;
    new_rel_reltup->reloftype = reloftype;

    new_rel_desc->rd_att->tdtypeid = new_type_oid;

    /* Now build and insert the tuple */
    InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
                       relacl, reloptions);
}

static Oid AddNewRelationType ( const char *  typeName,
Oid  typeNamespace,
Oid  new_rel_oid,
char  new_rel_kind,
Oid  ownerid,
Oid  new_row_type,
Oid  new_array_type 
) [static]

Definition at line 913 of file heap.c.

References DEFAULT_TYPDELIM, InvalidOid, NULL, TYPCATEGORY_COMPOSITE, TypeCreate(), and TYPTYPE_COMPOSITE.

Referenced by heap_create_with_catalog().

{
    return
        TypeCreate(new_row_type,    /* optional predetermined OID */
                   typeName,    /* type name */
                   typeNamespace,       /* type namespace */
                   new_rel_oid, /* relation oid */
                   new_rel_kind,    /* relation kind */
                   ownerid,     /* owner's ID */
                   -1,          /* internal size (varlena) */
                   TYPTYPE_COMPOSITE,   /* type-type (composite) */
                   TYPCATEGORY_COMPOSITE,       /* type-category (ditto) */
                   false,       /* composite types are never preferred */
                   DEFAULT_TYPDELIM,    /* default array delimiter */
                   F_RECORD_IN, /* input procedure */
                   F_RECORD_OUT,    /* output procedure */
                   F_RECORD_RECV,       /* receive procedure */
                   F_RECORD_SEND,       /* send procedure */
                   InvalidOid,  /* typmodin procedure - none */
                   InvalidOid,  /* typmodout procedure - none */
                   InvalidOid,  /* analyze procedure - default */
                   InvalidOid,  /* array element type - irrelevant */
                   false,       /* this is not an array type */
                   new_array_type,      /* array type if any */
                   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 */
}

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.")));
}

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

Definition at line 2578 of file heap.c.

References assign_expr_collations(), coerce_to_boolean(), ereport, errcode(), errmsg(), ERROR, EXPR_KIND_CHECK_CONSTRAINT, list_length(), ParseState::p_rtable, and transformExpr().

Referenced by AddRelationNewConstraints().

{
    Node       *expr;

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

    /*
     * Make sure it yields a boolean result.
     */
    expr = coerce_to_boolean(pstate, expr, "CHECK");

    /*
     * Take care of collations.
     */
    assign_expr_collations(pstate, expr);

    /*
     * Make sure no outside relations are referred to (this is probably dead
     * code now that add_missing_from is history).
     */
    if (list_length(pstate->p_rtable) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
            errmsg("only table \"%s\" can be referenced in check constraint",
                   relname)));

    return expr;
}

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);
    }
}

static List * insert_ordered_unique_oid ( List list,
Oid  datum 
) [static]

Definition at line 2928 of file heap.c.

References lappend_cell_oid(), lcons_oid(), lfirst_oid, linitial_oid, list_head(), lnext, NIL, and NULL.

Referenced by heap_truncate_find_FKs().

{
    ListCell   *prev;

    /* Does the datum belong at the front? */
    if (list == NIL || datum < linitial_oid(list))
        return lcons_oid(datum, list);
    /* Does it match the first entry? */
    if (datum == linitial_oid(list))
        return list;            /* duplicate, so don't insert */
    /* No, so find the entry it belongs after */
    prev = list_head(list);
    for (;;)
    {
        ListCell   *curr = lnext(prev);

        if (curr == NULL || datum < lfirst_oid(curr))
            break;              /* it belongs after 'prev', before 'curr' */

        if (datum == lfirst_oid(curr))
            return list;        /* duplicate, so don't insert */

        prev = curr;
    }
    /* Insert datum into list after 'prev' */
    lappend_cell_oid(list, prev, datum);
    return list;
}

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);
}

static bool MergeWithExistingConstraint ( Relation  rel,
char *  ccname,
Node expr,
bool  allow_merge,
bool  is_local,
bool  is_no_inherit 
) [static]

Definition at line 2355 of file heap.c.

References Anum_pg_constraint_conbin, Anum_pg_constraint_conname, Anum_pg_constraint_connamespace, Assert, BTEqualStrategyNumber, CatalogUpdateIndexes(), CONSTRAINT_CHECK, ConstraintNameNspIndexId, ConstraintRelationId, CStringGetDatum, elog, equal(), ereport, errcode(), errmsg(), ERROR, fastgetattr, GETSTRUCT, heap_close, heap_copytuple(), heap_open(), HeapTupleIsValid, NOTICE, ObjectIdGetDatum, RelationData::rd_att, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), simple_heap_update(), SnapshotNow, stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TextDatumGetCString, and val.

Referenced by AddRelationNewConstraints().

{
    bool        found;
    Relation    conDesc;
    SysScanDesc conscan;
    ScanKeyData skey[2];
    HeapTuple   tup;

    /* Search for a pg_constraint entry with same name and relation */
    conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);

    found = false;

    ScanKeyInit(&skey[0],
                Anum_pg_constraint_conname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(ccname));

    ScanKeyInit(&skey[1],
                Anum_pg_constraint_connamespace,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(RelationGetNamespace(rel)));

    conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
                                 SnapshotNow, 2, skey);

    while (HeapTupleIsValid(tup = systable_getnext(conscan)))
    {
        Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);

        if (con->conrelid == RelationGetRelid(rel))
        {
            /* Found it.  Conflicts if not identical check constraint */
            if (con->contype == CONSTRAINT_CHECK)
            {
                Datum       val;
                bool        isnull;

                val = fastgetattr(tup,
                                  Anum_pg_constraint_conbin,
                                  conDesc->rd_att, &isnull);
                if (isnull)
                    elog(ERROR, "null conbin for rel %s",
                         RelationGetRelationName(rel));
                if (equal(expr, stringToNode(TextDatumGetCString(val))))
                    found = true;
            }
            if (!found || !allow_merge)
                ereport(ERROR,
                        (errcode(ERRCODE_DUPLICATE_OBJECT),
                errmsg("constraint \"%s\" for relation \"%s\" already exists",
                       ccname, RelationGetRelationName(rel))));

            tup = heap_copytuple(tup);
            con = (Form_pg_constraint) GETSTRUCT(tup);

            /* If the constraint is "no inherit" then cannot merge */
            if (con->connoinherit)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
                                ccname, RelationGetRelationName(rel))));

            if (is_local)
                con->conislocal = true;
            else
                con->coninhcount++;
            if (is_no_inherit)
            {
                Assert(is_local);
                con->connoinherit = true;
            }
            /* OK to update the tuple */
            ereport(NOTICE,
               (errmsg("merging constraint \"%s\" with inherited definition",
                       ccname)));
            simple_heap_update(conDesc, &tup->t_self, tup);
            CatalogUpdateIndexes(conDesc, tup);
            break;
        }
    }

    systable_endscan(conscan);
    heap_close(conDesc, RowExclusiveLock);

    return found;
}

static void RelationRemoveInheritance ( Oid  relid  )  [static]
static void RelationTruncateIndexes ( Relation  heapRelation  )  [static]

Definition at line 2667 of file heap.c.

References AccessExclusiveLock, BuildIndexInfo(), index_build(), index_close(), index_open(), lfirst_oid, NoLock, RelationGetIndexList(), and RelationTruncate().

Referenced by heap_truncate_one_rel().

{
    ListCell   *indlist;

    /* Ask the relcache to produce a list of the indexes of the rel */
    foreach(indlist, RelationGetIndexList(heapRelation))
    {
        Oid         indexId = lfirst_oid(indlist);
        Relation    currentIndex;
        IndexInfo  *indexInfo;

        /* Open the index relation; use exclusive lock, just to be sure */
        currentIndex = index_open(indexId, AccessExclusiveLock);

        /* Fetch info needed for index_build */
        indexInfo = BuildIndexInfo(currentIndex);

        /*
         * Now truncate the actual file (and discard buffers).
         */
        RelationTruncate(currentIndex, 0);

        /* Initialize the index and rebuild */
        /* Note: we do not need to re-establish pkey setting */
        index_build(heapRelation, currentIndex, indexInfo, false, true);

        /* We're done with this index */
        index_close(currentIndex, NoLock);
    }
}

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 
)
static void SetRelationNumChecks ( Relation  rel,
int  numchecks 
) [static]

Definition at line 2456 of file heap.c.

References CacheInvalidateRelcache(), CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RelationGetRelid, RelationRelationId, RELOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.

Referenced by AddRelationNewConstraints(), and StoreConstraints().

{
    Relation    relrel;
    HeapTuple   reltup;
    Form_pg_class relStruct;

    relrel = heap_open(RelationRelationId, RowExclusiveLock);
    reltup = SearchSysCacheCopy1(RELOID,
                                 ObjectIdGetDatum(RelationGetRelid(rel)));
    if (!HeapTupleIsValid(reltup))
        elog(ERROR, "cache lookup failed for relation %u",
             RelationGetRelid(rel));
    relStruct = (Form_pg_class) GETSTRUCT(reltup);

    if (relStruct->relchecks != numchecks)
    {
        relStruct->relchecks = numchecks;

        simple_heap_update(relrel, &reltup->t_self, reltup);

        /* keep catalog indexes current */
        CatalogUpdateIndexes(relrel, reltup);
    }
    else
    {
        /* Skip the disk update, but force relcache inval anyway */
        CacheInvalidateRelcache(rel);
    }

    heap_freetuple(reltup);
    heap_close(relrel, RowExclusiveLock);
}

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);
}

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

Definition at line 2055 of file heap.c.

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

Referenced by heap_create_with_catalog().

{
    int         numchecks = 0;
    ListCell   *lc;

    if (!cooked_constraints)
        return;                 /* nothing to do */

    /*
     * Deparsing of constraint expressions will fail unless the just-created
     * pg_attribute tuples for this relation are made visible.  So, bump the
     * command counter.  CAUTION: this will cause a relcache entry rebuild.
     */
    CommandCounterIncrement();

    foreach(lc, cooked_constraints)
    {
        CookedConstraint *con = (CookedConstraint *) lfirst(lc);

        switch (con->contype)
        {
            case CONSTR_DEFAULT:
                StoreAttrDefault(rel, con->attnum, con->expr, is_internal);
                break;
            case CONSTR_CHECK:
                StoreRelCheck(rel, con->name, con->expr, !con->skip_validation,
                              con->is_local, con->inhcount,
                              con->is_no_inherit, is_internal);
                numchecks++;
                break;
            default:
                elog(ERROR, "unrecognized constraint type: %d",
                     (int) con->contype);
        }
    }

    if (numchecks > 0)
        SetRelationNumChecks(rel, numchecks);
}

static void StoreRelCheck ( Relation  rel,
char *  ccname,
Node expr,
bool  is_validated,
bool  is_local,
int  inhcount,
bool  is_no_inherit,
bool  is_internal 
) [static]

Definition at line 1953 of file heap.c.

References CONSTRAINT_CHECK, CreateConstraintEntry(), deparse_context_for(), deparse_expression(), i, InvalidOid, lfirst, list_length(), nodeToString(), NULL, palloc(), pfree(), pull_var_clause(), PVC_REJECT_AGGREGATES, PVC_REJECT_PLACEHOLDERS, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, and Var::varattno.

Referenced by AddRelationNewConstraints(), and StoreConstraints().

{
    char       *ccbin;
    char       *ccsrc;
    List       *varList;
    int         keycount;
    int16      *attNos;

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

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

    /*
     * Find columns of rel that are used in expr
     *
     * NB: pull_var_clause is okay here only because we don't allow subselects
     * in check constraints; it would fail to examine the contents of
     * subselects.
     */
    varList = pull_var_clause(expr,
                              PVC_REJECT_AGGREGATES,
                              PVC_REJECT_PLACEHOLDERS);
    keycount = list_length(varList);

    if (keycount > 0)
    {
        ListCell   *vl;
        int         i = 0;

        attNos = (int16 *) palloc(keycount * sizeof(int16));
        foreach(vl, varList)
        {
            Var        *var = (Var *) lfirst(vl);
            int         j;

            for (j = 0; j < i; j++)
                if (attNos[j] == var->varattno)
                    break;
            if (j == i)
                attNos[i++] = var->varattno;
        }
        keycount = i;
    }
    else
        attNos = NULL;

    /*
     * Create the Check Constraint
     */
    CreateConstraintEntry(ccname,       /* Constraint Name */
                          RelationGetNamespace(rel),    /* namespace */
                          CONSTRAINT_CHECK,     /* Constraint Type */
                          false,    /* Is Deferrable */
                          false,    /* Is Deferred */
                          is_validated,
                          RelationGetRelid(rel),        /* relation */
                          attNos,       /* attrs in the constraint */
                          keycount,     /* # attrs in the constraint */
                          InvalidOid,   /* not a domain constraint */
                          InvalidOid,   /* no associated index */
                          InvalidOid,   /* Foreign key fields */
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          0,
                          ' ',
                          ' ',
                          ' ',
                          NULL, /* not an exclusion constraint */
                          expr, /* Tree form of check constraint */
                          ccbin,    /* Binary form of check constraint */
                          ccsrc,    /* Source form of check constraint */
                          is_local,     /* conislocal */
                          inhcount,     /* coninhcount */
                          is_no_inherit,        /* connoinherit */
                          is_internal); /* internally constructed? */

    pfree(ccbin);
    pfree(ccsrc);
}

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];
}


Variable Documentation

Initial value:
 {
    0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
    MinTransactionIdAttributeNumber, 0, -1, -1,
    true, 'p', 'i', true, false, false, true, 0
}

Definition at line 146 of file heap.c.

Initial value:
 {
    0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
    MinCommandIdAttributeNumber, 0, -1, -1,
    true, 'p', 'i', true, false, false, true, 0
}

Definition at line 152 of file heap.c.

Initial value:
 {
    0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
    MaxTransactionIdAttributeNumber, 0, -1, -1,
    true, 'p', 'i', true, false, false, true, 0
}

Definition at line 158 of file heap.c.

Initial value:
 {
    0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
    MaxCommandIdAttributeNumber, 0, -1, -1,
    true, 'p', 'i', true, false, false, true, 0
}

Definition at line 164 of file heap.c.

Initial value:
 {
    0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
    TableOidAttributeNumber, 0, -1, -1,
    true, 'p', 'i', true, false, false, true, 0
}

Definition at line 176 of file heap.c.

Definition at line 77 of file heap.c.

Referenced by heap_create_with_catalog(), and set_next_heap_pg_class_oid().

const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7} [static]

Definition at line 182 of file heap.c.