Header And Logo

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

Functions

tablecmds.h File Reference

#include "access/htup.h"
#include "catalog/dependency.h"
#include "nodes/parsenodes.h"
#include "storage/lock.h"
#include "utils/relcache.h"
Include dependency graph for tablecmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

Oid DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId)
void RemoveRelations (DropStmt *drop)
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
void AlterTable (Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
LOCKMODE AlterTableGetLockLevel (List *cmds)
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
Oid AlterTableNamespace (AlterObjectSchemaStmt *stmt)
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
void CheckTableNotInUse (Relation rel, const char *stmt)
void ExecuteTruncate (TruncateStmt *stmt)
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
Oid renameatt (RenameStmt *stmt)
Oid RenameConstraint (RenameStmt *stmt)
Oid RenameRelation (RenameStmt *stmt)
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal)
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
void check_of_type (HeapTuple typetuple)
void register_on_commit_action (Oid relid, OnCommitAction action)
void remove_on_commit_action (Oid relid)
void PreCommit_on_commit_actions (void)
void AtEOXact_on_commit_actions (bool isCommit)
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)

Function Documentation

void AlterRelationNamespaceInternal ( Relation  classRel,
Oid  relOid,
Oid  oldNspOid,
Oid  newNspOid,
bool  hasDependEntry,
ObjectAddresses objsMoved 
)

Definition at line 9985 of file tablecmds.c.

References add_exact_object_address(), Assert, CatalogUpdateIndexes(), changeDependencyFor(), ObjectAddress::classId, elog, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_relname_relid(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, NamespaceRelationId, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, RelationRelationId, RELOID, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.

Referenced by AlterIndexNamespaces(), AlterSeqNamespaces(), AlterTableNamespaceInternal(), and AlterTypeNamespaceInternal().

{
    HeapTuple   classTup;
    Form_pg_class classForm;
    ObjectAddress   thisobj;

    classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
    if (!HeapTupleIsValid(classTup))
        elog(ERROR, "cache lookup failed for relation %u", relOid);
    classForm = (Form_pg_class) GETSTRUCT(classTup);

    Assert(classForm->relnamespace == oldNspOid);

    thisobj.classId = RelationRelationId;
    thisobj.objectId = relOid;
    thisobj.objectSubId = 0;

    /*
     * Do nothing when there's nothing to do.
     */
    if (!object_address_present(&thisobj, objsMoved))
    {
        /* check for duplicate name (more friendly than unique-index failure) */
        if (get_relname_relid(NameStr(classForm->relname),
                              newNspOid) != InvalidOid)
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_TABLE),
                     errmsg("relation \"%s\" already exists in schema \"%s\"",
                            NameStr(classForm->relname),
                            get_namespace_name(newNspOid))));

        /* classTup is a copy, so OK to scribble on */
        classForm->relnamespace = newNspOid;

        simple_heap_update(classRel, &classTup->t_self, classTup);
        CatalogUpdateIndexes(classRel, classTup);

        /* Update dependency on schema if caller said so */
        if (hasDependEntry &&
            changeDependencyFor(RelationRelationId, relOid,
                                NamespaceRelationId, oldNspOid, newNspOid) != 1)
            elog(ERROR, "failed to change schema dependency for relation \"%s\"",
                 NameStr(classForm->relname));

        add_exact_object_address(&thisobj, objsMoved);

        InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
    }

    heap_freetuple(classTup);
}

void AlterTable ( Oid  relid,
LOCKMODE  lockmode,
AlterTableStmt stmt 
)

Definition at line 2670 of file tablecmds.c.

References ATController(), CheckTableNotInUse(), AlterTableStmt::cmds, RangeVar::inhOpt, interpretInhOption(), NoLock, AlterTableStmt::relation, and relation_open().

Referenced by ProcessUtilitySlow().

{
    Relation    rel;

    /* Caller is required to provide an adequate lock. */
    rel = relation_open(relid, NoLock);

    CheckTableNotInUse(rel, "ALTER TABLE");

    ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
                 lockmode);
}

LOCKMODE AlterTableGetLockLevel ( List cmds  ) 

Definition at line 2727 of file tablecmds.c.

References AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AddOids, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_ChangeOwner, AT_ClusterOn, AT_ColumnDefault, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_GenericOptions, AT_ProcessedConstraint, AT_ReAddConstraint, AT_ReplaceRelOptions, AT_ResetOptions, AT_ResetRelOptions, AT_SetNotNull, AT_SetOptions, AT_SetRelOptions, AT_SetStatistics, AT_SetStorage, AT_SetTableSpace, AT_ValidateConstraint, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, AlterTableCmd::def, elog, ERROR, IsA, lfirst, and AlterTableCmd::subtype.

Referenced by AlterTableInternal(), ProcessUtilitySlow(), and transformAlterTableStmt().

{
    /*
     * Late in 9.1 dev cycle a number of issues were uncovered with access to
     * catalog relations, leading to the decision to re-enforce all DDL at
     * AccessExclusiveLock level by default.
     *
     * The issues are that there is a pervasive assumption in the code that
     * the catalogs will not be read unless an AccessExclusiveLock is held. If
     * that rule is relaxed, we must protect against a number of potential
     * effects - infrequent, but proven possible with test cases where
     * multiple DDL operations occur in a stream against frequently accessed
     * tables.
     *
     * 1. Catalog tables are read using SnapshotNow, which has a race bug that
     * allows a scan to return no valid rows even when one is present in the
     * case of a commit of a concurrent update of the catalog table.
     * SnapshotNow also ignores transactions in progress, so takes the latest
     * committed version without waiting for the latest changes.
     *
     * 2. Relcache needs to be internally consistent, so unless we lock the
     * definition during reads we have no way to guarantee that.
     *
     * 3. Catcache access isn't coordinated at all so refreshes can occur at
     * any time.
     */
#ifdef REDUCED_ALTER_TABLE_LOCK_LEVELS
    ListCell   *lcmd;
    LOCKMODE    lockmode = ShareUpdateExclusiveLock;

    foreach(lcmd, cmds)
    {
        AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
        LOCKMODE    cmd_lockmode = AccessExclusiveLock; /* default for compiler */

        switch (cmd->subtype)
        {
                /*
                 * Need AccessExclusiveLock for these subcommands because they
                 * affect or potentially affect both read and write
                 * operations.
                 *
                 * New subcommand types should be added here by default.
                 */
            case AT_AddColumn:  /* may rewrite heap, in some cases and visible
                                 * to SELECT */
            case AT_DropColumn: /* change visible to SELECT */
            case AT_AddColumnToView:    /* CREATE VIEW */
            case AT_AlterColumnType:    /* must rewrite heap */
            case AT_DropConstraint:     /* as DROP INDEX */
            case AT_AddOids:    /* must rewrite heap */
            case AT_DropOids:   /* calls AT_DropColumn */
            case AT_EnableAlwaysRule:   /* may change SELECT rules */
            case AT_EnableReplicaRule:  /* may change SELECT rules */
            case AT_EnableRule: /* may change SELECT rules */
            case AT_DisableRule:        /* may change SELECT rules */
            case AT_ChangeOwner:        /* change visible to SELECT */
            case AT_SetTableSpace:      /* must rewrite heap */
            case AT_DropNotNull:        /* may change some SQL plans */
            case AT_SetNotNull:
            case AT_GenericOptions:
            case AT_AlterColumnGenericOptions:
                cmd_lockmode = AccessExclusiveLock;
                break;

                /*
                 * These subcommands affect write operations only.
                 */
            case AT_ColumnDefault:
            case AT_ProcessedConstraint:        /* becomes AT_AddConstraint */
            case AT_AddConstraintRecurse:       /* becomes AT_AddConstraint */
            case AT_ReAddConstraint:            /* becomes AT_AddConstraint */
            case AT_EnableTrig:
            case AT_EnableAlwaysTrig:
            case AT_EnableReplicaTrig:
            case AT_EnableTrigAll:
            case AT_EnableTrigUser:
            case AT_DisableTrig:
            case AT_DisableTrigAll:
            case AT_DisableTrigUser:
            case AT_AddIndex:   /* from ADD CONSTRAINT */
            case AT_AddIndexConstraint:
                cmd_lockmode = ShareRowExclusiveLock;
                break;

            case AT_AddConstraint:
                if (IsA(cmd->def, Constraint))
                {
                    Constraint *con = (Constraint *) cmd->def;

                    switch (con->contype)
                    {
                        case CONSTR_EXCLUSION:
                        case CONSTR_PRIMARY:
                        case CONSTR_UNIQUE:

                            /*
                             * Cases essentially the same as CREATE INDEX. We
                             * could reduce the lock strength to ShareLock if
                             * we can work out how to allow concurrent catalog
                             * updates.
                             */
                            cmd_lockmode = ShareRowExclusiveLock;
                            break;
                        case CONSTR_FOREIGN:

                            /*
                             * We add triggers to both tables when we add a
                             * Foreign Key, so the lock level must be at least
                             * as strong as CREATE TRIGGER.
                             */
                            cmd_lockmode = ShareRowExclusiveLock;
                            break;

                        default:
                            cmd_lockmode = ShareRowExclusiveLock;
                    }
                }
                break;

                /*
                 * These subcommands affect inheritance behaviour. Queries
                 * started before us will continue to see the old inheritance
                 * behaviour, while queries started after we commit will see
                 * new behaviour. No need to prevent reads or writes to the
                 * subtable while we hook it up though.
                 */
            case AT_AddInherit:
            case AT_DropInherit:
                cmd_lockmode = ShareUpdateExclusiveLock;
                break;

                /*
                 * These subcommands affect implicit row type conversion. They
                 * have affects similar to CREATE/DROP CAST on queries.  We
                 * don't provide for invalidating parse trees as a result of
                 * such changes.  Do avoid concurrent pg_class updates,
                 * though.
                 */
            case AT_AddOf:
            case AT_DropOf:
                cmd_lockmode = ShareUpdateExclusiveLock;

                /*
                 * These subcommands affect general strategies for performance
                 * and maintenance, though don't change the semantic results
                 * from normal data reads and writes. Delaying an ALTER TABLE
                 * behind currently active writes only delays the point where
                 * the new strategy begins to take effect, so there is no
                 * benefit in waiting. In this case the minimum restriction
                 * applies: we don't currently allow concurrent catalog
                 * updates.
                 */
            case AT_SetStatistics:
            case AT_ClusterOn:
            case AT_DropCluster:
            case AT_SetRelOptions:
            case AT_ResetRelOptions:
            case AT_ReplaceRelOptions:
            case AT_SetOptions:
            case AT_ResetOptions:
            case AT_SetStorage:
            case AT_ValidateConstraint:
                cmd_lockmode = ShareUpdateExclusiveLock;
                break;

            default:            /* oops */
                elog(ERROR, "unrecognized alter table type: %d",
                     (int) cmd->subtype);
                break;
        }

        /*
         * Take the greatest lockmode from any subcommand
         */
        if (cmd_lockmode > lockmode)
            lockmode = cmd_lockmode;
    }
#else
    LOCKMODE    lockmode = AccessExclusiveLock;
#endif

    return lockmode;
}

void AlterTableInternal ( Oid  relid,
List cmds,
bool  recurse 
)

Definition at line 2695 of file tablecmds.c.

References AlterTableGetLockLevel(), ATController(), and relation_open().

Referenced by DefineVirtualRelation(), and index_check_primary_key().

{
    Relation    rel;
    LOCKMODE    lockmode = AlterTableGetLockLevel(cmds);

    rel = relation_open(relid, lockmode);

    ATController(rel, cmds, recurse, lockmode);
}

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)
Oid AlterTableNamespace ( AlterObjectSchemaStmt stmt  ) 

Definition at line 9884 of file tablecmds.c.

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_rel_name(), makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), NoLock, NOTICE, NULL, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RelationRelationId, RELKIND_SEQUENCE, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

{
    Relation    rel;
    Oid         relid;
    Oid         oldNspOid;
    Oid         nspOid;
    RangeVar   *newrv;
    ObjectAddresses *objsMoved;

    relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
                                     stmt->missing_ok, false,
                                     RangeVarCallbackForAlterRelation,
                                     (void *) stmt);

    if (!OidIsValid(relid))
    {
        ereport(NOTICE,
                (errmsg("relation \"%s\" does not exist, skipping",
                        stmt->relation->relname)));
        return InvalidOid;
    }

    rel = relation_open(relid, NoLock);

    oldNspOid = RelationGetNamespace(rel);

    /* If it's an owned sequence, disallow moving it by itself. */
    if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
    {
        Oid         tableId;
        int32       colId;

        if (sequenceIsOwned(relid, &tableId, &colId))
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("cannot move an owned sequence into another schema"),
                     errdetail("Sequence \"%s\" is linked to table \"%s\".",
                               RelationGetRelationName(rel),
                               get_rel_name(tableId))));
    }

    /* Get and lock schema OID and check its permissions. */
    newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
    nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);

    /* common checks on switching namespaces */
    CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid);

    objsMoved = new_object_addresses();
    AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
    free_object_addresses(objsMoved);

    /* close rel, but keep lock until commit */
    relation_close(rel, NoLock);

    return relid;
}

void AlterTableNamespaceInternal ( Relation  rel,
Oid  oldNspOid,
Oid  nspOid,
ObjectAddresses objsMoved 
)

Definition at line 9948 of file tablecmds.c.

References AccessExclusiveLock, AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterSeqNamespaces(), AlterTypeNamespaceInternal(), Assert, heap_close, heap_open(), NULL, RelationData::rd_rel, RelationGetRelid, RelationRelationId, RELKIND_MATVIEW, RELKIND_RELATION, and RowExclusiveLock.

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

{
    Relation    classRel;

    Assert(objsMoved != NULL);

    /* OK, modify the pg_class row and pg_depend entry */
    classRel = heap_open(RelationRelationId, RowExclusiveLock);

    AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
                                   nspOid, true, objsMoved);

    /* Fix the table's row type too */
    AlterTypeNamespaceInternal(rel->rd_rel->reltype,
                               nspOid, false, false, objsMoved);

    /* Fix other dependent stuff */
    if (rel->rd_rel->relkind == RELKIND_RELATION ||
        rel->rd_rel->relkind == RELKIND_MATVIEW)
    {
        AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
        AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
                           objsMoved, AccessExclusiveLock);
        AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
                                  false, objsMoved);
    }

    heap_close(classRel, RowExclusiveLock);
}

void AtEOSubXact_on_commit_actions ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 10342 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, lfirst, list_delete_cell(), list_head(), lnext, NULL, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

{
    ListCell   *cur_item;
    ListCell   *prev_item;

    prev_item = NULL;
    cur_item = list_head(on_commits);

    while (cur_item != NULL)
    {
        OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);

        if (!isCommit && oc->creating_subid == mySubid)
        {
            /* cur_item must be removed */
            on_commits = list_delete_cell(on_commits, cur_item, prev_item);
            pfree(oc);
            if (prev_item)
                cur_item = lnext(prev_item);
            else
                cur_item = list_head(on_commits);
        }
        else
        {
            /* cur_item must be preserved */
            if (oc->creating_subid == mySubid)
                oc->creating_subid = parentSubid;
            if (oc->deleting_subid == mySubid)
                oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
            prev_item = cur_item;
            cur_item = lnext(prev_item);
        }
    }
}

void AtEOXact_on_commit_actions ( bool  isCommit  ) 

Definition at line 10300 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, InvalidSubTransactionId, lfirst, list_delete_cell(), list_head(), lnext, NULL, and pfree().

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

{
    ListCell   *cur_item;
    ListCell   *prev_item;

    prev_item = NULL;
    cur_item = list_head(on_commits);

    while (cur_item != NULL)
    {
        OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);

        if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
            oc->creating_subid != InvalidSubTransactionId)
        {
            /* cur_item must be removed */
            on_commits = list_delete_cell(on_commits, cur_item, prev_item);
            pfree(oc);
            if (prev_item)
                cur_item = lnext(prev_item);
            else
                cur_item = list_head(on_commits);
        }
        else
        {
            /* cur_item must be preserved */
            oc->creating_subid = InvalidSubTransactionId;
            oc->deleting_subid = InvalidSubTransactionId;
            prev_item = cur_item;
            cur_item = lnext(prev_item);
        }
    }
}

void ATExecChangeOwner ( Oid  relationOid,
Oid  newOwnerId,
bool  recursing,
LOCKMODE  lockmode 
)

Definition at line 8134 of file tablecmds.c.

References ACL_CREATE, ACL_KIND_CLASS, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), Anum_pg_class_relacl, Anum_pg_class_relowner, ATExecChangeOwner(), CatalogUpdateIndexes(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_is_member_of_role(), DatumGetAclP, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, get_namespace_name(), get_rel_name(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst_oid, list_free(), NameStr, NoLock, ObjectIdGetDatum, pg_class_ownercheck(), pg_namespace_aclcheck(), PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, RelationRelationId, ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, RELKIND_VIEW, RELOID, RowExclusiveLock, SearchSysCache1, sequenceIsOwned(), simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and WARNING.

Referenced by AlterTypeOwner(), ATExecChangeOwner(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned().

{
    Relation    target_rel;
    Relation    class_rel;
    HeapTuple   tuple;
    Form_pg_class tuple_class;

    /*
     * Get exclusive lock till end of transaction on the target table. Use
     * relation_open so that we can work on indexes and sequences.
     */
    target_rel = relation_open(relationOid, lockmode);

    /* Get its pg_class tuple, too */
    class_rel = heap_open(RelationRelationId, RowExclusiveLock);

    tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for relation %u", relationOid);
    tuple_class = (Form_pg_class) GETSTRUCT(tuple);

    /* Can we change the ownership of this tuple? */
    switch (tuple_class->relkind)
    {
        case RELKIND_RELATION:
        case RELKIND_VIEW:
        case RELKIND_MATVIEW:
        case RELKIND_FOREIGN_TABLE:
            /* ok to change owner */
            break;
        case RELKIND_INDEX:
            if (!recursing)
            {
                /*
                 * Because ALTER INDEX OWNER used to be allowed, and in fact
                 * is generated by old versions of pg_dump, we give a warning
                 * and do nothing rather than erroring out.  Also, to avoid
                 * unnecessary chatter while restoring those old dumps, say
                 * nothing at all if the command would be a no-op anyway.
                 */
                if (tuple_class->relowner != newOwnerId)
                    ereport(WARNING,
                            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                             errmsg("cannot change owner of index \"%s\"",
                                    NameStr(tuple_class->relname)),
                             errhint("Change the ownership of the index's table, instead.")));
                /* quick hack to exit via the no-op path */
                newOwnerId = tuple_class->relowner;
            }
            break;
        case RELKIND_SEQUENCE:
            if (!recursing &&
                tuple_class->relowner != newOwnerId)
            {
                /* if it's an owned sequence, disallow changing it by itself */
                Oid         tableId;
                int32       colId;

                if (sequenceIsOwned(relationOid, &tableId, &colId))
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("cannot change owner of sequence \"%s\"",
                                    NameStr(tuple_class->relname)),
                      errdetail("Sequence \"%s\" is linked to table \"%s\".",
                                NameStr(tuple_class->relname),
                                get_rel_name(tableId))));
            }
            break;
        case RELKIND_COMPOSITE_TYPE:
            if (recursing)
                break;
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("\"%s\" is a composite type",
                            NameStr(tuple_class->relname)),
                     errhint("Use ALTER TYPE instead.")));
            break;
        case RELKIND_TOASTVALUE:
            if (recursing)
                break;
            /* FALL THRU */
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
            errmsg("\"%s\" is not a table, view, sequence, or foreign table",
                   NameStr(tuple_class->relname))));
    }

    /*
     * If the new owner is the same as the existing owner, consider the
     * command to have succeeded.  This is for dump restoration purposes.
     */
    if (tuple_class->relowner != newOwnerId)
    {
        Datum       repl_val[Natts_pg_class];
        bool        repl_null[Natts_pg_class];
        bool        repl_repl[Natts_pg_class];
        Acl        *newAcl;
        Datum       aclDatum;
        bool        isNull;
        HeapTuple   newtuple;

        /* skip permission checks when recursing to index or toast table */
        if (!recursing)
        {
            /* Superusers can always do it */
            if (!superuser())
            {
                Oid         namespaceOid = tuple_class->relnamespace;
                AclResult   aclresult;

                /* Otherwise, must be owner of the existing object */
                if (!pg_class_ownercheck(relationOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
                                   RelationGetRelationName(target_rel));

                /* Must be able to become new owner */
                check_is_member_of_role(GetUserId(), newOwnerId);

                /* New owner must have CREATE privilege on namespace */
                aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
                                                  ACL_CREATE);
                if (aclresult != ACLCHECK_OK)
                    aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                   get_namespace_name(namespaceOid));
            }
        }

        memset(repl_null, false, sizeof(repl_null));
        memset(repl_repl, false, sizeof(repl_repl));

        repl_repl[Anum_pg_class_relowner - 1] = true;
        repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);

        /*
         * Determine the modified ACL for the new owner.  This is only
         * necessary when the ACL is non-null.
         */
        aclDatum = SysCacheGetAttr(RELOID, tuple,
                                   Anum_pg_class_relacl,
                                   &isNull);
        if (!isNull)
        {
            newAcl = aclnewowner(DatumGetAclP(aclDatum),
                                 tuple_class->relowner, newOwnerId);
            repl_repl[Anum_pg_class_relacl - 1] = true;
            repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
        }

        newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);

        simple_heap_update(class_rel, &newtuple->t_self, newtuple);
        CatalogUpdateIndexes(class_rel, newtuple);

        heap_freetuple(newtuple);

        /*
         * We must similarly update any per-column ACLs to reflect the new
         * owner; for neatness reasons that's split out as a subroutine.
         */
        change_owner_fix_column_acls(relationOid,
                                     tuple_class->relowner,
                                     newOwnerId);

        /*
         * Update owner dependency reference, if any.  A composite type has
         * none, because it's tracked for the pg_type entry instead of here;
         * indexes and TOAST tables don't have their own entries either.
         */
        if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
            tuple_class->relkind != RELKIND_INDEX &&
            tuple_class->relkind != RELKIND_TOASTVALUE)
            changeDependencyOnOwner(RelationRelationId, relationOid,
                                    newOwnerId);

        /*
         * Also change the ownership of the table's row type, if it has one
         */
        if (tuple_class->relkind != RELKIND_INDEX)
            AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId,
                             tuple_class->relkind == RELKIND_COMPOSITE_TYPE);

        /*
         * If we are operating on a table or materialized view, also change
         * the ownership of any indexes and sequences that belong to the
         * relation, as well as its toast table (if it has one).
         */
        if (tuple_class->relkind == RELKIND_RELATION ||
            tuple_class->relkind == RELKIND_MATVIEW ||
            tuple_class->relkind == RELKIND_TOASTVALUE)
        {
            List       *index_oid_list;
            ListCell   *i;

            /* Find all the indexes belonging to this relation */
            index_oid_list = RelationGetIndexList(target_rel);

            /* For each index, recursively change its ownership */
            foreach(i, index_oid_list)
                ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);

            list_free(index_oid_list);
        }

        if (tuple_class->relkind == RELKIND_RELATION ||
            tuple_class->relkind == RELKIND_MATVIEW)
        {
            /* If it has a toast table, recurse to change its ownership */
            if (tuple_class->reltoastrelid != InvalidOid)
                ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
                                  true, lockmode);

            /* If it has dependent sequences, recurse to change them too */
            change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
        }
    }

    InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);

    ReleaseSysCache(tuple);
    heap_close(class_rel, RowExclusiveLock);
    relation_close(target_rel, NoLock);
}

void check_of_type ( HeapTuple  typetuple  ) 

Definition at line 4301 of file tablecmds.c.

References AccessShareLock, Assert, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, HeapTupleGetOid, NoLock, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), and TYPTYPE_COMPOSITE.

Referenced by ATExecAddOf(), and transformOfType().

{
    Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
    bool        typeOk = false;

    if (typ->typtype == TYPTYPE_COMPOSITE)
    {
        Relation    typeRelation;

        Assert(OidIsValid(typ->typrelid));
        typeRelation = relation_open(typ->typrelid, AccessShareLock);
        typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);

        /*
         * Close the parent rel, but keep our AccessShareLock on it until xact
         * commit.  That will prevent someone else from deleting or ALTERing
         * the type before the typed table creation/conversion commits.
         */
        relation_close(typeRelation, NoLock);
    }
    if (!typeOk)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("type %s is not a composite type",
                        format_type_be(HeapTupleGetOid(typetuple)))));
}

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 2589 of file tablecmds.c.

References AfterTriggerPendingOnRel(), ereport, errcode(), errmsg(), ERROR, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, and RELKIND_INDEX.

Referenced by AlterTable(), ATAddCheckConstraint(), ATExecAddColumn(), ATExecDropColumn(), ATExecDropConstraint(), ATSimpleRecursion(), ATTypedTableRecursion(), cluster_rel(), DefineVirtualRelation(), ExecRefreshMatView(), heap_drop_with_catalog(), index_drop(), reindex_index(), and truncate_check_rel().

{
    int         expected_refcnt;

    expected_refcnt = rel->rd_isnailed ? 2 : 1;
    if (rel->rd_refcnt != expected_refcnt)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_IN_USE),
        /* translator: first %s is a SQL command, eg ALTER TABLE */
                 errmsg("cannot %s \"%s\" because "
                        "it is being used by active queries in this session",
                        stmt, RelationGetRelationName(rel))));

    if (rel->rd_rel->relkind != RELKIND_INDEX &&
        AfterTriggerPendingOnRel(RelationGetRelid(rel)))
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_IN_USE),
        /* translator: first %s is a SQL command, eg ALTER TABLE */
                 errmsg("cannot %s \"%s\" because "
                        "it has pending trigger events",
                        stmt, RelationGetRelationName(rel))));
}

Oid DefineRelation ( CreateStmt stmt,
char  relkind,
Oid  ownerId 
)

Definition at line 429 of file tablecmds.c.

References AccessExclusiveLock, ACL_CREATE, ACL_KIND_TABLESPACE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, AddRelationNewConstraints(), allowSystemTableMods, Assert, CookedConstraint::attnum, RawColumnDefault::attnum, tupleDesc::attrs, BuildDescForRelation(), CommandCounterIncrement(), CreateStmt::constraints, CookedConstraint::contype, ColumnDef::cooked_default, ereport, errcode(), errmsg(), ERROR, CookedConstraint::expr, get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), GetUserId(), GLOBALTABLESPACE_OID, heap_create_with_catalog(), heap_reloptions(), CookedConstraint::inhcount, CreateStmt::inhRelations, InSecurityRestrictedOperation(), interpretOidsOption(), InvalidOid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lfirst, list_concat(), MergeAttributes(), MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, NULL, CreateStmt::ofTypename, OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, palloc(), pg_tablespace_aclcheck(), pg_type_aclcheck(), RangeVarGetAndCheckCreationNamespace(), RawColumnDefault::raw_default, ColumnDef::raw_default, CreateStmt::relation, relation_close(), relation_open(), RELKIND_FOREIGN_TABLE, RELKIND_RELATION, RangeVar::relname, RangeVar::relpersistence, RELPERSISTENCE_TEMP, CookedConstraint::skip_validation, StoreCatalogInheritance(), StrNCpy, CreateStmt::tableElts, CreateStmt::tablespacename, tupleDesc::tdhasoid, transformRelOptions(), and typenameTypeId().

Referenced by DefineCompositeType(), DefineSequence(), DefineVirtualRelation(), intorel_startup(), and ProcessUtilitySlow().

{
    char        relname[NAMEDATALEN];
    Oid         namespaceId;
    List       *schema = stmt->tableElts;
    Oid         relationId;
    Oid         tablespaceId;
    Relation    rel;
    TupleDesc   descriptor;
    List       *inheritOids;
    List       *old_constraints;
    bool        localHasOids;
    int         parentOidCount;
    List       *rawDefaults;
    List       *cookedDefaults;
    Datum       reloptions;
    ListCell   *listptr;
    AttrNumber  attnum;
    static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
    Oid         ofTypeId;

    /*
     * Truncate relname to appropriate length (probably a waste of time, as
     * parser should have done this already).
     */
    StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);

    /*
     * Check consistency of arguments
     */
    if (stmt->oncommit != ONCOMMIT_NOOP
        && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("ON COMMIT can only be used on temporary tables")));
    if (stmt->constraints != NIL && relkind == RELKIND_FOREIGN_TABLE)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("constraints are not supported on foreign tables")));

    /*
     * Look up the namespace in which we are supposed to create the relation,
     * check we have permission to create there, lock it against concurrent
     * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
     * namespace is selected.
     */
    namespaceId =
        RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);

    /*
     * Security check: disallow creating temp tables from security-restricted
     * code.  This is needed because calling code might not expect untrusted
     * tables to appear in pg_temp at the front of its search path.
     */
    if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
        && InSecurityRestrictedOperation())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("cannot create temporary table within security-restricted operation")));

    /*
     * Select tablespace to use.  If not specified, use default tablespace
     * (which may in turn default to database's default).
     */
    if (stmt->tablespacename)
    {
        tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
    }
    else
    {
        tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
        /* note InvalidOid is OK in this case */
    }

    /* Check permissions except when using database's default */
    if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
    {
        AclResult   aclresult;

        aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
                                           ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
                           get_tablespace_name(tablespaceId));
    }

    /* In all cases disallow placing user relations in pg_global */
    if (tablespaceId == GLOBALTABLESPACE_OID)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("only shared relations can be placed in pg_global tablespace")));

    /* Identify user ID that will own the table */
    if (!OidIsValid(ownerId))
        ownerId = GetUserId();

    /*
     * Parse and validate reloptions, if any.
     */
    reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
                                     true, false);

    (void) heap_reloptions(relkind, reloptions, true);

    if (stmt->ofTypename)
    {
        AclResult   aclresult;

        ofTypeId = typenameTypeId(NULL, stmt->ofTypename);

        aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error_type(aclresult, ofTypeId);
    }
    else
        ofTypeId = InvalidOid;

    /*
     * Look up inheritance ancestors and generate relation schema, including
     * inherited attributes.
     */
    schema = MergeAttributes(schema, stmt->inhRelations,
                             stmt->relation->relpersistence,
                             &inheritOids, &old_constraints, &parentOidCount);

    /*
     * Create a tuple descriptor from the relation schema.  Note that this
     * deals with column names, types, and NOT NULL constraints, but not
     * default values or CHECK constraints; we handle those below.
     */
    descriptor = BuildDescForRelation(schema);

    localHasOids = interpretOidsOption(stmt->options,
                                       (relkind == RELKIND_RELATION ||
                                        relkind == RELKIND_FOREIGN_TABLE));
    descriptor->tdhasoid = (localHasOids || parentOidCount > 0);

    /*
     * Find columns with default values and prepare for insertion of the
     * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
     * CookedConstraint structs that we'll pass to heap_create_with_catalog,
     * while raw defaults go into a list of RawColumnDefault structs that will
     * be processed by AddRelationNewConstraints.  (We can't deal with raw
     * expressions until we can do transformExpr.)
     *
     * We can set the atthasdef flags now in the tuple descriptor; this just
     * saves StoreAttrDefault from having to do an immediate update of the
     * pg_attribute rows.
     */
    rawDefaults = NIL;
    cookedDefaults = NIL;
    attnum = 0;

    foreach(listptr, schema)
    {
        ColumnDef  *colDef = lfirst(listptr);

        attnum++;

        if (colDef->raw_default != NULL)
        {
            RawColumnDefault *rawEnt;

            Assert(colDef->cooked_default == NULL);

            rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
            rawEnt->attnum = attnum;
            rawEnt->raw_default = colDef->raw_default;
            rawDefaults = lappend(rawDefaults, rawEnt);
            descriptor->attrs[attnum - 1]->atthasdef = true;
        }
        else if (colDef->cooked_default != NULL)
        {
            CookedConstraint *cooked;

            cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
            cooked->contype = CONSTR_DEFAULT;
            cooked->name = NULL;
            cooked->attnum = attnum;
            cooked->expr = colDef->cooked_default;
            cooked->skip_validation = false;
            cooked->is_local = true;    /* not used for defaults */
            cooked->inhcount = 0;       /* ditto */
            cooked->is_no_inherit = false;
            cookedDefaults = lappend(cookedDefaults, cooked);
            descriptor->attrs[attnum - 1]->atthasdef = true;
        }
    }

    /*
     * Create the relation.  Inherited defaults and constraints are passed in
     * for immediate handling --- since they don't need parsing, they can be
     * stored immediately.
     */
    relationId = heap_create_with_catalog(relname,
                                          namespaceId,
                                          tablespaceId,
                                          InvalidOid,
                                          InvalidOid,
                                          ofTypeId,
                                          ownerId,
                                          descriptor,
                                          list_concat(cookedDefaults,
                                                      old_constraints),
                                          relkind,
                                          stmt->relation->relpersistence,
                                          false,
                                          false,
                                          localHasOids,
                                          parentOidCount,
                                          stmt->oncommit,
                                          reloptions,
                                          true,
                                          allowSystemTableMods,
                                          false);

    /* Store inheritance information for new rel. */
    StoreCatalogInheritance(relationId, inheritOids);

    /*
     * We must bump the command counter to make the newly-created relation
     * tuple visible for opening.
     */
    CommandCounterIncrement();

    /*
     * Open the new relation and acquire exclusive lock on it.  This isn't
     * really necessary for locking out other backends (since they can't see
     * the new rel anyway until we commit), but it keeps the lock manager from
     * complaining about deadlock risks.
     */
    rel = relation_open(relationId, AccessExclusiveLock);

    /*
     * Now add any newly specified column default values and CHECK constraints
     * to the new relation.  These are passed to us in the form of raw
     * parsetrees; we need to transform them to executable expression trees
     * before they can be added. The most convenient way to do that is to
     * apply the parser's transformExpr routine, but transformExpr doesn't
     * work unless we have a pre-existing relation. So, the transformation has
     * to be postponed to this final step of CREATE TABLE.
     */
    if (rawDefaults || stmt->constraints)
        AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
                                  true, true, false);

    /*
     * Clean up.  We keep lock on new relation (although it shouldn't be
     * visible to anyone else anyway, until commit).
     */
    relation_close(rel, NoLock);

    return relationId;
}

void ExecuteTruncate ( TruncateStmt stmt  ) 

Definition at line 945 of file tablecmds.c.

References AccessExclusiveLock, ACL_KIND_CLASS, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), TruncateStmt::behavior, CheckTableForSerializableConflictIn(), CreateExecutorState(), DROP_CASCADE, DROP_RESTRICT, ereport, errmsg(), EState::es_num_result_relations, EState::es_result_relation_info, EState::es_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), find_all_inheritors(), FreeExecutorState(), GetCurrentSubTransactionId(), GetOldestMultiXactId(), getOwnedSequences(), GetUserId(), heap_close, heap_create_init_fork(), heap_open(), heap_openrv(), heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), RangeVar::inhOpt, InitResultRelInfo(), interpretInhOption(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_length(), list_member_oid(), NIL, NoLock, NOTICE, NULL, OidIsValid, palloc(), pg_class_ownercheck(), RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_rel, RecentXmin, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, TruncateStmt::relations, RelationSetNewRelfilenode(), RELPERSISTENCE_UNLOGGED, ResetSequence(), TruncateStmt::restart_seqs, and truncate_check_rel().

Referenced by standard_ProcessUtility().

{
    List       *rels = NIL;
    List       *relids = NIL;
    List       *seq_relids = NIL;
    EState     *estate;
    ResultRelInfo *resultRelInfos;
    ResultRelInfo *resultRelInfo;
    SubTransactionId mySubid;
    ListCell   *cell;

    /*
     * Open, exclusive-lock, and check all the explicitly-specified relations
     */
    foreach(cell, stmt->relations)
    {
        RangeVar   *rv = lfirst(cell);
        Relation    rel;
        bool        recurse = interpretInhOption(rv->inhOpt);
        Oid         myrelid;

        rel = heap_openrv(rv, AccessExclusiveLock);
        myrelid = RelationGetRelid(rel);
        /* don't throw error for "TRUNCATE foo, foo" */
        if (list_member_oid(relids, myrelid))
        {
            heap_close(rel, AccessExclusiveLock);
            continue;
        }
        truncate_check_rel(rel);
        rels = lappend(rels, rel);
        relids = lappend_oid(relids, myrelid);

        if (recurse)
        {
            ListCell   *child;
            List       *children;

            children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL);

            foreach(child, children)
            {
                Oid         childrelid = lfirst_oid(child);

                if (list_member_oid(relids, childrelid))
                    continue;

                /* find_all_inheritors already got lock */
                rel = heap_open(childrelid, NoLock);
                truncate_check_rel(rel);
                rels = lappend(rels, rel);
                relids = lappend_oid(relids, childrelid);
            }
        }
    }

    /*
     * In CASCADE mode, suck in all referencing relations as well.  This
     * requires multiple iterations to find indirectly-dependent relations. At
     * each phase, we need to exclusive-lock new rels before looking for their
     * dependencies, else we might miss something.  Also, we check each rel as
     * soon as we open it, to avoid a faux pas such as holding lock for a long
     * time on a rel we have no permissions for.
     */
    if (stmt->behavior == DROP_CASCADE)
    {
        for (;;)
        {
            List       *newrelids;

            newrelids = heap_truncate_find_FKs(relids);
            if (newrelids == NIL)
                break;          /* nothing else to add */

            foreach(cell, newrelids)
            {
                Oid         relid = lfirst_oid(cell);
                Relation    rel;

                rel = heap_open(relid, AccessExclusiveLock);
                ereport(NOTICE,
                        (errmsg("truncate cascades to table \"%s\"",
                                RelationGetRelationName(rel))));
                truncate_check_rel(rel);
                rels = lappend(rels, rel);
                relids = lappend_oid(relids, relid);
            }
        }
    }

    /*
     * Check foreign key references.  In CASCADE mode, this should be
     * unnecessary since we just pulled in all the references; but as a
     * cross-check, do it anyway if in an Assert-enabled build.
     */
#ifdef USE_ASSERT_CHECKING
    heap_truncate_check_FKs(rels, false);
#else
    if (stmt->behavior == DROP_RESTRICT)
        heap_truncate_check_FKs(rels, false);
#endif

    /*
     * If we are asked to restart sequences, find all the sequences, lock them
     * (we need AccessExclusiveLock for ResetSequence), and check permissions.
     * We want to do this early since it's pointless to do all the truncation
     * work only to fail on sequence permissions.
     */
    if (stmt->restart_seqs)
    {
        foreach(cell, rels)
        {
            Relation    rel = (Relation) lfirst(cell);
            List       *seqlist = getOwnedSequences(RelationGetRelid(rel));
            ListCell   *seqcell;

            foreach(seqcell, seqlist)
            {
                Oid         seq_relid = lfirst_oid(seqcell);
                Relation    seq_rel;

                seq_rel = relation_open(seq_relid, AccessExclusiveLock);

                /* This check must match AlterSequence! */
                if (!pg_class_ownercheck(seq_relid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
                                   RelationGetRelationName(seq_rel));

                seq_relids = lappend_oid(seq_relids, seq_relid);

                relation_close(seq_rel, NoLock);
            }
        }
    }

    /* Prepare to catch AFTER triggers. */
    AfterTriggerBeginQuery();

    /*
     * To fire triggers, we'll need an EState as well as a ResultRelInfo for
     * each relation.  We don't need to call ExecOpenIndices, though.
     */
    estate = CreateExecutorState();
    resultRelInfos = (ResultRelInfo *)
        palloc(list_length(rels) * sizeof(ResultRelInfo));
    resultRelInfo = resultRelInfos;
    foreach(cell, rels)
    {
        Relation    rel = (Relation) lfirst(cell);

        InitResultRelInfo(resultRelInfo,
                          rel,
                          0,    /* dummy rangetable index */
                          0);
        resultRelInfo++;
    }
    estate->es_result_relations = resultRelInfos;
    estate->es_num_result_relations = list_length(rels);

    /*
     * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
     * truncating (this is because one of them might throw an error). Also, if
     * we were to allow them to prevent statement execution, that would need
     * to be handled here.
     */
    resultRelInfo = resultRelInfos;
    foreach(cell, rels)
    {
        estate->es_result_relation_info = resultRelInfo;
        ExecBSTruncateTriggers(estate, resultRelInfo);
        resultRelInfo++;
    }

    /*
     * OK, truncate each table.
     */
    mySubid = GetCurrentSubTransactionId();

    foreach(cell, rels)
    {
        Relation    rel = (Relation) lfirst(cell);

        /*
         * Normally, we need a transaction-safe truncation here.  However, if
         * the table was either created in the current (sub)transaction or has
         * a new relfilenode in the current (sub)transaction, then we can just
         * truncate it in-place, because a rollback would cause the whole
         * table or the current physical file to be thrown away anyway.
         */
        if (rel->rd_createSubid == mySubid ||
            rel->rd_newRelfilenodeSubid == mySubid)
        {
            /* Immediate, non-rollbackable truncation is OK */
            heap_truncate_one_rel(rel);
        }
        else
        {
            Oid         heap_relid;
            Oid         toast_relid;
            MultiXactId minmulti;

            /*
             * 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);

            minmulti = GetOldestMultiXactId();

            /*
             * Need the full transaction-safe pushups.
             *
             * Create a new empty storage file for the relation, and assign it
             * as the relfilenode value. The old storage file is scheduled for
             * deletion at commit.
             */
            RelationSetNewRelfilenode(rel, RecentXmin, minmulti);
            if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
                heap_create_init_fork(rel);

            heap_relid = RelationGetRelid(rel);
            toast_relid = rel->rd_rel->reltoastrelid;

            /*
             * The same for the toast table, if any.
             */
            if (OidIsValid(toast_relid))
            {
                rel = relation_open(toast_relid, AccessExclusiveLock);
                RelationSetNewRelfilenode(rel, RecentXmin, minmulti);
                if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
                    heap_create_init_fork(rel);
                heap_close(rel, NoLock);
            }

            /*
             * Reconstruct the indexes to match, and we're done.
             */
            reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST);
        }
    }

    /*
     * Restart owned sequences if we were asked to.
     */
    foreach(cell, seq_relids)
    {
        Oid         seq_relid = lfirst_oid(cell);

        ResetSequence(seq_relid);
    }

    /*
     * Process all AFTER STATEMENT TRUNCATE triggers.
     */
    resultRelInfo = resultRelInfos;
    foreach(cell, rels)
    {
        estate->es_result_relation_info = resultRelInfo;
        ExecASTruncateTriggers(estate, resultRelInfo);
        resultRelInfo++;
    }

    /* Handle queued AFTER triggers */
    AfterTriggerEndQuery(estate);

    /* We can clean up the EState now */
    FreeExecutorState(estate);

    /* And close the rels (can't do this while EState still holds refs) */
    foreach(cell, rels)
    {
        Relation    rel = (Relation) lfirst(cell);

        heap_close(rel, NoLock);
    }
}

void find_composite_type_dependencies ( Oid  typeOid,
Relation  origRelation,
const char *  origTypeName 
)

Definition at line 4147 of file tablecmds.c.

References AccessShareLock, Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, tupleDesc::attrs, BTEqualStrategyNumber, DependReferenceIndexId, DependRelationId, ereport, errcode(), errmsg(), ERROR, find_composite_type_dependencies(), get_array_type(), GETSTRUCT, heap_open(), HeapTupleIsValid, NameStr, ObjectIdGetDatum, OidIsValid, RelationData::rd_att, RelationData::rd_rel, relation_close(), relation_open(), RelationGetRelationName, RelationRelationId, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and TypeRelationId.

Referenced by ATPrepAlterColumnType(), ATRewriteTables(), find_composite_type_dependencies(), and get_rels_with_domain().

{
    Relation    depRel;
    ScanKeyData key[2];
    SysScanDesc depScan;
    HeapTuple   depTup;
    Oid         arrayOid;

    /*
     * We scan pg_depend to find those things that depend on the rowtype. (We
     * assume we can ignore refobjsubid for a rowtype.)
     */
    depRel = heap_open(DependRelationId, AccessShareLock);

    ScanKeyInit(&key[0],
                Anum_pg_depend_refclassid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(TypeRelationId));
    ScanKeyInit(&key[1],
                Anum_pg_depend_refobjid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(typeOid));

    depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
                                 SnapshotNow, 2, key);

    while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
    {
        Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
        Relation    rel;
        Form_pg_attribute att;

        /* Ignore dependees that aren't user columns of relations */
        /* (we assume system columns are never of rowtypes) */
        if (pg_depend->classid != RelationRelationId ||
            pg_depend->objsubid <= 0)
            continue;

        rel = relation_open(pg_depend->objid, AccessShareLock);
        att = rel->rd_att->attrs[pg_depend->objsubid - 1];

        if (rel->rd_rel->relkind == RELKIND_RELATION ||
            rel->rd_rel->relkind == RELKIND_MATVIEW)
        {
            if (origTypeName)
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
                                origTypeName,
                                RelationGetRelationName(rel),
                                NameStr(att->attname))));
            else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
                                RelationGetRelationName(origRelation),
                                RelationGetRelationName(rel),
                                NameStr(att->attname))));
            else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
                                RelationGetRelationName(origRelation),
                                RelationGetRelationName(rel),
                                NameStr(att->attname))));
            else
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
                                RelationGetRelationName(origRelation),
                                RelationGetRelationName(rel),
                                NameStr(att->attname))));
        }
        else if (OidIsValid(rel->rd_rel->reltype))
        {
            /*
             * A view or composite type itself isn't a problem, but we must
             * recursively check for indirect dependencies via its rowtype.
             */
            find_composite_type_dependencies(rel->rd_rel->reltype,
                                             origRelation, origTypeName);
        }

        relation_close(rel, AccessShareLock);
    }

    systable_endscan(depScan);

    relation_close(depRel, AccessShareLock);

    /*
     * If there's an array type for the rowtype, must check for uses of it,
     * too.
     */
    arrayOid = get_array_type(typeOid);
    if (OidIsValid(arrayOid))
        find_composite_type_dependencies(arrayOid, origRelation, origTypeName);
}

void PreCommit_on_commit_actions ( void   ) 

Definition at line 10230 of file tablecmds.c.

References Assert, CommandCounterIncrement(), OnCommitItem::deleting_subid, DROP_CASCADE, heap_truncate(), InvalidSubTransactionId, lappend_oid(), lfirst, MyXactAccessedTempRel, NIL, OnCommitItem::oncommit, ONCOMMIT_DELETE_ROWS, ONCOMMIT_DROP, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, PERFORM_DELETION_INTERNAL, performDeletion(), and OnCommitItem::relid.

Referenced by CommitTransaction(), and PrepareTransaction().

{
    ListCell   *l;
    List       *oids_to_truncate = NIL;

    foreach(l, on_commits)
    {
        OnCommitItem *oc = (OnCommitItem *) lfirst(l);

        /* Ignore entry if already dropped in this xact */
        if (oc->deleting_subid != InvalidSubTransactionId)
            continue;

        switch (oc->oncommit)
        {
            case ONCOMMIT_NOOP:
            case ONCOMMIT_PRESERVE_ROWS:
                /* Do nothing (there shouldn't be such entries, actually) */
                break;
            case ONCOMMIT_DELETE_ROWS:
                /*
                 * If this transaction hasn't accessed any temporary
                 * relations, we can skip truncating ON COMMIT DELETE ROWS
                 * tables, as they must still be empty.
                 */
                if (MyXactAccessedTempRel)
                    oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
                break;
            case ONCOMMIT_DROP:
                {
                    ObjectAddress object;

                    object.classId = RelationRelationId;
                    object.objectId = oc->relid;
                    object.objectSubId = 0;

                    /*
                     * Since this is an automatic drop, rather than one
                     * directly initiated by the user, we pass the
                     * PERFORM_DELETION_INTERNAL flag.
                     */
                    performDeletion(&object,
                                    DROP_CASCADE, PERFORM_DELETION_INTERNAL);

                    /*
                     * Note that table deletion will call
                     * remove_on_commit_action, so the entry should get marked
                     * as deleted.
                     */
                    Assert(oc->deleting_subid != InvalidSubTransactionId);
                    break;
                }
        }
    }
    if (oids_to_truncate != NIL)
    {
        heap_truncate(oids_to_truncate);
        CommandCounterIncrement();      /* XXX needed? */
    }
}

void RangeVarCallbackOwnsTable ( const RangeVar relation,
Oid  relId,
Oid  oldRelId,
void *  arg 
)

Definition at line 10387 of file tablecmds.c.

References ACL_KIND_CLASS, aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), GetUserId(), OidIsValid, pg_class_ownercheck(), DropRelationCallbackState::relkind, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_TOASTVALUE, and RangeVar::relname.

Referenced by cluster(), ExecRefreshMatView(), and ReindexTable().

{
    char        relkind;

    /* Nothing to do if the relation was not found. */
    if (!OidIsValid(relId))
        return;

    /*
     * If the relation does exist, check whether it's an index.  But note that
     * the relation might have been dropped between the time we did the name
     * lookup and now.  In that case, there's nothing to do.
     */
    relkind = get_rel_relkind(relId);
    if (!relkind)
        return;
    if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
        relkind != RELKIND_MATVIEW)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("\"%s\" is not a table or materialized view", relation->relname)));

    /* Check permissions */
    if (!pg_class_ownercheck(relId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, relation->relname);
}

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 10176 of file tablecmds.c.

References CacheMemoryContext, OnCommitItem::creating_subid, OnCommitItem::deleting_subid, GetCurrentSubTransactionId(), lcons(), MemoryContextSwitchTo(), OnCommitItem::oncommit, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, palloc(), and OnCommitItem::relid.

Referenced by heap_create_with_catalog().

{
    OnCommitItem *oc;
    MemoryContext oldcxt;

    /*
     * We needn't bother registering the relation unless there is an ON COMMIT
     * action we need to take.
     */
    if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
        return;

    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

    oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
    oc->relid = relid;
    oc->oncommit = action;
    oc->creating_subid = GetCurrentSubTransactionId();
    oc->deleting_subid = InvalidSubTransactionId;

    on_commits = lcons(oc, on_commits);

    MemoryContextSwitchTo(oldcxt);
}

void remove_on_commit_action ( Oid  relid  ) 

Definition at line 10207 of file tablecmds.c.

References OnCommitItem::deleting_subid, GetCurrentSubTransactionId(), lfirst, and OnCommitItem::relid.

Referenced by heap_drop_with_catalog().

{
    ListCell   *l;

    foreach(l, on_commits)
    {
        OnCommitItem *oc = (OnCommitItem *) lfirst(l);

        if (oc->relid == relid)
        {
            oc->deleting_subid = GetCurrentSubTransactionId();
            break;
        }
    }
}

void RemoveRelations ( DropStmt drop  ) 

Definition at line 746 of file tablecmds.c.

References AcceptInvalidationMessages(), add_exact_object_address(), Assert, DropStmt::behavior, ObjectAddress::classId, DropRelationCallbackState::concurrent, DropStmt::concurrent, DROP_CASCADE, DropErrorMsgNonExistent(), elog, ereport, errcode(), errmsg(), ERROR, free_object_addresses(), DropRelationCallbackState::heapOid, lfirst, list_length(), makeRangeVarFromNameList(), DropStmt::missing_ok, new_object_addresses(), OBJECT_FOREIGN_TABLE, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_VIEW, ObjectAddress::objectId, DropStmt::objects, ObjectAddress::objectSubId, OidIsValid, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), DropRelationCallbackState::relkind, RangeVar::relname, and DropStmt::removeType.

Referenced by ExecDropStmt().

{
    ObjectAddresses *objects;
    char        relkind;
    ListCell   *cell;
    int         flags = 0;
    LOCKMODE    lockmode = AccessExclusiveLock;

    /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
    if (drop->concurrent)
    {
        flags |= PERFORM_DELETION_CONCURRENTLY;
        lockmode = ShareUpdateExclusiveLock;
        Assert(drop->removeType == OBJECT_INDEX);
        if (list_length(drop->objects) != 1)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
        if (drop->behavior == DROP_CASCADE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
    }

    /*
     * First we identify all the relations, then we delete them in a single
     * performMultipleDeletions() call.  This is to avoid unwanted DROP
     * RESTRICT errors if one of the relations depends on another.
     */

    /* Determine required relkind */
    switch (drop->removeType)
    {
        case OBJECT_TABLE:
            relkind = RELKIND_RELATION;
            break;

        case OBJECT_INDEX:
            relkind = RELKIND_INDEX;
            break;

        case OBJECT_SEQUENCE:
            relkind = RELKIND_SEQUENCE;
            break;

        case OBJECT_VIEW:
            relkind = RELKIND_VIEW;
            break;

        case OBJECT_MATVIEW:
            relkind = RELKIND_MATVIEW;
            break;

        case OBJECT_FOREIGN_TABLE:
            relkind = RELKIND_FOREIGN_TABLE;
            break;

        default:
            elog(ERROR, "unrecognized drop object type: %d",
                 (int) drop->removeType);
            relkind = 0;        /* keep compiler quiet */
            break;
    }

    /* Lock and validate each relation; build a list of object addresses */
    objects = new_object_addresses();

    foreach(cell, drop->objects)
    {
        RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
        Oid         relOid;
        ObjectAddress obj;
        struct DropRelationCallbackState state;

        /*
         * These next few steps are a great deal like relation_openrv, but we
         * don't bother building a relcache entry since we don't need it.
         *
         * Check for shared-cache-inval messages before trying to access the
         * relation.  This is needed to cover the case where the name
         * identifies a rel that has been dropped and recreated since the
         * start of our transaction: if we don't flush the old syscache entry,
         * then we'll latch onto that entry and suffer an error later.
         */
        AcceptInvalidationMessages();

        /* Look up the appropriate relation using namespace search. */
        state.relkind = relkind;
        state.heapOid = InvalidOid;
        state.concurrent = drop->concurrent;
        relOid = RangeVarGetRelidExtended(rel, lockmode, true,
                                          false,
                                          RangeVarCallbackForDropRelation,
                                          (void *) &state);

        /* Not there? */
        if (!OidIsValid(relOid))
        {
            DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
            continue;
        }

        /* OK, we're ready to delete this one */
        obj.classId = RelationRelationId;
        obj.objectId = relOid;
        obj.objectSubId = 0;

        add_exact_object_address(&obj, objects);
    }

    performMultipleDeletions(objects, drop->behavior, flags);

    free_object_addresses(objects);
}

Oid renameatt ( RenameStmt stmt  ) 

Definition at line 2278 of file tablecmds.c.

References AccessExclusiveLock, RenameStmt::behavior, ereport, errmsg(), RangeVar::inhOpt, interpretInhOption(), RenameStmt::missing_ok, RenameStmt::newname, NOTICE, NULL, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), RenameStmt::relation, RangeVar::relname, renameatt_internal(), and RenameStmt::subname.

Referenced by ExecRenameStmt().

{
    Oid         relid;

    /* lock level taken here should match renameatt_internal */
    relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
                                     stmt->missing_ok, false,
                                     RangeVarCallbackForRenameAttribute,
                                     NULL);

    if (!OidIsValid(relid))
    {
        ereport(NOTICE,
                (errmsg("relation \"%s\" does not exist, skipping",
                        stmt->relation->relname)));
        return InvalidOid;
    }

    renameatt_internal(relid,
                       stmt->subname,   /* old att name */
                       stmt->newname,   /* new att name */
                       interpretInhOption(stmt->relation->inhOpt),      /* recursive? */
                       false,   /* recursing? */
                       0,       /* expected inhcount */
                       stmt->behavior);

    /* This is an ALTER TABLE command so it's about the relid */
    return relid;
}

Oid RenameConstraint ( RenameStmt stmt  ) 
Oid RenameRelation ( RenameStmt stmt  ) 

Definition at line 2451 of file tablecmds.c.

References AccessExclusiveLock, ereport, errmsg(), RenameStmt::missing_ok, NOTICE, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameStmt::relation, and RenameRelationInternal().

Referenced by ExecRenameStmt().

{
    Oid         relid;

    /*
     * Grab an exclusive lock on the target table, index, sequence or view,
     * which we will NOT release until end of transaction.
     *
     * Lock level used here should match RenameRelationInternal, to avoid lock
     * escalation.
     */
    relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
                                     stmt->missing_ok, false,
                                     RangeVarCallbackForAlterRelation,
                                     (void *) stmt);

    if (!OidIsValid(relid))
    {
        ereport(NOTICE,
                (errmsg("relation \"%s\" does not exist, skipping",
                        stmt->relation->relname)));
        return InvalidOid;
    }

    /* Do the work */
    RenameRelationInternal(relid, stmt->newname, false);

    return relid;
}

void RenameRelationInternal ( Oid  myrelid,
const char *  newrelname,
bool  is_internal 
)

Definition at line 2491 of file tablecmds.c.

References AccessExclusiveLock, CatalogUpdateIndexes(), elog, ereport, errcode(), errmsg(), ERROR, get_index_constraint(), get_relname_relid(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHookArg, namestrcpy(), NoLock, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetNamespace, RelationRelationId, RELKIND_INDEX, RELOID, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.

Referenced by ATExecAddIndexConstraint(), finish_heap_swap(), rename_constraint_internal(), RenameRelation(), and RenameType().

{
    Relation    targetrelation;
    Relation    relrelation;    /* for RELATION relation */
    HeapTuple   reltup;
    Form_pg_class relform;
    Oid         namespaceId;

    /*
     * Grab an exclusive lock on the target table, index, sequence or view,
     * which we will NOT release until end of transaction.
     */
    targetrelation = relation_open(myrelid, AccessExclusiveLock);
    namespaceId = RelationGetNamespace(targetrelation);

    /*
     * Find relation's pg_class tuple, and make sure newrelname isn't in use.
     */
    relrelation = heap_open(RelationRelationId, RowExclusiveLock);

    reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
    if (!HeapTupleIsValid(reltup))      /* shouldn't happen */
        elog(ERROR, "cache lookup failed for relation %u", myrelid);
    relform = (Form_pg_class) GETSTRUCT(reltup);

    if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_TABLE),
                 errmsg("relation \"%s\" already exists",
                        newrelname)));

    /*
     * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
     * because it's a copy...)
     */
    namestrcpy(&(relform->relname), newrelname);

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

    /* keep the system catalog indexes current */
    CatalogUpdateIndexes(relrelation, reltup);

    InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
                                 InvalidOid, is_internal);

    heap_freetuple(reltup);
    heap_close(relrelation, RowExclusiveLock);

    /*
     * Also rename the associated type, if any.
     */
    if (OidIsValid(targetrelation->rd_rel->reltype))
        RenameTypeInternal(targetrelation->rd_rel->reltype,
                           newrelname, namespaceId);

    /*
     * Also rename the associated constraint, if any.
     */
    if (targetrelation->rd_rel->relkind == RELKIND_INDEX)
    {
        Oid         constraintId = get_index_constraint(myrelid);

        if (OidIsValid(constraintId))
            RenameConstraintById(constraintId, newrelname);
    }

    /*
     * Close rel, but keep exclusive lock!
     */
    relation_close(targetrelation, NoLock);
}

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 2033 of file tablecmds.c.

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

Referenced by acquire_inherited_sample_rows(), and StoreCatalogInheritance1().

{
    Relation    relationRelation;
    HeapTuple   tuple;
    Form_pg_class classtuple;

    /*
     * Fetch a modifiable copy of the tuple, modify it, update pg_class.
     */
    relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
    tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for relation %u", relationId);
    classtuple = (Form_pg_class) GETSTRUCT(tuple);

    if (classtuple->relhassubclass != relhassubclass)
    {
        classtuple->relhassubclass = relhassubclass;
        simple_heap_update(relationRelation, &tuple->t_self, tuple);

        /* keep the catalog indexes up to date */
        CatalogUpdateIndexes(relationRelation, tuple);
    }
    else
    {
        /* no need to change tuple, but force relcache rebuild anyway */
        CacheInvalidateRelcacheByTuple(tuple);
    }

    heap_freetuple(tuple);
    heap_close(relationRelation, RowExclusiveLock);
}