LCOV - code coverage report
Current view: top level - src/backend/commands - tablecmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 6266 6827 91.8 %
Date: 2024-04-13 09:11:47 Functions: 201 202 99.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tablecmds.c
       4             :  *    Commands for creating and altering table structures and settings
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/commands/tablecmds.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/attmap.h"
      18             : #include "access/genam.h"
      19             : #include "access/gist.h"
      20             : #include "access/heapam.h"
      21             : #include "access/heapam_xlog.h"
      22             : #include "access/multixact.h"
      23             : #include "access/reloptions.h"
      24             : #include "access/relscan.h"
      25             : #include "access/sysattr.h"
      26             : #include "access/tableam.h"
      27             : #include "access/toast_compression.h"
      28             : #include "access/xact.h"
      29             : #include "access/xlog.h"
      30             : #include "access/xloginsert.h"
      31             : #include "catalog/catalog.h"
      32             : #include "catalog/heap.h"
      33             : #include "catalog/index.h"
      34             : #include "catalog/namespace.h"
      35             : #include "catalog/objectaccess.h"
      36             : #include "catalog/partition.h"
      37             : #include "catalog/pg_am.h"
      38             : #include "catalog/pg_attrdef.h"
      39             : #include "catalog/pg_collation.h"
      40             : #include "catalog/pg_constraint.h"
      41             : #include "catalog/pg_depend.h"
      42             : #include "catalog/pg_foreign_table.h"
      43             : #include "catalog/pg_inherits.h"
      44             : #include "catalog/pg_largeobject.h"
      45             : #include "catalog/pg_namespace.h"
      46             : #include "catalog/pg_opclass.h"
      47             : #include "catalog/pg_policy.h"
      48             : #include "catalog/pg_rewrite.h"
      49             : #include "catalog/pg_statistic_ext.h"
      50             : #include "catalog/pg_tablespace.h"
      51             : #include "catalog/pg_trigger.h"
      52             : #include "catalog/pg_type.h"
      53             : #include "catalog/storage.h"
      54             : #include "catalog/storage_xlog.h"
      55             : #include "catalog/toasting.h"
      56             : #include "commands/cluster.h"
      57             : #include "commands/comment.h"
      58             : #include "commands/defrem.h"
      59             : #include "commands/event_trigger.h"
      60             : #include "commands/sequence.h"
      61             : #include "commands/tablecmds.h"
      62             : #include "commands/tablespace.h"
      63             : #include "commands/trigger.h"
      64             : #include "commands/typecmds.h"
      65             : #include "commands/user.h"
      66             : #include "commands/vacuum.h"
      67             : #include "executor/executor.h"
      68             : #include "foreign/fdwapi.h"
      69             : #include "foreign/foreign.h"
      70             : #include "miscadmin.h"
      71             : #include "nodes/makefuncs.h"
      72             : #include "nodes/nodeFuncs.h"
      73             : #include "nodes/parsenodes.h"
      74             : #include "optimizer/optimizer.h"
      75             : #include "parser/parse_coerce.h"
      76             : #include "parser/parse_collate.h"
      77             : #include "parser/parse_expr.h"
      78             : #include "parser/parse_relation.h"
      79             : #include "parser/parse_type.h"
      80             : #include "parser/parse_utilcmd.h"
      81             : #include "parser/parser.h"
      82             : #include "partitioning/partbounds.h"
      83             : #include "partitioning/partdesc.h"
      84             : #include "pgstat.h"
      85             : #include "rewrite/rewriteDefine.h"
      86             : #include "rewrite/rewriteHandler.h"
      87             : #include "rewrite/rewriteManip.h"
      88             : #include "storage/bufmgr.h"
      89             : #include "storage/lmgr.h"
      90             : #include "storage/lock.h"
      91             : #include "storage/predicate.h"
      92             : #include "storage/smgr.h"
      93             : #include "tcop/utility.h"
      94             : #include "utils/acl.h"
      95             : #include "utils/builtins.h"
      96             : #include "utils/fmgroids.h"
      97             : #include "utils/inval.h"
      98             : #include "utils/lsyscache.h"
      99             : #include "utils/memutils.h"
     100             : #include "utils/partcache.h"
     101             : #include "utils/relcache.h"
     102             : #include "utils/ruleutils.h"
     103             : #include "utils/snapmgr.h"
     104             : #include "utils/syscache.h"
     105             : #include "utils/timestamp.h"
     106             : #include "utils/typcache.h"
     107             : #include "utils/usercontext.h"
     108             : 
     109             : /*
     110             :  * ON COMMIT action list
     111             :  */
     112             : typedef struct OnCommitItem
     113             : {
     114             :     Oid         relid;          /* relid of relation */
     115             :     OnCommitAction oncommit;    /* what to do at end of xact */
     116             : 
     117             :     /*
     118             :      * If this entry was created during the current transaction,
     119             :      * creating_subid is the ID of the creating subxact; if created in a prior
     120             :      * transaction, creating_subid is zero.  If deleted during the current
     121             :      * transaction, deleting_subid is the ID of the deleting subxact; if no
     122             :      * deletion request is pending, deleting_subid is zero.
     123             :      */
     124             :     SubTransactionId creating_subid;
     125             :     SubTransactionId deleting_subid;
     126             : } OnCommitItem;
     127             : 
     128             : static List *on_commits = NIL;
     129             : 
     130             : 
     131             : /*
     132             :  * State information for ALTER TABLE
     133             :  *
     134             :  * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo
     135             :  * structs, one for each table modified by the operation (the named table
     136             :  * plus any child tables that are affected).  We save lists of subcommands
     137             :  * to apply to this table (possibly modified by parse transformation steps);
     138             :  * these lists will be executed in Phase 2.  If a Phase 3 step is needed,
     139             :  * necessary information is stored in the constraints and newvals lists.
     140             :  *
     141             :  * Phase 2 is divided into multiple passes; subcommands are executed in
     142             :  * a pass determined by subcommand type.
     143             :  */
     144             : 
     145             : typedef enum AlterTablePass
     146             : {
     147             :     AT_PASS_UNSET = -1,         /* UNSET will cause ERROR */
     148             :     AT_PASS_DROP,               /* DROP (all flavors) */
     149             :     AT_PASS_ALTER_TYPE,         /* ALTER COLUMN TYPE */
     150             :     AT_PASS_ADD_COL,            /* ADD COLUMN */
     151             :     AT_PASS_SET_EXPRESSION,     /* ALTER SET EXPRESSION */
     152             :     AT_PASS_OLD_INDEX,          /* re-add existing indexes */
     153             :     AT_PASS_OLD_CONSTR,         /* re-add existing constraints */
     154             :     /* We could support a RENAME COLUMN pass here, but not currently used */
     155             :     AT_PASS_ADD_CONSTR,         /* ADD constraints (initial examination) */
     156             :     AT_PASS_COL_ATTRS,          /* set column attributes, eg NOT NULL */
     157             :     AT_PASS_ADD_INDEXCONSTR,    /* ADD index-based constraints */
     158             :     AT_PASS_ADD_INDEX,          /* ADD indexes */
     159             :     AT_PASS_ADD_OTHERCONSTR,    /* ADD other constraints, defaults */
     160             :     AT_PASS_MISC,               /* other stuff */
     161             : } AlterTablePass;
     162             : 
     163             : #define AT_NUM_PASSES           (AT_PASS_MISC + 1)
     164             : 
     165             : typedef struct AlteredTableInfo
     166             : {
     167             :     /* Information saved before any work commences: */
     168             :     Oid         relid;          /* Relation to work on */
     169             :     char        relkind;        /* Its relkind */
     170             :     TupleDesc   oldDesc;        /* Pre-modification tuple descriptor */
     171             : 
     172             :     /*
     173             :      * Transiently set during Phase 2, normally set to NULL.
     174             :      *
     175             :      * ATRewriteCatalogs sets this when it starts, and closes when ATExecCmd
     176             :      * returns control.  This can be exploited by ATExecCmd subroutines to
     177             :      * close/reopen across transaction boundaries.
     178             :      */
     179             :     Relation    rel;
     180             : 
     181             :     /* Information saved by Phase 1 for Phase 2: */
     182             :     List       *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */
     183             :     /* Information saved by Phases 1/2 for Phase 3: */
     184             :     List       *constraints;    /* List of NewConstraint */
     185             :     List       *newvals;        /* List of NewColumnValue */
     186             :     List       *afterStmts;     /* List of utility command parsetrees */
     187             :     bool        verify_new_notnull; /* T if we should recheck NOT NULL */
     188             :     int         rewrite;        /* Reason for forced rewrite, if any */
     189             :     bool        chgAccessMethod;    /* T if SET ACCESS METHOD is used */
     190             :     Oid         newAccessMethod;    /* new access method; 0 means no change,
     191             :                                      * if above is true */
     192             :     Oid         newTableSpace;  /* new tablespace; 0 means no change */
     193             :     bool        chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
     194             :     char        newrelpersistence;  /* if above is true */
     195             :     Expr       *partition_constraint;   /* for attach partition validation */
     196             :     /* true, if validating default due to some other attach/detach */
     197             :     bool        validate_default;
     198             :     /* Objects to rebuild after completing ALTER TYPE operations */
     199             :     List       *changedConstraintOids;  /* OIDs of constraints to rebuild */
     200             :     List       *changedConstraintDefs;  /* string definitions of same */
     201             :     List       *changedIndexOids;   /* OIDs of indexes to rebuild */
     202             :     List       *changedIndexDefs;   /* string definitions of same */
     203             :     char       *replicaIdentityIndex;   /* index to reset as REPLICA IDENTITY */
     204             :     char       *clusterOnIndex; /* index to use for CLUSTER */
     205             :     List       *changedStatisticsOids;  /* OIDs of statistics to rebuild */
     206             :     List       *changedStatisticsDefs;  /* string definitions of same */
     207             : } AlteredTableInfo;
     208             : 
     209             : /* Struct describing one new constraint to check in Phase 3 scan */
     210             : /* Note: new not-null constraints are handled elsewhere */
     211             : typedef struct NewConstraint
     212             : {
     213             :     char       *name;           /* Constraint name, or NULL if none */
     214             :     ConstrType  contype;        /* CHECK or FOREIGN */
     215             :     Oid         refrelid;       /* PK rel, if FOREIGN */
     216             :     Oid         refindid;       /* OID of PK's index, if FOREIGN */
     217             :     bool        conwithperiod;  /* Whether the new FOREIGN KEY uses PERIOD */
     218             :     Oid         conid;          /* OID of pg_constraint entry, if FOREIGN */
     219             :     Node       *qual;           /* Check expr or CONSTR_FOREIGN Constraint */
     220             :     ExprState  *qualstate;      /* Execution state for CHECK expr */
     221             : } NewConstraint;
     222             : 
     223             : /*
     224             :  * Struct describing one new column value that needs to be computed during
     225             :  * Phase 3 copy (this could be either a new column with a non-null default, or
     226             :  * a column that we're changing the type of).  Columns without such an entry
     227             :  * are just copied from the old table during ATRewriteTable.  Note that the
     228             :  * expr is an expression over *old* table values, except when is_generated
     229             :  * is true; then it is an expression over columns of the *new* tuple.
     230             :  */
     231             : typedef struct NewColumnValue
     232             : {
     233             :     AttrNumber  attnum;         /* which column */
     234             :     Expr       *expr;           /* expression to compute */
     235             :     ExprState  *exprstate;      /* execution state */
     236             :     bool        is_generated;   /* is it a GENERATED expression? */
     237             : } NewColumnValue;
     238             : 
     239             : /*
     240             :  * Error-reporting support for RemoveRelations
     241             :  */
     242             : struct dropmsgstrings
     243             : {
     244             :     char        kind;
     245             :     int         nonexistent_code;
     246             :     const char *nonexistent_msg;
     247             :     const char *skipping_msg;
     248             :     const char *nota_msg;
     249             :     const char *drophint_msg;
     250             : };
     251             : 
     252             : static const struct dropmsgstrings dropmsgstringarray[] = {
     253             :     {RELKIND_RELATION,
     254             :         ERRCODE_UNDEFINED_TABLE,
     255             :         gettext_noop("table \"%s\" does not exist"),
     256             :         gettext_noop("table \"%s\" does not exist, skipping"),
     257             :         gettext_noop("\"%s\" is not a table"),
     258             :     gettext_noop("Use DROP TABLE to remove a table.")},
     259             :     {RELKIND_SEQUENCE,
     260             :         ERRCODE_UNDEFINED_TABLE,
     261             :         gettext_noop("sequence \"%s\" does not exist"),
     262             :         gettext_noop("sequence \"%s\" does not exist, skipping"),
     263             :         gettext_noop("\"%s\" is not a sequence"),
     264             :     gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
     265             :     {RELKIND_VIEW,
     266             :         ERRCODE_UNDEFINED_TABLE,
     267             :         gettext_noop("view \"%s\" does not exist"),
     268             :         gettext_noop("view \"%s\" does not exist, skipping"),
     269             :         gettext_noop("\"%s\" is not a view"),
     270             :     gettext_noop("Use DROP VIEW to remove a view.")},
     271             :     {RELKIND_MATVIEW,
     272             :         ERRCODE_UNDEFINED_TABLE,
     273             :         gettext_noop("materialized view \"%s\" does not exist"),
     274             :         gettext_noop("materialized view \"%s\" does not exist, skipping"),
     275             :         gettext_noop("\"%s\" is not a materialized view"),
     276             :     gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
     277             :     {RELKIND_INDEX,
     278             :         ERRCODE_UNDEFINED_OBJECT,
     279             :         gettext_noop("index \"%s\" does not exist"),
     280             :         gettext_noop("index \"%s\" does not exist, skipping"),
     281             :         gettext_noop("\"%s\" is not an index"),
     282             :     gettext_noop("Use DROP INDEX to remove an index.")},
     283             :     {RELKIND_COMPOSITE_TYPE,
     284             :         ERRCODE_UNDEFINED_OBJECT,
     285             :         gettext_noop("type \"%s\" does not exist"),
     286             :         gettext_noop("type \"%s\" does not exist, skipping"),
     287             :         gettext_noop("\"%s\" is not a type"),
     288             :     gettext_noop("Use DROP TYPE to remove a type.")},
     289             :     {RELKIND_FOREIGN_TABLE,
     290             :         ERRCODE_UNDEFINED_OBJECT,
     291             :         gettext_noop("foreign table \"%s\" does not exist"),
     292             :         gettext_noop("foreign table \"%s\" does not exist, skipping"),
     293             :         gettext_noop("\"%s\" is not a foreign table"),
     294             :     gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
     295             :     {RELKIND_PARTITIONED_TABLE,
     296             :         ERRCODE_UNDEFINED_TABLE,
     297             :         gettext_noop("table \"%s\" does not exist"),
     298             :         gettext_noop("table \"%s\" does not exist, skipping"),
     299             :         gettext_noop("\"%s\" is not a table"),
     300             :     gettext_noop("Use DROP TABLE to remove a table.")},
     301             :     {RELKIND_PARTITIONED_INDEX,
     302             :         ERRCODE_UNDEFINED_OBJECT,
     303             :         gettext_noop("index \"%s\" does not exist"),
     304             :         gettext_noop("index \"%s\" does not exist, skipping"),
     305             :         gettext_noop("\"%s\" is not an index"),
     306             :     gettext_noop("Use DROP INDEX to remove an index.")},
     307             :     {'\0', 0, NULL, NULL, NULL, NULL}
     308             : };
     309             : 
     310             : /* communication between RemoveRelations and RangeVarCallbackForDropRelation */
     311             : struct DropRelationCallbackState
     312             : {
     313             :     /* These fields are set by RemoveRelations: */
     314             :     char        expected_relkind;
     315             :     LOCKMODE    heap_lockmode;
     316             :     /* These fields are state to track which subsidiary locks are held: */
     317             :     Oid         heapOid;
     318             :     Oid         partParentOid;
     319             :     /* These fields are passed back by RangeVarCallbackForDropRelation: */
     320             :     char        actual_relkind;
     321             :     char        actual_relpersistence;
     322             : };
     323             : 
     324             : /* Alter table target-type flags for ATSimplePermissions */
     325             : #define     ATT_TABLE               0x0001
     326             : #define     ATT_VIEW                0x0002
     327             : #define     ATT_MATVIEW             0x0004
     328             : #define     ATT_INDEX               0x0008
     329             : #define     ATT_COMPOSITE_TYPE      0x0010
     330             : #define     ATT_FOREIGN_TABLE       0x0020
     331             : #define     ATT_PARTITIONED_INDEX   0x0040
     332             : #define     ATT_SEQUENCE            0x0080
     333             : 
     334             : /*
     335             :  * ForeignTruncateInfo
     336             :  *
     337             :  * Information related to truncation of foreign tables.  This is used for
     338             :  * the elements in a hash table. It uses the server OID as lookup key,
     339             :  * and includes a per-server list of all foreign tables involved in the
     340             :  * truncation.
     341             :  */
     342             : typedef struct ForeignTruncateInfo
     343             : {
     344             :     Oid         serverid;
     345             :     List       *rels;
     346             : } ForeignTruncateInfo;
     347             : 
     348             : /*
     349             :  * Partition tables are expected to be dropped when the parent partitioned
     350             :  * table gets dropped. Hence for partitioning we use AUTO dependency.
     351             :  * Otherwise, for regular inheritance use NORMAL dependency.
     352             :  */
     353             : #define child_dependency_type(child_is_partition)   \
     354             :     ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
     355             : 
     356             : static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
     357             : static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
     358             : static void truncate_check_activity(Relation rel);
     359             : static void RangeVarCallbackForTruncate(const RangeVar *relation,
     360             :                                         Oid relId, Oid oldRelId, void *arg);
     361             : static List *MergeAttributes(List *columns, const List *supers, char relpersistence,
     362             :                              bool is_partition, List **supconstr,
     363             :                              List **supnotnulls);
     364             : static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
     365             : static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
     366             : static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
     367             : static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
     368             : static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
     369             : static void StoreCatalogInheritance(Oid relationId, List *supers,
     370             :                                     bool child_is_partition);
     371             : static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
     372             :                                      int32 seqNumber, Relation inhRelation,
     373             :                                      bool child_is_partition);
     374             : static int  findAttrByName(const char *attributeName, const List *columns);
     375             : static void AlterIndexNamespaces(Relation classRel, Relation rel,
     376             :                                  Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved);
     377             : static void AlterSeqNamespaces(Relation classRel, Relation rel,
     378             :                                Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
     379             :                                LOCKMODE lockmode);
     380             : static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
     381             :                                            bool recurse, bool recursing, LOCKMODE lockmode);
     382             : static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
     383             :                                      Relation rel, HeapTuple contuple, List **otherrelids,
     384             :                                      LOCKMODE lockmode);
     385             : static ObjectAddress ATExecValidateConstraint(List **wqueue,
     386             :                                               Relation rel, char *constrName,
     387             :                                               bool recurse, bool recursing, LOCKMODE lockmode);
     388             : static int  transformColumnNameList(Oid relId, List *colList,
     389             :                                     int16 *attnums, Oid *atttypids);
     390             : static int  transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
     391             :                                        List **attnamelist,
     392             :                                        int16 *attnums, Oid *atttypids,
     393             :                                        Oid *opclasses, bool *pk_has_without_overlaps);
     394             : static Oid  transformFkeyCheckAttrs(Relation pkrel,
     395             :                                     int numattrs, int16 *attnums,
     396             :                                     bool with_period, Oid *opclasses,
     397             :                                     bool *pk_has_without_overlaps);
     398             : static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
     399             : static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId,
     400             :                                      Oid *funcid);
     401             : static void validateForeignKeyConstraint(char *conname,
     402             :                                          Relation rel, Relation pkrel,
     403             :                                          Oid pkindOid, Oid constraintOid, bool hasperiod);
     404             : static void ATController(AlterTableStmt *parsetree,
     405             :                          Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
     406             :                          AlterTableUtilityContext *context);
     407             : static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
     408             :                       bool recurse, bool recursing, LOCKMODE lockmode,
     409             :                       AlterTableUtilityContext *context);
     410             : static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
     411             :                               AlterTableUtilityContext *context);
     412             : static void ATExecCmd(List **wqueue, AlteredTableInfo *tab,
     413             :                       AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
     414             :                       AlterTableUtilityContext *context);
     415             : static AlterTableCmd *ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab,
     416             :                                           Relation rel, AlterTableCmd *cmd,
     417             :                                           bool recurse, LOCKMODE lockmode,
     418             :                                           AlterTablePass cur_pass,
     419             :                                           AlterTableUtilityContext *context);
     420             : static void ATRewriteTables(AlterTableStmt *parsetree,
     421             :                             List **wqueue, LOCKMODE lockmode,
     422             :                             AlterTableUtilityContext *context);
     423             : static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
     424             : static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
     425             : static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets);
     426             : static void ATSimpleRecursion(List **wqueue, Relation rel,
     427             :                               AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
     428             :                               AlterTableUtilityContext *context);
     429             : static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode);
     430             : static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
     431             :                                   LOCKMODE lockmode,
     432             :                                   AlterTableUtilityContext *context);
     433             : static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
     434             :                                            DropBehavior behavior);
     435             : static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
     436             :                             bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
     437             :                             AlterTableUtilityContext *context);
     438             : static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
     439             :                                      Relation rel, AlterTableCmd **cmd,
     440             :                                      bool recurse, bool recursing,
     441             :                                      LOCKMODE lockmode, AlterTablePass cur_pass,
     442             :                                      AlterTableUtilityContext *context);
     443             : static bool check_for_column_name_collision(Relation rel, const char *colname,
     444             :                                             bool if_not_exists);
     445             : static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
     446             : static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
     447             : static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
     448             :                                        LOCKMODE lockmode);
     449             : static bool set_attnotnull(List **wqueue, Relation rel,
     450             :                            AttrNumber attnum, bool recurse, LOCKMODE lockmode);
     451             : static ObjectAddress ATExecSetNotNull(List **wqueue, Relation rel,
     452             :                                       char *constrname, char *colName,
     453             :                                       bool recurse, bool recursing,
     454             :                                       List **readyRels, LOCKMODE lockmode);
     455             : static ObjectAddress ATExecSetAttNotNull(List **wqueue, Relation rel,
     456             :                                          const char *colName, LOCKMODE lockmode);
     457             : static bool NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr);
     458             : static bool ConstraintImpliedByRelConstraint(Relation scanrel,
     459             :                                              List *testConstraint, List *provenConstraint);
     460             : static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
     461             :                                          Node *newDefault, LOCKMODE lockmode);
     462             : static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
     463             :                                                Node *newDefault);
     464             : static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
     465             :                                        Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
     466             : static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
     467             :                                        Node *def, LOCKMODE lockmode, bool recurse, bool recursing);
     468             : static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
     469             :                                         bool recurse, bool recursing);
     470             : static ObjectAddress ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
     471             :                                          Node *newExpr, LOCKMODE lockmode);
     472             : static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
     473             : static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
     474             : static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
     475             :                                          Node *newValue, LOCKMODE lockmode);
     476             : static ObjectAddress ATExecSetOptions(Relation rel, const char *colName,
     477             :                                       Node *options, bool isReset, LOCKMODE lockmode);
     478             : static ObjectAddress ATExecSetStorage(Relation rel, const char *colName,
     479             :                                       Node *newValue, LOCKMODE lockmode);
     480             : static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
     481             :                              AlterTableCmd *cmd, LOCKMODE lockmode,
     482             :                              AlterTableUtilityContext *context);
     483             : static ObjectAddress ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
     484             :                                       DropBehavior behavior,
     485             :                                       bool recurse, bool recursing,
     486             :                                       bool missing_ok, LOCKMODE lockmode,
     487             :                                       ObjectAddresses *addrs);
     488             : static void ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
     489             :                                 LOCKMODE lockmode, AlterTableUtilityContext *context);
     490             : static ObjectAddress ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
     491             :                                     IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
     492             : static ObjectAddress ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
     493             :                                          CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode);
     494             : static ObjectAddress ATExecAddConstraint(List **wqueue,
     495             :                                          AlteredTableInfo *tab, Relation rel,
     496             :                                          Constraint *newConstraint, bool recurse, bool is_readd,
     497             :                                          LOCKMODE lockmode);
     498             : static char *ChooseForeignKeyConstraintNameAddition(List *colnames);
     499             : static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
     500             :                                               IndexStmt *stmt, LOCKMODE lockmode);
     501             : static ObjectAddress ATAddCheckNNConstraint(List **wqueue,
     502             :                                             AlteredTableInfo *tab, Relation rel,
     503             :                                             Constraint *constr,
     504             :                                             bool recurse, bool recursing, bool is_readd,
     505             :                                             LOCKMODE lockmode);
     506             : static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab,
     507             :                                                Relation rel, Constraint *fkconstraint,
     508             :                                                bool recurse, bool recursing,
     509             :                                                LOCKMODE lockmode);
     510             : static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint,
     511             :                                             Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
     512             :                                             int numfks, int16 *pkattnum, int16 *fkattnum,
     513             :                                             Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
     514             :                                             int numfkdelsetcols, int16 *fkdelsetcols,
     515             :                                             bool old_check_ok,
     516             :                                             Oid parentDelTrigger, Oid parentUpdTrigger,
     517             :                                             bool with_period);
     518             : static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums,
     519             :                                          int numfksetcols, const int16 *fksetcolsattnums,
     520             :                                          List *fksetcols);
     521             : static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint,
     522             :                                     Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr,
     523             :                                     int numfks, int16 *pkattnum, int16 *fkattnum,
     524             :                                     Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators,
     525             :                                     int numfkdelsetcols, int16 *fkdelsetcols,
     526             :                                     bool old_check_ok, LOCKMODE lockmode,
     527             :                                     Oid parentInsTrigger, Oid parentUpdTrigger,
     528             :                                     bool with_period);
     529             : 
     530             : static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
     531             :                                        Relation partitionRel);
     532             : static void CloneFkReferenced(Relation parentRel, Relation partitionRel);
     533             : static void CloneFkReferencing(List **wqueue, Relation parentRel,
     534             :                                Relation partRel);
     535             : static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid,
     536             :                                           Constraint *fkconstraint, Oid constraintOid,
     537             :                                           Oid indexOid,
     538             :                                           Oid parentInsTrigger, Oid parentUpdTrigger,
     539             :                                           Oid *insertTrigOid, Oid *updateTrigOid);
     540             : static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid,
     541             :                                            Constraint *fkconstraint, Oid constraintOid,
     542             :                                            Oid indexOid,
     543             :                                            Oid parentDelTrigger, Oid parentUpdTrigger,
     544             :                                            Oid *deleteTrigOid, Oid *updateTrigOid);
     545             : static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk,
     546             :                                          Oid partRelid,
     547             :                                          Oid parentConstrOid, int numfks,
     548             :                                          AttrNumber *mapped_conkey, AttrNumber *confkey,
     549             :                                          Oid *conpfeqop,
     550             :                                          Oid parentInsTrigger,
     551             :                                          Oid parentUpdTrigger,
     552             :                                          Relation trigrel);
     553             : static void GetForeignKeyActionTriggers(Relation trigrel,
     554             :                                         Oid conoid, Oid confrelid, Oid conrelid,
     555             :                                         Oid *deleteTriggerOid,
     556             :                                         Oid *updateTriggerOid);
     557             : static void GetForeignKeyCheckTriggers(Relation trigrel,
     558             :                                        Oid conoid, Oid confrelid, Oid conrelid,
     559             :                                        Oid *insertTriggerOid,
     560             :                                        Oid *updateTriggerOid);
     561             : static void ATExecDropConstraint(Relation rel, const char *constrName,
     562             :                                  DropBehavior behavior, bool recurse,
     563             :                                  bool missing_ok, LOCKMODE lockmode);
     564             : static ObjectAddress dropconstraint_internal(Relation rel,
     565             :                                              HeapTuple constraintTup, DropBehavior behavior,
     566             :                                              bool recurse, bool recursing,
     567             :                                              bool missing_ok, List **readyRels,
     568             :                                              LOCKMODE lockmode);
     569             : static void ATPrepAlterColumnType(List **wqueue,
     570             :                                   AlteredTableInfo *tab, Relation rel,
     571             :                                   bool recurse, bool recursing,
     572             :                                   AlterTableCmd *cmd, LOCKMODE lockmode,
     573             :                                   AlterTableUtilityContext *context);
     574             : static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
     575             : static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
     576             :                                            AlterTableCmd *cmd, LOCKMODE lockmode);
     577             : static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype,
     578             :                                               Relation rel, AttrNumber attnum, const char *colName);
     579             : static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
     580             : static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
     581             : static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab);
     582             : static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
     583             :                                    LOCKMODE lockmode);
     584             : static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
     585             :                                  char *cmd, List **wqueue, LOCKMODE lockmode,
     586             :                                  bool rewrite);
     587             : static void RebuildConstraintComment(AlteredTableInfo *tab, AlterTablePass pass,
     588             :                                      Oid objid, Relation rel, List *domname,
     589             :                                      const char *conname);
     590             : static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
     591             : static void TryReuseForeignKey(Oid oldId, Constraint *con);
     592             : static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
     593             :                                                      List *options, LOCKMODE lockmode);
     594             : static void change_owner_fix_column_acls(Oid relationOid,
     595             :                                          Oid oldOwnerId, Oid newOwnerId);
     596             : static void change_owner_recurse_to_sequences(Oid relationOid,
     597             :                                               Oid newOwnerId, LOCKMODE lockmode);
     598             : static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
     599             :                                      LOCKMODE lockmode);
     600             : static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
     601             : static void ATPrepSetAccessMethod(AlteredTableInfo *tab, Relation rel, const char *amname);
     602             : static void ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethod);
     603             : static bool ATPrepChangePersistence(Relation rel, bool toLogged);
     604             : static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
     605             :                                 const char *tablespacename, LOCKMODE lockmode);
     606             : static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
     607             : static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace);
     608             : static void ATExecSetRelOptions(Relation rel, List *defList,
     609             :                                 AlterTableType operation,
     610             :                                 LOCKMODE lockmode);
     611             : static void ATExecEnableDisableTrigger(Relation rel, const char *trigname,
     612             :                                        char fires_when, bool skip_system, bool recurse,
     613             :                                        LOCKMODE lockmode);
     614             : static void ATExecEnableDisableRule(Relation rel, const char *rulename,
     615             :                                     char fires_when, LOCKMODE lockmode);
     616             : static void ATPrepAddInherit(Relation child_rel);
     617             : static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
     618             : static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
     619             : static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
     620             :                                    DependencyType deptype);
     621             : static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
     622             : static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
     623             : static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
     624             : static void ATExecGenericOptions(Relation rel, List *options);
     625             : static void ATExecSetRowSecurity(Relation rel, bool rls);
     626             : static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
     627             : static ObjectAddress ATExecSetCompression(Relation rel,
     628             :                                           const char *column, Node *newValue, LOCKMODE lockmode);
     629             : 
     630             : static void index_copy_data(Relation rel, RelFileLocator newrlocator);
     631             : static const char *storage_name(char c);
     632             : 
     633             : static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
     634             :                                             Oid oldRelOid, void *arg);
     635             : static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
     636             :                                              Oid oldrelid, void *arg);
     637             : static PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec);
     638             : static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs,
     639             :                                   List **partexprs, Oid *partopclass, Oid *partcollation,
     640             :                                   PartitionStrategy strategy);
     641             : static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition);
     642             : static void RemoveInheritance(Relation child_rel, Relation parent_rel,
     643             :                               bool expect_detached);
     644             : static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel,
     645             :                                     int inhcount);
     646             : static ObjectAddress ATExecAttachPartition(List **wqueue, Relation rel,
     647             :                                            PartitionCmd *cmd,
     648             :                                            AlterTableUtilityContext *context);
     649             : static void AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel);
     650             : static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
     651             :                                                List *partConstraint,
     652             :                                                bool validate_default);
     653             : static void CloneRowTriggersToPartition(Relation parent, Relation partition);
     654             : static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel);
     655             : static void DropClonedTriggersFromPartition(Oid partitionId);
     656             : static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab,
     657             :                                            Relation rel, RangeVar *name,
     658             :                                            bool concurrent);
     659             : static void DetachPartitionFinalize(Relation rel, Relation partRel,
     660             :                                     bool concurrent, Oid defaultPartOid);
     661             : static ObjectAddress ATExecDetachPartitionFinalize(Relation rel, RangeVar *name);
     662             : static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx,
     663             :                                               RangeVar *name);
     664             : static void validatePartitionedIndex(Relation partedIdx, Relation partedTbl);
     665             : static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
     666             :                                   Relation partitionTbl);
     667             : static void verifyPartitionIndexNotNull(IndexInfo *iinfo, Relation partIdx);
     668             : static List *GetParentedForeignKeyRefs(Relation partition);
     669             : static void ATDetachCheckNoForeignKeyRefs(Relation partition);
     670             : static char GetAttributeCompression(Oid atttypid, const char *compression);
     671             : static char GetAttributeStorage(Oid atttypid, const char *storagemode);
     672             : 
     673             : static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab,
     674             :                                  Relation rel, PartitionCmd *cmd,
     675             :                                  AlterTableUtilityContext *context);
     676             : static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel,
     677             :                                   PartitionCmd *cmd, AlterTableUtilityContext *context);
     678             : 
     679             : /* ----------------------------------------------------------------
     680             :  *      DefineRelation
     681             :  *              Creates a new relation.
     682             :  *
     683             :  * stmt carries parsetree information from an ordinary CREATE TABLE statement.
     684             :  * The other arguments are used to extend the behavior for other cases:
     685             :  * relkind: relkind to assign to the new relation
     686             :  * ownerId: if not InvalidOid, use this as the new relation's owner.
     687             :  * typaddress: if not null, it's set to the pg_type entry's address.
     688             :  * queryString: for error reporting
     689             :  *
     690             :  * Note that permissions checks are done against current user regardless of
     691             :  * ownerId.  A nonzero ownerId is used when someone is creating a relation
     692             :  * "on behalf of" someone else, so we still want to see that the current user
     693             :  * has permissions to do it.
     694             :  *
     695             :  * If successful, returns the address of the new relation.
     696             :  * ----------------------------------------------------------------
     697             :  */
     698             : ObjectAddress
     699       53078 : DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
     700             :                ObjectAddress *typaddress, const char *queryString)
     701             : {
     702             :     char        relname[NAMEDATALEN];
     703             :     Oid         namespaceId;
     704             :     Oid         relationId;
     705             :     Oid         tablespaceId;
     706             :     Relation    rel;
     707             :     TupleDesc   descriptor;
     708             :     List       *inheritOids;
     709             :     List       *old_constraints;
     710             :     List       *old_notnulls;
     711             :     List       *rawDefaults;
     712             :     List       *cookedDefaults;
     713             :     List       *nncols;
     714             :     Datum       reloptions;
     715             :     ListCell   *listptr;
     716             :     AttrNumber  attnum;
     717             :     bool        partitioned;
     718             :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
     719             :     Oid         ofTypeId;
     720             :     ObjectAddress address;
     721             :     LOCKMODE    parentLockmode;
     722       53078 :     Oid         accessMethodId = InvalidOid;
     723             : 
     724             :     /*
     725             :      * Truncate relname to appropriate length (probably a waste of time, as
     726             :      * parser should have done this already).
     727             :      */
     728       53078 :     strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
     729             : 
     730             :     /*
     731             :      * Check consistency of arguments
     732             :      */
     733       53078 :     if (stmt->oncommit != ONCOMMIT_NOOP
     734         178 :         && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
     735          12 :         ereport(ERROR,
     736             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     737             :                  errmsg("ON COMMIT can only be used on temporary tables")));
     738             : 
     739       53066 :     if (stmt->partspec != NULL)
     740             :     {
     741        4870 :         if (relkind != RELKIND_RELATION)
     742           0 :             elog(ERROR, "unexpected relkind: %d", (int) relkind);
     743             : 
     744        4870 :         relkind = RELKIND_PARTITIONED_TABLE;
     745        4870 :         partitioned = true;
     746             :     }
     747             :     else
     748       48196 :         partitioned = false;
     749             : 
     750             :     /*
     751             :      * Look up the namespace in which we are supposed to create the relation,
     752             :      * check we have permission to create there, lock it against concurrent
     753             :      * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
     754             :      * namespace is selected.
     755             :      */
     756             :     namespaceId =
     757       53066 :         RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock, NULL);
     758             : 
     759             :     /*
     760             :      * Security check: disallow creating temp tables from security-restricted
     761             :      * code.  This is needed because calling code might not expect untrusted
     762             :      * tables to appear in pg_temp at the front of its search path.
     763             :      */
     764       53066 :     if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
     765        2960 :         && InSecurityRestrictedOperation())
     766           0 :         ereport(ERROR,
     767             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     768             :                  errmsg("cannot create temporary table within security-restricted operation")));
     769             : 
     770             :     /*
     771             :      * Determine the lockmode to use when scanning parents.  A self-exclusive
     772             :      * lock is needed here.
     773             :      *
     774             :      * For regular inheritance, if two backends attempt to add children to the
     775             :      * same parent simultaneously, and that parent has no pre-existing
     776             :      * children, then both will attempt to update the parent's relhassubclass
     777             :      * field, leading to a "tuple concurrently updated" error.  Also, this
     778             :      * interlocks against a concurrent ANALYZE on the parent table, which
     779             :      * might otherwise be attempting to clear the parent's relhassubclass
     780             :      * field, if its previous children were recently dropped.
     781             :      *
     782             :      * If the child table is a partition, then we instead grab an exclusive
     783             :      * lock on the parent because its partition descriptor will be changed by
     784             :      * addition of the new partition.
     785             :      */
     786       53066 :     parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
     787             :                       ShareUpdateExclusiveLock);
     788             : 
     789             :     /* Determine the list of OIDs of the parents. */
     790       53066 :     inheritOids = NIL;
     791       63394 :     foreach(listptr, stmt->inhRelations)
     792             :     {
     793       10328 :         RangeVar   *rv = (RangeVar *) lfirst(listptr);
     794             :         Oid         parentOid;
     795             : 
     796       10328 :         parentOid = RangeVarGetRelid(rv, parentLockmode, false);
     797             : 
     798             :         /*
     799             :          * Reject duplications in the list of parents.
     800             :          */
     801       10328 :         if (list_member_oid(inheritOids, parentOid))
     802           0 :             ereport(ERROR,
     803             :                     (errcode(ERRCODE_DUPLICATE_TABLE),
     804             :                      errmsg("relation \"%s\" would be inherited from more than once",
     805             :                             get_rel_name(parentOid))));
     806             : 
     807       10328 :         inheritOids = lappend_oid(inheritOids, parentOid);
     808             :     }
     809             : 
     810             :     /*
     811             :      * Select tablespace to use: an explicitly indicated one, or (in the case
     812             :      * of a partitioned table) the parent's, if it has one.
     813             :      */
     814       53066 :     if (stmt->tablespacename)
     815             :     {
     816         110 :         tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
     817             : 
     818         104 :         if (partitioned && tablespaceId == MyDatabaseTableSpace)
     819           6 :             ereport(ERROR,
     820             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     821             :                      errmsg("cannot specify default tablespace for partitioned relations")));
     822             :     }
     823       52956 :     else if (stmt->partbound)
     824             :     {
     825             :         Assert(list_length(inheritOids) == 1);
     826        8262 :         tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
     827             :     }
     828             :     else
     829       44694 :         tablespaceId = InvalidOid;
     830             : 
     831             :     /* still nothing? use the default */
     832       53054 :     if (!OidIsValid(tablespaceId))
     833       52934 :         tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
     834             :                                             partitioned);
     835             : 
     836             :     /* Check permissions except when using database's default */
     837       53048 :     if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
     838             :     {
     839             :         AclResult   aclresult;
     840             : 
     841         138 :         aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
     842             :                                     ACL_CREATE);
     843         138 :         if (aclresult != ACLCHECK_OK)
     844           6 :             aclcheck_error(aclresult, OBJECT_TABLESPACE,
     845           6 :                            get_tablespace_name(tablespaceId));
     846             :     }
     847             : 
     848             :     /* In all cases disallow placing user relations in pg_global */
     849       53042 :     if (tablespaceId == GLOBALTABLESPACE_OID)
     850          18 :         ereport(ERROR,
     851             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     852             :                  errmsg("only shared relations can be placed in pg_global tablespace")));
     853             : 
     854             :     /* Identify user ID that will own the table */
     855       53024 :     if (!OidIsValid(ownerId))
     856       52796 :         ownerId = GetUserId();
     857             : 
     858             :     /*
     859             :      * Parse and validate reloptions, if any.
     860             :      */
     861       53024 :     reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
     862             :                                      true, false);
     863             : 
     864       53006 :     switch (relkind)
     865             :     {
     866       13370 :         case RELKIND_VIEW:
     867       13370 :             (void) view_reloptions(reloptions, true);
     868       13352 :             break;
     869        4852 :         case RELKIND_PARTITIONED_TABLE:
     870        4852 :             (void) partitioned_table_reloptions(reloptions, true);
     871        4846 :             break;
     872       34784 :         default:
     873       34784 :             (void) heap_reloptions(relkind, reloptions, true);
     874             :     }
     875             : 
     876       52886 :     if (stmt->ofTypename)
     877             :     {
     878             :         AclResult   aclresult;
     879             : 
     880          86 :         ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
     881             : 
     882          86 :         aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
     883          86 :         if (aclresult != ACLCHECK_OK)
     884           6 :             aclcheck_error_type(aclresult, ofTypeId);
     885             :     }
     886             :     else
     887       52800 :         ofTypeId = InvalidOid;
     888             : 
     889             :     /*
     890             :      * Look up inheritance ancestors and generate relation schema, including
     891             :      * inherited attributes.  (Note that stmt->tableElts is destructively
     892             :      * modified by MergeAttributes.)
     893             :      */
     894       52712 :     stmt->tableElts =
     895       52880 :         MergeAttributes(stmt->tableElts, inheritOids,
     896       52880 :                         stmt->relation->relpersistence,
     897       52880 :                         stmt->partbound != NULL,
     898             :                         &old_constraints, &old_notnulls);
     899             : 
     900             :     /*
     901             :      * Create a tuple descriptor from the relation schema.  Note that this
     902             :      * deals with column names, types, and in-descriptor NOT NULL flags, but
     903             :      * not default values, NOT NULL or CHECK constraints; we handle those
     904             :      * below.
     905             :      */
     906       52712 :     descriptor = BuildDescForRelation(stmt->tableElts);
     907             : 
     908             :     /*
     909             :      * Find columns with default values and prepare for insertion of the
     910             :      * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
     911             :      * CookedConstraint structs that we'll pass to heap_create_with_catalog,
     912             :      * while raw defaults go into a list of RawColumnDefault structs that will
     913             :      * be processed by AddRelationNewConstraints.  (We can't deal with raw
     914             :      * expressions until we can do transformExpr.)
     915             :      *
     916             :      * We can set the atthasdef flags now in the tuple descriptor; this just
     917             :      * saves StoreAttrDefault from having to do an immediate update of the
     918             :      * pg_attribute rows.
     919             :      */
     920       52664 :     rawDefaults = NIL;
     921       52664 :     cookedDefaults = NIL;
     922       52664 :     attnum = 0;
     923             : 
     924      266982 :     foreach(listptr, stmt->tableElts)
     925             :     {
     926      214318 :         ColumnDef  *colDef = lfirst(listptr);
     927             :         Form_pg_attribute attr;
     928             : 
     929      214318 :         attnum++;
     930      214318 :         attr = TupleDescAttr(descriptor, attnum - 1);
     931             : 
     932      214318 :         if (colDef->raw_default != NULL)
     933             :         {
     934             :             RawColumnDefault *rawEnt;
     935             : 
     936             :             Assert(colDef->cooked_default == NULL);
     937             : 
     938        2400 :             rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
     939        2400 :             rawEnt->attnum = attnum;
     940        2400 :             rawEnt->raw_default = colDef->raw_default;
     941        2400 :             rawEnt->missingMode = false;
     942        2400 :             rawEnt->generated = colDef->generated;
     943        2400 :             rawDefaults = lappend(rawDefaults, rawEnt);
     944        2400 :             attr->atthasdef = true;
     945             :         }
     946      211918 :         else if (colDef->cooked_default != NULL)
     947             :         {
     948             :             CookedConstraint *cooked;
     949             : 
     950         442 :             cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
     951         442 :             cooked->contype = CONSTR_DEFAULT;
     952         442 :             cooked->conoid = InvalidOid; /* until created */
     953         442 :             cooked->name = NULL;
     954         442 :             cooked->attnum = attnum;
     955         442 :             cooked->expr = colDef->cooked_default;
     956         442 :             cooked->skip_validation = false;
     957         442 :             cooked->is_local = true; /* not used for defaults */
     958         442 :             cooked->inhcount = 0;    /* ditto */
     959         442 :             cooked->is_no_inherit = false;
     960         442 :             cookedDefaults = lappend(cookedDefaults, cooked);
     961         442 :             attr->atthasdef = true;
     962             :         }
     963             :     }
     964             : 
     965             :     /*
     966             :      * For relations with table AM and partitioned tables, select access
     967             :      * method to use: an explicitly indicated one, or (in the case of a
     968             :      * partitioned table) the parent's, if it has one.
     969             :      */
     970       52664 :     if (stmt->accessMethod != NULL)
     971             :     {
     972             :         Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
     973         116 :         accessMethodId = get_table_am_oid(stmt->accessMethod, false);
     974             :     }
     975       52548 :     else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
     976             :     {
     977       36424 :         if (stmt->partbound)
     978             :         {
     979             :             Assert(list_length(inheritOids) == 1);
     980        8104 :             accessMethodId = get_rel_relam(linitial_oid(inheritOids));
     981             :         }
     982             : 
     983       36424 :         if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
     984       31558 :             accessMethodId = get_table_am_oid(default_table_access_method, false);
     985             :     }
     986             : 
     987             :     /*
     988             :      * Create the relation.  Inherited defaults and constraints are passed in
     989             :      * for immediate handling --- since they don't need parsing, they can be
     990             :      * stored immediately.
     991             :      */
     992       52646 :     relationId = heap_create_with_catalog(relname,
     993             :                                           namespaceId,
     994             :                                           tablespaceId,
     995             :                                           InvalidOid,
     996             :                                           InvalidOid,
     997             :                                           ofTypeId,
     998             :                                           ownerId,
     999             :                                           accessMethodId,
    1000             :                                           descriptor,
    1001             :                                           list_concat(cookedDefaults,
    1002             :                                                       old_constraints),
    1003             :                                           relkind,
    1004       52646 :                                           stmt->relation->relpersistence,
    1005             :                                           false,
    1006             :                                           false,
    1007             :                                           stmt->oncommit,
    1008             :                                           reloptions,
    1009             :                                           true,
    1010             :                                           allowSystemTableMods,
    1011             :                                           false,
    1012             :                                           InvalidOid,
    1013             :                                           typaddress);
    1014             : 
    1015             :     /*
    1016             :      * We must bump the command counter to make the newly-created relation
    1017             :      * tuple visible for opening.
    1018             :      */
    1019       52622 :     CommandCounterIncrement();
    1020             : 
    1021             :     /*
    1022             :      * Open the new relation and acquire exclusive lock on it.  This isn't
    1023             :      * really necessary for locking out other backends (since they can't see
    1024             :      * the new rel anyway until we commit), but it keeps the lock manager from
    1025             :      * complaining about deadlock risks.
    1026             :      */
    1027       52622 :     rel = relation_open(relationId, AccessExclusiveLock);
    1028             : 
    1029             :     /*
    1030             :      * Now add any newly specified column default and generation expressions
    1031             :      * to the new relation.  These are passed to us in the form of raw
    1032             :      * parsetrees; we need to transform them to executable expression trees
    1033             :      * before they can be added. The most convenient way to do that is to
    1034             :      * apply the parser's transformExpr routine, but transformExpr doesn't
    1035             :      * work unless we have a pre-existing relation. So, the transformation has
    1036             :      * to be postponed to this final step of CREATE TABLE.
    1037             :      *
    1038             :      * This needs to be before processing the partitioning clauses because
    1039             :      * those could refer to generated columns.
    1040             :      */
    1041       52622 :     if (rawDefaults)
    1042        2036 :         AddRelationNewConstraints(rel, rawDefaults, NIL,
    1043             :                                   true, true, false, queryString);
    1044             : 
    1045             :     /*
    1046             :      * Make column generation expressions visible for use by partitioning.
    1047             :      */
    1048       52520 :     CommandCounterIncrement();
    1049             : 
    1050             :     /* Process and store partition bound, if any. */
    1051       52520 :     if (stmt->partbound)
    1052             :     {
    1053             :         PartitionBoundSpec *bound;
    1054             :         ParseState *pstate;
    1055        8208 :         Oid         parentId = linitial_oid(inheritOids),
    1056             :                     defaultPartOid;
    1057             :         Relation    parent,
    1058        8208 :                     defaultRel = NULL;
    1059             :         ParseNamespaceItem *nsitem;
    1060             : 
    1061             :         /* Already have strong enough lock on the parent */
    1062        8208 :         parent = table_open(parentId, NoLock);
    1063             : 
    1064             :         /*
    1065             :          * We are going to try to validate the partition bound specification
    1066             :          * against the partition key of parentRel, so it better have one.
    1067             :          */
    1068        8208 :         if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    1069          18 :             ereport(ERROR,
    1070             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1071             :                      errmsg("\"%s\" is not partitioned",
    1072             :                             RelationGetRelationName(parent))));
    1073             : 
    1074             :         /*
    1075             :          * The partition constraint of the default partition depends on the
    1076             :          * partition bounds of every other partition. It is possible that
    1077             :          * another backend might be about to execute a query on the default
    1078             :          * partition table, and that the query relies on previously cached
    1079             :          * default partition constraints. We must therefore take a table lock
    1080             :          * strong enough to prevent all queries on the default partition from
    1081             :          * proceeding until we commit and send out a shared-cache-inval notice
    1082             :          * that will make them update their index lists.
    1083             :          *
    1084             :          * Order of locking: The relation being added won't be visible to
    1085             :          * other backends until it is committed, hence here in
    1086             :          * DefineRelation() the order of locking the default partition and the
    1087             :          * relation being added does not matter. But at all other places we
    1088             :          * need to lock the default relation before we lock the relation being
    1089             :          * added or removed i.e. we should take the lock in same order at all
    1090             :          * the places such that lock parent, lock default partition and then
    1091             :          * lock the partition so as to avoid a deadlock.
    1092             :          */
    1093             :         defaultPartOid =
    1094        8190 :             get_default_oid_from_partdesc(RelationGetPartitionDesc(parent,
    1095             :                                                                    true));
    1096        8190 :         if (OidIsValid(defaultPartOid))
    1097         378 :             defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
    1098             : 
    1099             :         /* Transform the bound values */
    1100        8190 :         pstate = make_parsestate(NULL);
    1101        8190 :         pstate->p_sourcetext = queryString;
    1102             : 
    1103             :         /*
    1104             :          * Add an nsitem containing this relation, so that transformExpr
    1105             :          * called on partition bound expressions is able to report errors
    1106             :          * using a proper context.
    1107             :          */
    1108        8190 :         nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
    1109             :                                                NULL, false, false);
    1110        8190 :         addNSItemToQuery(pstate, nsitem, false, true, true);
    1111             : 
    1112        8190 :         bound = transformPartitionBound(pstate, parent, stmt->partbound);
    1113             : 
    1114             :         /*
    1115             :          * Check first that the new partition's bound is valid and does not
    1116             :          * overlap with any of existing partitions of the parent.
    1117             :          */
    1118        7986 :         check_new_partition_bound(relname, parent, bound, pstate);
    1119             : 
    1120             :         /*
    1121             :          * If the default partition exists, its partition constraints will
    1122             :          * change after the addition of this new partition such that it won't
    1123             :          * allow any row that qualifies for this new partition. So, check that
    1124             :          * the existing data in the default partition satisfies the constraint
    1125             :          * as it will exist after adding this partition.
    1126             :          */
    1127        7872 :         if (OidIsValid(defaultPartOid))
    1128             :         {
    1129         348 :             check_default_partition_contents(parent, defaultRel, bound);
    1130             :             /* Keep the lock until commit. */
    1131         330 :             table_close(defaultRel, NoLock);
    1132             :         }
    1133             : 
    1134             :         /* Update the pg_class entry. */
    1135        7854 :         StorePartitionBound(rel, parent, bound);
    1136             : 
    1137        7854 :         table_close(parent, NoLock);
    1138             :     }
    1139             : 
    1140             :     /* Store inheritance information for new rel. */
    1141       52166 :     StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
    1142             : 
    1143             :     /*
    1144             :      * Process the partitioning specification (if any) and store the partition
    1145             :      * key information into the catalog.
    1146             :      */
    1147       52166 :     if (partitioned)
    1148             :     {
    1149             :         ParseState *pstate;
    1150             :         int         partnatts;
    1151             :         AttrNumber  partattrs[PARTITION_MAX_KEYS];
    1152             :         Oid         partopclass[PARTITION_MAX_KEYS];
    1153             :         Oid         partcollation[PARTITION_MAX_KEYS];
    1154        4846 :         List       *partexprs = NIL;
    1155             : 
    1156        4846 :         pstate = make_parsestate(NULL);
    1157        4846 :         pstate->p_sourcetext = queryString;
    1158             : 
    1159        4846 :         partnatts = list_length(stmt->partspec->partParams);
    1160             : 
    1161             :         /* Protect fixed-size arrays here and in executor */
    1162        4846 :         if (partnatts > PARTITION_MAX_KEYS)
    1163           0 :             ereport(ERROR,
    1164             :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1165             :                      errmsg("cannot partition using more than %d columns",
    1166             :                             PARTITION_MAX_KEYS)));
    1167             : 
    1168             :         /*
    1169             :          * We need to transform the raw parsetrees corresponding to partition
    1170             :          * expressions into executable expression trees.  Like column defaults
    1171             :          * and CHECK constraints, we could not have done the transformation
    1172             :          * earlier.
    1173             :          */
    1174        4846 :         stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
    1175             : 
    1176        4816 :         ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
    1177             :                               partattrs, &partexprs, partopclass,
    1178        4816 :                               partcollation, stmt->partspec->strategy);
    1179             : 
    1180        4732 :         StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
    1181             :                           partexprs,
    1182             :                           partopclass, partcollation);
    1183             : 
    1184             :         /* make it all visible */
    1185        4732 :         CommandCounterIncrement();
    1186             :     }
    1187             : 
    1188             :     /*
    1189             :      * If we're creating a partition, create now all the indexes, triggers,
    1190             :      * FKs defined in the parent.
    1191             :      *
    1192             :      * We can't do it earlier, because DefineIndex wants to know the partition
    1193             :      * key which we just stored.
    1194             :      */
    1195       52052 :     if (stmt->partbound)
    1196             :     {
    1197        7848 :         Oid         parentId = linitial_oid(inheritOids);
    1198             :         Relation    parent;
    1199             :         List       *idxlist;
    1200             :         ListCell   *cell;
    1201             : 
    1202             :         /* Already have strong enough lock on the parent */
    1203        7848 :         parent = table_open(parentId, NoLock);
    1204        7848 :         idxlist = RelationGetIndexList(parent);
    1205             : 
    1206             :         /*
    1207             :          * For each index in the parent table, create one in the partition
    1208             :          */
    1209        9270 :         foreach(cell, idxlist)
    1210             :         {
    1211        1440 :             Relation    idxRel = index_open(lfirst_oid(cell), AccessShareLock);
    1212             :             AttrMap    *attmap;
    1213             :             IndexStmt  *idxstmt;
    1214             :             Oid         constraintOid;
    1215             : 
    1216        1440 :             if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    1217             :             {
    1218          36 :                 if (idxRel->rd_index->indisunique)
    1219          12 :                     ereport(ERROR,
    1220             :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1221             :                              errmsg("cannot create foreign partition of partitioned table \"%s\"",
    1222             :                                     RelationGetRelationName(parent)),
    1223             :                              errdetail("Table \"%s\" contains indexes that are unique.",
    1224             :                                        RelationGetRelationName(parent))));
    1225             :                 else
    1226             :                 {
    1227          24 :                     index_close(idxRel, AccessShareLock);
    1228          24 :                     continue;
    1229             :                 }
    1230             :             }
    1231             : 
    1232        1404 :             attmap = build_attrmap_by_name(RelationGetDescr(rel),
    1233             :                                            RelationGetDescr(parent),
    1234             :                                            false);
    1235             :             idxstmt =
    1236        1404 :                 generateClonedIndexStmt(NULL, idxRel,
    1237             :                                         attmap, &constraintOid);
    1238        1404 :             DefineIndex(RelationGetRelid(rel),
    1239             :                         idxstmt,
    1240             :                         InvalidOid,
    1241             :                         RelationGetRelid(idxRel),
    1242             :                         constraintOid,
    1243             :                         -1,
    1244             :                         false, false, false, false, false);
    1245             : 
    1246        1398 :             index_close(idxRel, AccessShareLock);
    1247             :         }
    1248             : 
    1249        7830 :         list_free(idxlist);
    1250             : 
    1251             :         /*
    1252             :          * If there are any row-level triggers, clone them to the new
    1253             :          * partition.
    1254             :          */
    1255        7830 :         if (parent->trigdesc != NULL)
    1256         426 :             CloneRowTriggersToPartition(parent, rel);
    1257             : 
    1258             :         /*
    1259             :          * And foreign keys too.  Note that because we're freshly creating the
    1260             :          * table, there is no need to verify these new constraints.
    1261             :          */
    1262        7830 :         CloneForeignKeyConstraints(NULL, parent, rel);
    1263             : 
    1264        7830 :         table_close(parent, NoLock);
    1265             :     }
    1266             : 
    1267             :     /*
    1268             :      * Now add any newly specified CHECK constraints to the new relation. Same
    1269             :      * as for defaults above, but these need to come after partitioning is set
    1270             :      * up.
    1271             :      */
    1272       52034 :     if (stmt->constraints)
    1273         634 :         AddRelationNewConstraints(rel, NIL, stmt->constraints,
    1274             :                                   true, true, false, queryString);
    1275             : 
    1276             :     /*
    1277             :      * Finally, merge the not-null constraints that are declared directly with
    1278             :      * those that come from parent relations (making sure to count inheritance
    1279             :      * appropriately for each), create them, and set the attnotnull flag on
    1280             :      * columns that don't yet have it.
    1281             :      */
    1282       52016 :     nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
    1283             :                                            old_notnulls);
    1284       59498 :     foreach(listptr, nncols)
    1285        7494 :         set_attnotnull(NULL, rel, lfirst_int(listptr), false, NoLock);
    1286             : 
    1287       52004 :     ObjectAddressSet(address, RelationRelationId, relationId);
    1288             : 
    1289             :     /*
    1290             :      * Clean up.  We keep lock on new relation (although it shouldn't be
    1291             :      * visible to anyone else anyway, until commit).
    1292             :      */
    1293       52004 :     relation_close(rel, NoLock);
    1294             : 
    1295       52004 :     return address;
    1296             : }
    1297             : 
    1298             : /*
    1299             :  * BuildDescForRelation
    1300             :  *
    1301             :  * Given a list of ColumnDef nodes, build a TupleDesc.
    1302             :  *
    1303             :  * Note: tdtypeid will need to be filled in later on.
    1304             :  */
    1305             : TupleDesc
    1306       55384 : BuildDescForRelation(const List *columns)
    1307             : {
    1308             :     int         natts;
    1309             :     AttrNumber  attnum;
    1310             :     ListCell   *l;
    1311             :     TupleDesc   desc;
    1312             :     bool        has_not_null;
    1313             :     char       *attname;
    1314             :     Oid         atttypid;
    1315             :     int32       atttypmod;
    1316             :     Oid         attcollation;
    1317             :     int         attdim;
    1318             : 
    1319             :     /*
    1320             :      * allocate a new tuple descriptor
    1321             :      */
    1322       55384 :     natts = list_length(columns);
    1323       55384 :     desc = CreateTemplateTupleDesc(natts);
    1324       55384 :     has_not_null = false;
    1325             : 
    1326       55384 :     attnum = 0;
    1327             : 
    1328      272638 :     foreach(l, columns)
    1329             :     {
    1330      217314 :         ColumnDef  *entry = lfirst(l);
    1331             :         AclResult   aclresult;
    1332             :         Form_pg_attribute att;
    1333             : 
    1334             :         /*
    1335             :          * for each entry in the list, get the name and type information from
    1336             :          * the list and have TupleDescInitEntry fill in the attribute
    1337             :          * information we need.
    1338             :          */
    1339      217314 :         attnum++;
    1340             : 
    1341      217314 :         attname = entry->colname;
    1342      217314 :         typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
    1343             : 
    1344      217314 :         aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
    1345      217314 :         if (aclresult != ACLCHECK_OK)
    1346          42 :             aclcheck_error_type(aclresult, atttypid);
    1347             : 
    1348      217272 :         attcollation = GetColumnDefCollation(NULL, entry, atttypid);
    1349      217272 :         attdim = list_length(entry->typeName->arrayBounds);
    1350      217272 :         if (attdim > PG_INT16_MAX)
    1351           0 :             ereport(ERROR,
    1352             :                     errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1353             :                     errmsg("too many array dimensions"));
    1354             : 
    1355      217272 :         if (entry->typeName->setof)
    1356           0 :             ereport(ERROR,
    1357             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    1358             :                      errmsg("column \"%s\" cannot be declared SETOF",
    1359             :                             attname)));
    1360             : 
    1361      217272 :         TupleDescInitEntry(desc, attnum, attname,
    1362             :                            atttypid, atttypmod, attdim);
    1363      217272 :         att = TupleDescAttr(desc, attnum - 1);
    1364             : 
    1365             :         /* Override TupleDescInitEntry's settings as requested */
    1366      217272 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
    1367             : 
    1368             :         /* Fill in additional stuff not handled by TupleDescInitEntry */
    1369      217272 :         att->attnotnull = entry->is_not_null;
    1370      217272 :         has_not_null |= entry->is_not_null;
    1371      217272 :         att->attislocal = entry->is_local;
    1372      217272 :         att->attinhcount = entry->inhcount;
    1373      217272 :         att->attidentity = entry->identity;
    1374      217272 :         att->attgenerated = entry->generated;
    1375      217272 :         att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
    1376      217260 :         if (entry->storage)
    1377       22670 :             att->attstorage = entry->storage;
    1378      194590 :         else if (entry->storage_name)
    1379          20 :             att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
    1380             :     }
    1381             : 
    1382       55324 :     if (has_not_null)
    1383             :     {
    1384       12078 :         TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
    1385             : 
    1386       12078 :         constr->has_not_null = true;
    1387       12078 :         constr->has_generated_stored = false;
    1388       12078 :         constr->defval = NULL;
    1389       12078 :         constr->missing = NULL;
    1390       12078 :         constr->num_defval = 0;
    1391       12078 :         constr->check = NULL;
    1392       12078 :         constr->num_check = 0;
    1393       12078 :         desc->constr = constr;
    1394             :     }
    1395             :     else
    1396             :     {
    1397       43246 :         desc->constr = NULL;
    1398             :     }
    1399             : 
    1400       55324 :     return desc;
    1401             : }
    1402             : 
    1403             : /*
    1404             :  * Emit the right error or warning message for a "DROP" command issued on a
    1405             :  * non-existent relation
    1406             :  */
    1407             : static void
    1408        1080 : DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
    1409             : {
    1410             :     const struct dropmsgstrings *rentry;
    1411             : 
    1412        1200 :     if (rel->schemaname != NULL &&
    1413         120 :         !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
    1414             :     {
    1415          42 :         if (!missing_ok)
    1416             :         {
    1417           0 :             ereport(ERROR,
    1418             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
    1419             :                      errmsg("schema \"%s\" does not exist", rel->schemaname)));
    1420             :         }
    1421             :         else
    1422             :         {
    1423          42 :             ereport(NOTICE,
    1424             :                     (errmsg("schema \"%s\" does not exist, skipping",
    1425             :                             rel->schemaname)));
    1426             :         }
    1427          42 :         return;
    1428             :     }
    1429             : 
    1430        1358 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
    1431             :     {
    1432        1358 :         if (rentry->kind == rightkind)
    1433             :         {
    1434        1038 :             if (!missing_ok)
    1435             :             {
    1436         132 :                 ereport(ERROR,
    1437             :                         (errcode(rentry->nonexistent_code),
    1438             :                          errmsg(rentry->nonexistent_msg, rel->relname)));
    1439             :             }
    1440             :             else
    1441             :             {
    1442         906 :                 ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
    1443         906 :                 break;
    1444             :             }
    1445             :         }
    1446             :     }
    1447             : 
    1448             :     Assert(rentry->kind != '\0');    /* Should be impossible */
    1449             : }
    1450             : 
    1451             : /*
    1452             :  * Emit the right error message for a "DROP" command issued on a
    1453             :  * relation of the wrong type
    1454             :  */
    1455             : static void
    1456           0 : DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
    1457             : {
    1458             :     const struct dropmsgstrings *rentry;
    1459             :     const struct dropmsgstrings *wentry;
    1460             : 
    1461           0 :     for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
    1462           0 :         if (rentry->kind == rightkind)
    1463           0 :             break;
    1464             :     Assert(rentry->kind != '\0');
    1465             : 
    1466           0 :     for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
    1467           0 :         if (wentry->kind == wrongkind)
    1468           0 :             break;
    1469             :     /* wrongkind could be something we don't have in our table... */
    1470             : 
    1471           0 :     ereport(ERROR,
    1472             :             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1473             :              errmsg(rentry->nota_msg, relname),
    1474             :              (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
    1475             : }
    1476             : 
    1477             : /*
    1478             :  * RemoveRelations
    1479             :  *      Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
    1480             :  *      DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
    1481             :  */
    1482             : void
    1483       16152 : RemoveRelations(DropStmt *drop)
    1484             : {
    1485             :     ObjectAddresses *objects;
    1486             :     char        relkind;
    1487             :     ListCell   *cell;
    1488       16152 :     int         flags = 0;
    1489       16152 :     LOCKMODE    lockmode = AccessExclusiveLock;
    1490             : 
    1491             :     /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
    1492       16152 :     if (drop->concurrent)
    1493             :     {
    1494             :         /*
    1495             :          * Note that for temporary relations this lock may get upgraded later
    1496             :          * on, but as no other session can access a temporary relation, this
    1497             :          * is actually fine.
    1498             :          */
    1499         134 :         lockmode = ShareUpdateExclusiveLock;
    1500             :         Assert(drop->removeType == OBJECT_INDEX);
    1501         134 :         if (list_length(drop->objects) != 1)
    1502           6 :             ereport(ERROR,
    1503             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1504             :                      errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
    1505         128 :         if (drop->behavior == DROP_CASCADE)
    1506           0 :             ereport(ERROR,
    1507             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1508             :                      errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
    1509             :     }
    1510             : 
    1511             :     /*
    1512             :      * First we identify all the relations, then we delete them in a single
    1513             :      * performMultipleDeletions() call.  This is to avoid unwanted DROP
    1514             :      * RESTRICT errors if one of the relations depends on another.
    1515             :      */
    1516             : 
    1517             :     /* Determine required relkind */
    1518       16146 :     switch (drop->removeType)
    1519             :     {
    1520       14048 :         case OBJECT_TABLE:
    1521       14048 :             relkind = RELKIND_RELATION;
    1522       14048 :             break;
    1523             : 
    1524         778 :         case OBJECT_INDEX:
    1525         778 :             relkind = RELKIND_INDEX;
    1526         778 :             break;
    1527             : 
    1528         172 :         case OBJECT_SEQUENCE:
    1529         172 :             relkind = RELKIND_SEQUENCE;
    1530         172 :             break;
    1531             : 
    1532         880 :         case OBJECT_VIEW:
    1533         880 :             relkind = RELKIND_VIEW;
    1534         880 :             break;
    1535             : 
    1536         120 :         case OBJECT_MATVIEW:
    1537         120 :             relkind = RELKIND_MATVIEW;
    1538         120 :             break;
    1539             : 
    1540         148 :         case OBJECT_FOREIGN_TABLE:
    1541         148 :             relkind = RELKIND_FOREIGN_TABLE;
    1542         148 :             break;
    1543             : 
    1544           0 :         default:
    1545           0 :             elog(ERROR, "unrecognized drop object type: %d",
    1546             :                  (int) drop->removeType);
    1547             :             relkind = 0;        /* keep compiler quiet */
    1548             :             break;
    1549             :     }
    1550             : 
    1551             :     /* Lock and validate each relation; build a list of object addresses */
    1552       16146 :     objects = new_object_addresses();
    1553             : 
    1554       35774 :     foreach(cell, drop->objects)
    1555             :     {
    1556       19786 :         RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
    1557             :         Oid         relOid;
    1558             :         ObjectAddress obj;
    1559             :         struct DropRelationCallbackState state;
    1560             : 
    1561             :         /*
    1562             :          * These next few steps are a great deal like relation_openrv, but we
    1563             :          * don't bother building a relcache entry since we don't need it.
    1564             :          *
    1565             :          * Check for shared-cache-inval messages before trying to access the
    1566             :          * relation.  This is needed to cover the case where the name
    1567             :          * identifies a rel that has been dropped and recreated since the
    1568             :          * start of our transaction: if we don't flush the old syscache entry,
    1569             :          * then we'll latch onto that entry and suffer an error later.
    1570             :          */
    1571       19786 :         AcceptInvalidationMessages();
    1572             : 
    1573             :         /* Look up the appropriate relation using namespace search. */
    1574       19786 :         state.expected_relkind = relkind;
    1575       39572 :         state.heap_lockmode = drop->concurrent ?
    1576       19786 :             ShareUpdateExclusiveLock : AccessExclusiveLock;
    1577             :         /* We must initialize these fields to show that no locks are held: */
    1578       19786 :         state.heapOid = InvalidOid;
    1579       19786 :         state.partParentOid = InvalidOid;
    1580             : 
    1581       19786 :         relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
    1582             :                                           RangeVarCallbackForDropRelation,
    1583             :                                           (void *) &state);
    1584             : 
    1585             :         /* Not there? */
    1586       19766 :         if (!OidIsValid(relOid))
    1587             :         {
    1588        1080 :             DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
    1589         948 :             continue;
    1590             :         }
    1591             : 
    1592             :         /*
    1593             :          * Decide if concurrent mode needs to be used here or not.  The
    1594             :          * callback retrieved the rel's persistence for us.
    1595             :          */
    1596       18686 :         if (drop->concurrent &&
    1597         122 :             state.actual_relpersistence != RELPERSISTENCE_TEMP)
    1598             :         {
    1599             :             Assert(list_length(drop->objects) == 1 &&
    1600             :                    drop->removeType == OBJECT_INDEX);
    1601         104 :             flags |= PERFORM_DELETION_CONCURRENTLY;
    1602             :         }
    1603             : 
    1604             :         /*
    1605             :          * Concurrent index drop cannot be used with partitioned indexes,
    1606             :          * either.
    1607             :          */
    1608       18686 :         if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
    1609         104 :             state.actual_relkind == RELKIND_PARTITIONED_INDEX)
    1610           6 :             ereport(ERROR,
    1611             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1612             :                      errmsg("cannot drop partitioned index \"%s\" concurrently",
    1613             :                             rel->relname)));
    1614             : 
    1615             :         /*
    1616             :          * If we're told to drop a partitioned index, we must acquire lock on
    1617             :          * all the children of its parent partitioned table before proceeding.
    1618             :          * Otherwise we'd try to lock the child index partitions before their
    1619             :          * tables, leading to potential deadlock against other sessions that
    1620             :          * will lock those objects in the other order.
    1621             :          */
    1622       18680 :         if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
    1623          70 :             (void) find_all_inheritors(state.heapOid,
    1624             :                                        state.heap_lockmode,
    1625             :                                        NULL);
    1626             : 
    1627             :         /* OK, we're ready to delete this one */
    1628       18680 :         obj.classId = RelationRelationId;
    1629       18680 :         obj.objectId = relOid;
    1630       18680 :         obj.objectSubId = 0;
    1631             : 
    1632       18680 :         add_exact_object_address(&obj, objects);
    1633             :     }
    1634             : 
    1635       15988 :     performMultipleDeletions(objects, drop->behavior, flags);
    1636             : 
    1637       15852 :     free_object_addresses(objects);
    1638       15852 : }
    1639             : 
    1640             : /*
    1641             :  * Before acquiring a table lock, check whether we have sufficient rights.
    1642             :  * In the case of DROP INDEX, also try to lock the table before the index.
    1643             :  * Also, if the table to be dropped is a partition, we try to lock the parent
    1644             :  * first.
    1645             :  */
    1646             : static void
    1647       19966 : RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
    1648             :                                 void *arg)
    1649             : {
    1650             :     HeapTuple   tuple;
    1651             :     struct DropRelationCallbackState *state;
    1652             :     char        expected_relkind;
    1653             :     bool        is_partition;
    1654             :     Form_pg_class classform;
    1655             :     LOCKMODE    heap_lockmode;
    1656       19966 :     bool        invalid_system_index = false;
    1657             : 
    1658       19966 :     state = (struct DropRelationCallbackState *) arg;
    1659       19966 :     heap_lockmode = state->heap_lockmode;
    1660             : 
    1661             :     /*
    1662             :      * If we previously locked some other index's heap, and the name we're
    1663             :      * looking up no longer refers to that relation, release the now-useless
    1664             :      * lock.
    1665             :      */
    1666       19966 :     if (relOid != oldRelOid && OidIsValid(state->heapOid))
    1667             :     {
    1668           0 :         UnlockRelationOid(state->heapOid, heap_lockmode);
    1669           0 :         state->heapOid = InvalidOid;
    1670             :     }
    1671             : 
    1672             :     /*
    1673             :      * Similarly, if we previously locked some other partition's heap, and the
    1674             :      * name we're looking up no longer refers to that relation, release the
    1675             :      * now-useless lock.
    1676             :      */
    1677       19966 :     if (relOid != oldRelOid && OidIsValid(state->partParentOid))
    1678             :     {
    1679           0 :         UnlockRelationOid(state->partParentOid, AccessExclusiveLock);
    1680           0 :         state->partParentOid = InvalidOid;
    1681             :     }
    1682             : 
    1683             :     /* Didn't find a relation, so no need for locking or permission checks. */
    1684       19966 :     if (!OidIsValid(relOid))
    1685        1086 :         return;
    1686             : 
    1687       18880 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
    1688       18880 :     if (!HeapTupleIsValid(tuple))
    1689           0 :         return;                 /* concurrently dropped, so nothing to do */
    1690       18880 :     classform = (Form_pg_class) GETSTRUCT(tuple);
    1691       18880 :     is_partition = classform->relispartition;
    1692             : 
    1693             :     /* Pass back some data to save lookups in RemoveRelations */
    1694       18880 :     state->actual_relkind = classform->relkind;
    1695       18880 :     state->actual_relpersistence = classform->relpersistence;
    1696             : 
    1697             :     /*
    1698             :      * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
    1699             :      * but RemoveRelations() can only pass one relkind for a given relation.
    1700             :      * It chooses RELKIND_RELATION for both regular and partitioned tables.
    1701             :      * That means we must be careful before giving the wrong type error when
    1702             :      * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
    1703             :      * exists with indexes.
    1704             :      */
    1705       18880 :     if (classform->relkind == RELKIND_PARTITIONED_TABLE)
    1706        2956 :         expected_relkind = RELKIND_RELATION;
    1707       15924 :     else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
    1708          76 :         expected_relkind = RELKIND_INDEX;
    1709             :     else
    1710       15848 :         expected_relkind = classform->relkind;
    1711             : 
    1712       18880 :     if (state->expected_relkind != expected_relkind)
    1713           0 :         DropErrorMsgWrongType(rel->relname, classform->relkind,
    1714           0 :                               state->expected_relkind);
    1715             : 
    1716             :     /* Allow DROP to either table owner or schema owner */
    1717       18880 :     if (!object_ownercheck(RelationRelationId, relOid, GetUserId()) &&
    1718          18 :         !object_ownercheck(NamespaceRelationId, classform->relnamespace, GetUserId()))
    1719          18 :         aclcheck_error(ACLCHECK_NOT_OWNER,
    1720          18 :                        get_relkind_objtype(classform->relkind),
    1721          18 :                        rel->relname);
    1722             : 
    1723             :     /*
    1724             :      * Check the case of a system index that might have been invalidated by a
    1725             :      * failed concurrent process and allow its drop. For the time being, this
    1726             :      * only concerns indexes of toast relations that became invalid during a
    1727             :      * REINDEX CONCURRENTLY process.
    1728             :      */
    1729       18862 :     if (IsSystemClass(relOid, classform) && classform->relkind == RELKIND_INDEX)
    1730             :     {
    1731             :         HeapTuple   locTuple;
    1732             :         Form_pg_index indexform;
    1733             :         bool        indisvalid;
    1734             : 
    1735           0 :         locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
    1736           0 :         if (!HeapTupleIsValid(locTuple))
    1737             :         {
    1738           0 :             ReleaseSysCache(tuple);
    1739           0 :             return;
    1740             :         }
    1741             : 
    1742           0 :         indexform = (Form_pg_index) GETSTRUCT(locTuple);
    1743           0 :         indisvalid = indexform->indisvalid;
    1744           0 :         ReleaseSysCache(locTuple);
    1745             : 
    1746             :         /* Mark object as being an invalid index of system catalogs */
    1747           0 :         if (!indisvalid)
    1748           0 :             invalid_system_index = true;
    1749             :     }
    1750             : 
    1751             :     /* In the case of an invalid index, it is fine to bypass this check */
    1752       18862 :     if (!invalid_system_index && !allowSystemTableMods && IsSystemClass(relOid, classform))
    1753           2 :         ereport(ERROR,
    1754             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1755             :                  errmsg("permission denied: \"%s\" is a system catalog",
    1756             :                         rel->relname)));
    1757             : 
    1758       18860 :     ReleaseSysCache(tuple);
    1759             : 
    1760             :     /*
    1761             :      * In DROP INDEX, attempt to acquire lock on the parent table before
    1762             :      * locking the index.  index_drop() will need this anyway, and since
    1763             :      * regular queries lock tables before their indexes, we risk deadlock if
    1764             :      * we do it the other way around.  No error if we don't find a pg_index
    1765             :      * entry, though --- the relation may have been dropped.  Note that this
    1766             :      * code will execute for either plain or partitioned indexes.
    1767             :      */
    1768       18860 :     if (expected_relkind == RELKIND_INDEX &&
    1769             :         relOid != oldRelOid)
    1770             :     {
    1771         766 :         state->heapOid = IndexGetRelation(relOid, true);
    1772         766 :         if (OidIsValid(state->heapOid))
    1773         766 :             LockRelationOid(state->heapOid, heap_lockmode);
    1774             :     }
    1775             : 
    1776             :     /*
    1777             :      * Similarly, if the relation is a partition, we must acquire lock on its
    1778             :      * parent before locking the partition.  That's because queries lock the
    1779             :      * parent before its partitions, so we risk deadlock if we do it the other
    1780             :      * way around.
    1781             :      */
    1782       18860 :     if (is_partition && relOid != oldRelOid)
    1783             :     {
    1784         588 :         state->partParentOid = get_partition_parent(relOid, true);
    1785         588 :         if (OidIsValid(state->partParentOid))
    1786         588 :             LockRelationOid(state->partParentOid, AccessExclusiveLock);
    1787             :     }
    1788             : }
    1789             : 
    1790             : /*
    1791             :  * ExecuteTruncate
    1792             :  *      Executes a TRUNCATE command.
    1793             :  *
    1794             :  * This is a multi-relation truncate.  We first open and grab exclusive
    1795             :  * lock on all relations involved, checking permissions and otherwise
    1796             :  * verifying that the relation is OK for truncation.  Note that if relations
    1797             :  * are foreign tables, at this stage, we have not yet checked that their
    1798             :  * foreign data in external data sources are OK for truncation.  These are
    1799             :  * checked when foreign data are actually truncated later.  In CASCADE mode,
    1800             :  * relations having FK references to the targeted relations are automatically
    1801             :  * added to the group; in RESTRICT mode, we check that all FK references are
    1802             :  * internal to the group that's being truncated.  Finally all the relations
    1803             :  * are truncated and reindexed.
    1804             :  */
    1805             : void
    1806        1444 : ExecuteTruncate(TruncateStmt *stmt)
    1807             : {
    1808        1444 :     List       *rels = NIL;
    1809        1444 :     List       *relids = NIL;
    1810        1444 :     List       *relids_logged = NIL;
    1811             :     ListCell   *cell;
    1812             : 
    1813             :     /*
    1814             :      * Open, exclusive-lock, and check all the explicitly-specified relations
    1815             :      */
    1816        3114 :     foreach(cell, stmt->relations)
    1817             :     {
    1818        1718 :         RangeVar   *rv = lfirst(cell);
    1819             :         Relation    rel;
    1820        1718 :         bool        recurse = rv->inh;
    1821             :         Oid         myrelid;
    1822        1718 :         LOCKMODE    lockmode = AccessExclusiveLock;
    1823             : 
    1824        1718 :         myrelid = RangeVarGetRelidExtended(rv, lockmode,
    1825             :                                            0, RangeVarCallbackForTruncate,
    1826             :                                            NULL);
    1827             : 
    1828             :         /* don't throw error for "TRUNCATE foo, foo" */
    1829        1682 :         if (list_member_oid(relids, myrelid))
    1830           2 :             continue;
    1831             : 
    1832             :         /* open the relation, we already hold a lock on it */
    1833        1680 :         rel = table_open(myrelid, NoLock);
    1834             : 
    1835             :         /*
    1836             :          * RangeVarGetRelidExtended() has done most checks with its callback,
    1837             :          * but other checks with the now-opened Relation remain.
    1838             :          */
    1839        1680 :         truncate_check_activity(rel);
    1840             : 
    1841        1680 :         rels = lappend(rels, rel);
    1842        1680 :         relids = lappend_oid(relids, myrelid);
    1843             : 
    1844             :         /* Log this relation only if needed for logical decoding */
    1845        1680 :         if (RelationIsLogicallyLogged(rel))
    1846          64 :             relids_logged = lappend_oid(relids_logged, myrelid);
    1847             : 
    1848        1680 :         if (recurse)
    1849             :         {
    1850             :             ListCell   *child;
    1851             :             List       *children;
    1852             : 
    1853        1618 :             children = find_all_inheritors(myrelid, lockmode, NULL);
    1854             : 
    1855        4968 :             foreach(child, children)
    1856             :             {
    1857        3350 :                 Oid         childrelid = lfirst_oid(child);
    1858             : 
    1859        3350 :                 if (list_member_oid(relids, childrelid))
    1860        1618 :                     continue;
    1861             : 
    1862             :                 /* find_all_inheritors already got lock */
    1863        1732 :                 rel = table_open(childrelid, NoLock);
    1864             : 
    1865             :                 /*
    1866             :                  * It is possible that the parent table has children that are
    1867             :                  * temp tables of other backends.  We cannot safely access
    1868             :                  * such tables (because of buffering issues), and the best
    1869             :                  * thing to do is to silently ignore them.  Note that this
    1870             :                  * check is the same as one of the checks done in
    1871             :                  * truncate_check_activity() called below, still it is kept
    1872             :                  * here for simplicity.
    1873             :                  */
    1874        1732 :                 if (RELATION_IS_OTHER_TEMP(rel))
    1875             :                 {
    1876           8 :                     table_close(rel, lockmode);
    1877           8 :                     continue;
    1878             :                 }
    1879             : 
    1880             :                 /*
    1881             :                  * Inherited TRUNCATE commands perform access permission
    1882             :                  * checks on the parent table only. So we skip checking the
    1883             :                  * children's permissions and don't call
    1884             :                  * truncate_check_perms() here.
    1885             :                  */
    1886        1724 :                 truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
    1887        1724 :                 truncate_check_activity(rel);
    1888             : 
    1889        1724 :                 rels = lappend(rels, rel);
    1890        1724 :                 relids = lappend_oid(relids, childrelid);
    1891             : 
    1892             :                 /* Log this relation only if needed for logical decoding */
    1893        1724 :                 if (RelationIsLogicallyLogged(rel))
    1894          22 :                     relids_logged = lappend_oid(relids_logged, childrelid);
    1895             :             }
    1896             :         }
    1897          62 :         else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    1898          12 :             ereport(ERROR,
    1899             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1900             :                      errmsg("cannot truncate only a partitioned table"),
    1901             :                      errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
    1902             :     }
    1903             : 
    1904        1396 :     ExecuteTruncateGuts(rels, relids, relids_logged,
    1905        1396 :                         stmt->behavior, stmt->restart_seqs, false);
    1906             : 
    1907             :     /* And close the rels */
    1908        4552 :     foreach(cell, rels)
    1909             :     {
    1910        3238 :         Relation    rel = (Relation) lfirst(cell);
    1911             : 
    1912        3238 :         table_close(rel, NoLock);
    1913             :     }
    1914        1314 : }
    1915             : 
    1916             : /*
    1917             :  * ExecuteTruncateGuts
    1918             :  *
    1919             :  * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
    1920             :  * command (see above) as well as replication subscribers that execute a
    1921             :  * replicated TRUNCATE action.
    1922             :  *
    1923             :  * explicit_rels is the list of Relations to truncate that the command
    1924             :  * specified.  relids is the list of Oids corresponding to explicit_rels.
    1925             :  * relids_logged is the list of Oids (a subset of relids) that require
    1926             :  * WAL-logging.  This is all a bit redundant, but the existing callers have
    1927             :  * this information handy in this form.
    1928             :  */
    1929             : void
    1930        1434 : ExecuteTruncateGuts(List *explicit_rels,
    1931             :                     List *relids,
    1932             :                     List *relids_logged,
    1933             :                     DropBehavior behavior, bool restart_seqs,
    1934             :                     bool run_as_table_owner)
    1935             : {
    1936             :     List       *rels;
    1937        1434 :     List       *seq_relids = NIL;
    1938        1434 :     HTAB       *ft_htab = NULL;
    1939             :     EState     *estate;
    1940             :     ResultRelInfo *resultRelInfos;
    1941             :     ResultRelInfo *resultRelInfo;
    1942             :     SubTransactionId mySubid;
    1943             :     ListCell   *cell;
    1944             :     Oid        *logrelids;
    1945             : 
    1946             :     /*
    1947             :      * Check the explicitly-specified relations.
    1948             :      *
    1949             :      * In CASCADE mode, suck in all referencing relations as well.  This
    1950             :      * requires multiple iterations to find indirectly-dependent relations. At
    1951             :      * each phase, we need to exclusive-lock new rels before looking for their
    1952             :      * dependencies, else we might miss something.  Also, we check each rel as
    1953             :      * soon as we open it, to avoid a faux pas such as holding lock for a long
    1954             :      * time on a rel we have no permissions for.
    1955             :      */
    1956        1434 :     rels = list_copy(explicit_rels);
    1957        1434 :     if (behavior == DROP_CASCADE)
    1958             :     {
    1959             :         for (;;)
    1960          40 :         {
    1961             :             List       *newrelids;
    1962             : 
    1963          80 :             newrelids = heap_truncate_find_FKs(relids);
    1964          80 :             if (newrelids == NIL)
    1965          40 :                 break;          /* nothing else to add */
    1966             : 
    1967         134 :             foreach(cell, newrelids)
    1968             :             {
    1969          94 :                 Oid         relid = lfirst_oid(cell);
    1970             :                 Relation    rel;
    1971             : 
    1972          94 :                 rel = table_open(relid, AccessExclusiveLock);
    1973          94 :                 ereport(NOTICE,
    1974             :                         (errmsg("truncate cascades to table \"%s\"",
    1975             :                                 RelationGetRelationName(rel))));
    1976          94 :                 truncate_check_rel(relid, rel->rd_rel);
    1977          94 :                 truncate_check_perms(relid, rel->rd_rel);
    1978          94 :                 truncate_check_activity(rel);
    1979          94 :                 rels = lappend(rels, rel);
    1980          94 :                 relids = lappend_oid(relids, relid);
    1981             : 
    1982             :                 /* Log this relation only if needed for logical decoding */
    1983          94 :                 if (RelationIsLogicallyLogged(rel))
    1984           0 :                     relids_logged = lappend_oid(relids_logged, relid);
    1985             :             }
    1986             :         }
    1987             :     }
    1988             : 
    1989             :     /*
    1990             :      * Check foreign key references.  In CASCADE mode, this should be
    1991             :      * unnecessary since we just pulled in all the references; but as a
    1992             :      * cross-check, do it anyway if in an Assert-enabled build.
    1993             :      */
    1994             : #ifdef USE_ASSERT_CHECKING
    1995             :     heap_truncate_check_FKs(rels, false);
    1996             : #else
    1997        1434 :     if (behavior == DROP_RESTRICT)
    1998        1394 :         heap_truncate_check_FKs(rels, false);
    1999             : #endif
    2000             : 
    2001             :     /*
    2002             :      * If we are asked to restart sequences, find all the sequences, lock them
    2003             :      * (we need AccessExclusiveLock for ResetSequence), and check permissions.
    2004             :      * We want to do this early since it's pointless to do all the truncation
    2005             :      * work only to fail on sequence permissions.
    2006             :      */
    2007        1360 :     if (restart_seqs)
    2008             :     {
    2009          52 :         foreach(cell, rels)
    2010             :         {
    2011          26 :             Relation    rel = (Relation) lfirst(cell);
    2012          26 :             List       *seqlist = getOwnedSequences(RelationGetRelid(rel));
    2013             :             ListCell   *seqcell;
    2014             : 
    2015          62 :             foreach(seqcell, seqlist)
    2016             :             {
    2017          36 :                 Oid         seq_relid = lfirst_oid(seqcell);
    2018             :                 Relation    seq_rel;
    2019             : 
    2020          36 :                 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
    2021             : 
    2022             :                 /* This check must match AlterSequence! */
    2023          36 :                 if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
    2024           0 :                     aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SEQUENCE,
    2025           0 :                                    RelationGetRelationName(seq_rel));
    2026             : 
    2027          36 :                 seq_relids = lappend_oid(seq_relids, seq_relid);
    2028             : 
    2029          36 :                 relation_close(seq_rel, NoLock);
    2030             :             }
    2031             :         }
    2032             :     }
    2033             : 
    2034             :     /* Prepare to catch AFTER triggers. */
    2035        1360 :     AfterTriggerBeginQuery();
    2036             : 
    2037             :     /*
    2038             :      * To fire triggers, we'll need an EState as well as a ResultRelInfo for
    2039             :      * each relation.  We don't need to call ExecOpenIndices, though.
    2040             :      *
    2041             :      * We put the ResultRelInfos in the es_opened_result_relations list, even
    2042             :      * though we don't have a range table and don't populate the
    2043             :      * es_result_relations array.  That's a bit bogus, but it's enough to make
    2044             :      * ExecGetTriggerResultRel() find them.
    2045             :      */
    2046        1360 :     estate = CreateExecutorState();
    2047             :     resultRelInfos = (ResultRelInfo *)
    2048        1360 :         palloc(list_length(rels) * sizeof(ResultRelInfo));
    2049        1360 :     resultRelInfo = resultRelInfos;
    2050        4770 :     foreach(cell, rels)
    2051             :     {
    2052        3410 :         Relation    rel = (Relation) lfirst(cell);
    2053             : 
    2054        3410 :         InitResultRelInfo(resultRelInfo,
    2055             :                           rel,
    2056             :                           0,    /* dummy rangetable index */
    2057             :                           NULL,
    2058             :                           0);
    2059        3410 :         estate->es_opened_result_relations =
    2060        3410 :             lappend(estate->es_opened_result_relations, resultRelInfo);
    2061        3410 :         resultRelInfo++;
    2062             :     }
    2063             : 
    2064             :     /*
    2065             :      * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
    2066             :      * truncating (this is because one of them might throw an error). Also, if
    2067             :      * we were to allow them to prevent statement execution, that would need
    2068             :      * to be handled here.
    2069             :      */
    2070        1360 :     resultRelInfo = resultRelInfos;
    2071        4770 :     foreach(cell, rels)
    2072             :     {
    2073             :         UserContext ucxt;
    2074             : 
    2075        3410 :         if (run_as_table_owner)
    2076          70 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
    2077             :                                   &ucxt);
    2078        3410 :         ExecBSTruncateTriggers(estate, resultRelInfo);
    2079        3410 :         if (run_as_table_owner)
    2080          70 :             RestoreUserContext(&ucxt);
    2081        3410 :         resultRelInfo++;
    2082             :     }
    2083             : 
    2084             :     /*
    2085             :      * OK, truncate each table.
    2086             :      */
    2087        1360 :     mySubid = GetCurrentSubTransactionId();
    2088             : 
    2089        4770 :     foreach(cell, rels)
    2090             :     {
    2091        3410 :         Relation    rel = (Relation) lfirst(cell);
    2092             : 
    2093             :         /* Skip partitioned tables as there is nothing to do */
    2094        3410 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    2095         692 :             continue;
    2096             : 
    2097             :         /*
    2098             :          * Build the lists of foreign tables belonging to each foreign server
    2099             :          * and pass each list to the foreign data wrapper's callback function,
    2100             :          * so that each server can truncate its all foreign tables in bulk.
    2101             :          * Each list is saved as a single entry in a hash table that uses the
    2102             :          * server OID as lookup key.
    2103             :          */
    2104        2718 :         if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    2105             :         {
    2106          34 :             Oid         serverid = GetForeignServerIdByRelId(RelationGetRelid(rel));
    2107             :             bool        found;
    2108             :             ForeignTruncateInfo *ft_info;
    2109             : 
    2110             :             /* First time through, initialize hashtable for foreign tables */
    2111          34 :             if (!ft_htab)
    2112             :             {
    2113             :                 HASHCTL     hctl;
    2114             : 
    2115          30 :                 memset(&hctl, 0, sizeof(HASHCTL));
    2116          30 :                 hctl.keysize = sizeof(Oid);
    2117          30 :                 hctl.entrysize = sizeof(ForeignTruncateInfo);
    2118          30 :                 hctl.hcxt = CurrentMemoryContext;
    2119             : 
    2120          30 :                 ft_htab = hash_create("TRUNCATE for Foreign Tables",
    2121             :                                       32,   /* start small and extend */
    2122             :                                       &hctl,
    2123             :                                       HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
    2124             :             }
    2125             : 
    2126             :             /* Find or create cached entry for the foreign table */
    2127          34 :             ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
    2128          34 :             if (!found)
    2129          30 :                 ft_info->rels = NIL;
    2130             : 
    2131             :             /*
    2132             :              * Save the foreign table in the entry of the server that the
    2133             :              * foreign table belongs to.
    2134             :              */
    2135          34 :             ft_info->rels = lappend(ft_info->rels, rel);
    2136          34 :             continue;
    2137             :         }
    2138             : 
    2139             :         /*
    2140             :          * Normally, we need a transaction-safe truncation here.  However, if
    2141             :          * the table was either created in the current (sub)transaction or has
    2142             :          * a new relfilenumber in the current (sub)transaction, then we can
    2143             :          * just truncate it in-place, because a rollback would cause the whole
    2144             :          * table or the current physical file to be thrown away anyway.
    2145             :          */
    2146        2684 :         if (rel->rd_createSubid == mySubid ||
    2147        2658 :             rel->rd_newRelfilelocatorSubid == mySubid)
    2148             :         {
    2149             :             /* Immediate, non-rollbackable truncation is OK */
    2150          90 :             heap_truncate_one_rel(rel);
    2151             :         }
    2152             :         else
    2153             :         {
    2154             :             Oid         heap_relid;
    2155             :             Oid         toast_relid;
    2156        2594 :             ReindexParams reindex_params = {0};
    2157             : 
    2158             :             /*
    2159             :              * This effectively deletes all rows in the table, and may be done
    2160             :              * in a serializable transaction.  In that case we must record a
    2161             :              * rw-conflict in to this transaction from each transaction
    2162             :              * holding a predicate lock on the table.
    2163             :              */
    2164        2594 :             CheckTableForSerializableConflictIn(rel);
    2165             : 
    2166             :             /*
    2167             :              * Need the full transaction-safe pushups.
    2168             :              *
    2169             :              * Create a new empty storage file for the relation, and assign it
    2170             :              * as the relfilenumber value. The old storage file is scheduled
    2171             :              * for deletion at commit.
    2172             :              */
    2173        2594 :             RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
    2174             : 
    2175        2594 :             heap_relid = RelationGetRelid(rel);
    2176             : 
    2177             :             /*
    2178             :              * The same for the toast table, if any.
    2179             :              */
    2180        2594 :             toast_relid = rel->rd_rel->reltoastrelid;
    2181        2594 :             if (OidIsValid(toast_relid))
    2182             :             {
    2183        1596 :                 Relation    toastrel = relation_open(toast_relid,
    2184             :                                                      AccessExclusiveLock);
    2185             : 
    2186        1596 :                 RelationSetNewRelfilenumber(toastrel,
    2187        1596 :                                             toastrel->rd_rel->relpersistence);
    2188        1596 :                 table_close(toastrel, NoLock);
    2189             :             }
    2190             : 
    2191             :             /*
    2192             :              * Reconstruct the indexes to match, and we're done.
    2193             :              */
    2194        2594 :             reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
    2195             :                              &reindex_params);
    2196             :         }
    2197             : 
    2198        2684 :         pgstat_count_truncate(rel);
    2199             :     }
    2200             : 
    2201             :     /* Now go through the hash table, and truncate foreign tables */
    2202        1360 :     if (ft_htab)
    2203             :     {
    2204             :         ForeignTruncateInfo *ft_info;
    2205             :         HASH_SEQ_STATUS seq;
    2206             : 
    2207          30 :         hash_seq_init(&seq, ft_htab);
    2208             : 
    2209          30 :         PG_TRY();
    2210             :         {
    2211          52 :             while ((ft_info = hash_seq_search(&seq)) != NULL)
    2212             :             {
    2213          30 :                 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
    2214             : 
    2215             :                 /* truncate_check_rel() has checked that already */
    2216             :                 Assert(routine->ExecForeignTruncate != NULL);
    2217             : 
    2218          30 :                 routine->ExecForeignTruncate(ft_info->rels,
    2219             :                                              behavior,
    2220             :                                              restart_seqs);
    2221             :             }
    2222             :         }
    2223           8 :         PG_FINALLY();
    2224             :         {
    2225          30 :             hash_destroy(ft_htab);
    2226             :         }
    2227          30 :         PG_END_TRY();
    2228             :     }
    2229             : 
    2230             :     /*
    2231             :      * Restart owned sequences if we were asked to.
    2232             :      */
    2233        1388 :     foreach(cell, seq_relids)
    2234             :     {
    2235          36 :         Oid         seq_relid = lfirst_oid(cell);
    2236             : 
    2237          36 :         ResetSequence(seq_relid);
    2238             :     }
    2239             : 
    2240             :     /*
    2241             :      * Write a WAL record to allow this set of actions to be logically
    2242             :      * decoded.
    2243             :      *
    2244             :      * Assemble an array of relids so we can write a single WAL record for the
    2245             :      * whole action.
    2246             :      */
    2247        1352 :     if (relids_logged != NIL)
    2248             :     {
    2249             :         xl_heap_truncate xlrec;
    2250          50 :         int         i = 0;
    2251             : 
    2252             :         /* should only get here if wal_level >= logical */
    2253             :         Assert(XLogLogicalInfoActive());
    2254             : 
    2255          50 :         logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
    2256         136 :         foreach(cell, relids_logged)
    2257          86 :             logrelids[i++] = lfirst_oid(cell);
    2258             : 
    2259          50 :         xlrec.dbId = MyDatabaseId;
    2260          50 :         xlrec.nrelids = list_length(relids_logged);
    2261          50 :         xlrec.flags = 0;
    2262          50 :         if (behavior == DROP_CASCADE)
    2263           2 :             xlrec.flags |= XLH_TRUNCATE_CASCADE;
    2264          50 :         if (restart_seqs)
    2265           4 :             xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
    2266             : 
    2267          50 :         XLogBeginInsert();
    2268          50 :         XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
    2269          50 :         XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
    2270             : 
    2271          50 :         XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
    2272             : 
    2273          50 :         (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
    2274             :     }
    2275             : 
    2276             :     /*
    2277             :      * Process all AFTER STATEMENT TRUNCATE triggers.
    2278             :      */
    2279        1352 :     resultRelInfo = resultRelInfos;
    2280        4754 :     foreach(cell, rels)
    2281             :     {
    2282             :         UserContext ucxt;
    2283             : 
    2284        3402 :         if (run_as_table_owner)
    2285          70 :             SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
    2286             :                                   &ucxt);
    2287        3402 :         ExecASTruncateTriggers(estate, resultRelInfo);
    2288        3402 :         if (run_as_table_owner)
    2289          70 :             RestoreUserContext(&ucxt);
    2290        3402 :         resultRelInfo++;
    2291             :     }
    2292             : 
    2293             :     /* Handle queued AFTER triggers */
    2294        1352 :     AfterTriggerEndQuery(estate);
    2295             : 
    2296             :     /* We can clean up the EState now */
    2297        1352 :     FreeExecutorState(estate);
    2298             : 
    2299             :     /*
    2300             :      * Close any rels opened by CASCADE (can't do this while EState still
    2301             :      * holds refs)
    2302             :      */
    2303        1352 :     rels = list_difference_ptr(rels, explicit_rels);
    2304        1446 :     foreach(cell, rels)
    2305             :     {
    2306          94 :         Relation    rel = (Relation) lfirst(cell);
    2307             : 
    2308          94 :         table_close(rel, NoLock);
    2309             :     }
    2310        1352 : }
    2311             : 
    2312             : /*
    2313             :  * Check that a given relation is safe to truncate.  Subroutine for
    2314             :  * ExecuteTruncate() and RangeVarCallbackForTruncate().
    2315             :  */
    2316             : static void
    2317        3606 : truncate_check_rel(Oid relid, Form_pg_class reltuple)
    2318             : {
    2319        3606 :     char       *relname = NameStr(reltuple->relname);
    2320             : 
    2321             :     /*
    2322             :      * Only allow truncate on regular tables, foreign tables using foreign
    2323             :      * data wrappers supporting TRUNCATE and partitioned tables (although, the
    2324             :      * latter are only being included here for the following checks; no
    2325             :      * physical truncation will occur in their case.).
    2326             :      */
    2327        3606 :     if (reltuple->relkind == RELKIND_FOREIGN_TABLE)
    2328             :     {
    2329          36 :         Oid         serverid = GetForeignServerIdByRelId(relid);
    2330          36 :         FdwRoutine *fdwroutine = GetFdwRoutineByServerId(serverid);
    2331             : 
    2332          36 :         if (!fdwroutine->ExecForeignTruncate)
    2333           2 :             ereport(ERROR,
    2334             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2335             :                      errmsg("cannot truncate foreign table \"%s\"",
    2336             :                             relname)));
    2337             :     }
    2338        3570 :     else if (reltuple->relkind != RELKIND_RELATION &&
    2339         712 :              reltuple->relkind != RELKIND_PARTITIONED_TABLE)
    2340           0 :         ereport(ERROR,
    2341             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2342             :                  errmsg("\"%s\" is not a table", relname)));
    2343             : 
    2344             :     /*
    2345             :      * Most system catalogs can't be truncated at all, or at least not unless
    2346             :      * allow_system_table_mods=on. As an exception, however, we allow
    2347             :      * pg_largeobject to be truncated as part of pg_upgrade, because we need
    2348             :      * to change its relfilenode to match the old cluster, and allowing a
    2349             :      * TRUNCATE command to be executed is the easiest way of doing that.
    2350             :      */
    2351        3604 :     if (!allowSystemTableMods && IsSystemClass(relid, reltuple)
    2352          22 :         && (!IsBinaryUpgrade || relid != LargeObjectRelationId))
    2353           2 :         ereport(ERROR,
    2354             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2355             :                  errmsg("permission denied: \"%s\" is a system catalog",
    2356             :                         relname)));
    2357             : 
    2358        3602 :     InvokeObjectTruncateHook(relid);
    2359        3602 : }
    2360             : 
    2361             : /*
    2362             :  * Check that current user has the permission to truncate given relation.
    2363             :  */
    2364             : static void
    2365        1878 : truncate_check_perms(Oid relid, Form_pg_class reltuple)
    2366             : {
    2367        1878 :     char       *relname = NameStr(reltuple->relname);
    2368             :     AclResult   aclresult;
    2369             : 
    2370             :     /* Permissions checks */
    2371        1878 :     aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
    2372        1878 :     if (aclresult != ACLCHECK_OK)
    2373          32 :         aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
    2374             :                        relname);
    2375        1846 : }
    2376             : 
    2377             : /*
    2378             :  * Set of extra sanity checks to check if a given relation is safe to
    2379             :  * truncate.  This is split with truncate_check_rel() as
    2380             :  * RangeVarCallbackForTruncate() cannot open a Relation yet.
    2381             :  */
    2382             : static void
    2383        3498 : truncate_check_activity(Relation rel)
    2384             : {
    2385             :     /*
    2386             :      * Don't allow truncate on temp tables of other backends ... their local
    2387             :      * buffer manager is not going to cope.
    2388             :      */
    2389        3498 :     if (RELATION_IS_OTHER_TEMP(rel))
    2390           0 :         ereport(ERROR,
    2391             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2392             :                  errmsg("cannot truncate temporary tables of other sessions")));
    2393             : 
    2394             :     /*
    2395             :      * Also check for active uses of the relation in the current transaction,
    2396             :      * including open scans and pending AFTER trigger events.
    2397             :      */
    2398        3498 :     CheckTableNotInUse(rel, "TRUNCATE");
    2399        3498 : }
    2400             : 
    2401             : /*
    2402             :  * storage_name
    2403             :  *    returns the name corresponding to a typstorage/attstorage enum value
    2404             :  */
    2405             : static const char *
    2406          24 : storage_name(char c)
    2407             : {
    2408          24 :     switch (c)
    2409             :     {
    2410           0 :         case TYPSTORAGE_PLAIN:
    2411           0 :             return "PLAIN";
    2412           0 :         case TYPSTORAGE_EXTERNAL:
    2413           0 :             return "EXTERNAL";
    2414          12 :         case TYPSTORAGE_EXTENDED:
    2415          12 :             return "EXTENDED";
    2416          12 :         case TYPSTORAGE_MAIN:
    2417          12 :             return "MAIN";
    2418           0 :         default:
    2419           0 :             return "???";
    2420             :     }
    2421             : }
    2422             : 
    2423             : /*----------
    2424             :  * MergeAttributes
    2425             :  *      Returns new schema given initial schema and superclasses.
    2426             :  *
    2427             :  * Input arguments:
    2428             :  * 'columns' is the column/attribute definition for the table. (It's a list
    2429             :  *      of ColumnDef's.) It is destructively changed.
    2430             :  * 'supers' is a list of OIDs of parent relations, already locked by caller.
    2431             :  * 'relpersistence' is the persistence type of the table.
    2432             :  * 'is_partition' tells if the table is a partition.
    2433             :  *
    2434             :  * Output arguments:
    2435             :  * 'supconstr' receives a list of constraints belonging to the parents,
    2436             :  *      updated as necessary to be valid for the child.
    2437             :  * 'supnotnulls' receives a list of CookedConstraints that corresponds to
    2438             :  *      constraints coming from inheritance parents.
    2439             :  *
    2440             :  * Return value:
    2441             :  * Completed schema list.
    2442             :  *
    2443             :  * Notes:
    2444             :  *    The order in which the attributes are inherited is very important.
    2445             :  *    Intuitively, the inherited attributes should come first. If a table
    2446             :  *    inherits from multiple parents, the order of those attributes are
    2447             :  *    according to the order of the parents specified in CREATE TABLE.
    2448             :  *
    2449             :  *    Here's an example:
    2450             :  *
    2451             :  *      create table person (name text, age int4, location point);
    2452             :  *      create table emp (salary int4, manager text) inherits(person);
    2453             :  *      create table student (gpa float8) inherits (person);
    2454             :  *      create table stud_emp (percent int4) inherits (emp, student);
    2455             :  *
    2456             :  *    The order of the attributes of stud_emp is:
    2457             :  *
    2458             :  *                          person {1:name, 2:age, 3:location}
    2459             :  *                          /    \
    2460             :  *             {6:gpa}  student   emp {4:salary, 5:manager}
    2461             :  *                          \    /
    2462             :  *                         stud_emp {7:percent}
    2463             :  *
    2464             :  *     If the same attribute name appears multiple times, then it appears
    2465             :  *     in the result table in the proper location for its first appearance.
    2466             :  *
    2467             :  *     Constraints (including not-null constraints) for the child table
    2468             :  *     are the union of all relevant constraints, from both the child schema
    2469             :  *     and parent tables.  In addition, in legacy inheritance, each column that
    2470             :  *     appears in a primary key in any of the parents also gets a NOT NULL
    2471             :  *     constraint (partitioning doesn't need this, because the PK itself gets
    2472             :  *     inherited.)
    2473             :  *
    2474             :  *     The default value for a child column is defined as:
    2475             :  *      (1) If the child schema specifies a default, that value is used.
    2476             :  *      (2) If neither the child nor any parent specifies a default, then
    2477             :  *          the column will not have a default.
    2478             :  *      (3) If conflicting defaults are inherited from different parents
    2479             :  *          (and not overridden by the child), an error is raised.
    2480             :  *      (4) Otherwise the inherited default is used.
    2481             :  *
    2482             :  *      Note that the default-value infrastructure is used for generated
    2483             :  *      columns' expressions too, so most of the preceding paragraph applies
    2484             :  *      to generation expressions too.  We insist that a child column be
    2485             :  *      generated if and only if its parent(s) are, but it need not have
    2486             :  *      the same generation expression.
    2487             :  *----------
    2488             :  */
    2489             : static List *
    2490       52880 : MergeAttributes(List *columns, const List *supers, char relpersistence,
    2491             :                 bool is_partition, List **supconstr, List **supnotnulls)
    2492             : {
    2493       52880 :     List       *inh_columns = NIL;
    2494       52880 :     List       *constraints = NIL;
    2495       52880 :     List       *nnconstraints = NIL;
    2496       52880 :     bool        have_bogus_defaults = false;
    2497             :     int         child_attno;
    2498             :     static Node bogus_marker = {0}; /* marks conflicting defaults */
    2499       52880 :     List       *saved_columns = NIL;
    2500             :     ListCell   *lc;
    2501             : 
    2502             :     /*
    2503             :      * Check for and reject tables with too many columns. We perform this
    2504             :      * check relatively early for two reasons: (a) we don't run the risk of
    2505             :      * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is
    2506             :      * okay if we're processing <= 1600 columns, but could take minutes to
    2507             :      * execute if the user attempts to create a table with hundreds of
    2508             :      * thousands of columns.
    2509             :      *
    2510             :      * Note that we also need to check that we do not exceed this figure after
    2511             :      * including columns from inherited relations.
    2512             :      */
    2513       52880 :     if (list_length(columns) > MaxHeapAttributeNumber)
    2514           0 :         ereport(ERROR,
    2515             :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    2516             :                  errmsg("tables can have at most %d columns",
    2517             :                         MaxHeapAttributeNumber)));
    2518             : 
    2519             :     /*
    2520             :      * Check for duplicate names in the explicit list of attributes.
    2521             :      *
    2522             :      * Although we might consider merging such entries in the same way that we
    2523             :      * handle name conflicts for inherited attributes, it seems to make more
    2524             :      * sense to assume such conflicts are errors.
    2525             :      *
    2526             :      * We don't use foreach() here because we have two nested loops over the
    2527             :      * columns list, with possible element deletions in the inner one.  If we
    2528             :      * used foreach_delete_current() it could only fix up the state of one of
    2529             :      * the loops, so it seems cleaner to use looping over list indexes for
    2530             :      * both loops.  Note that any deletion will happen beyond where the outer
    2531             :      * loop is, so its index never needs adjustment.
    2532             :      */
    2533      246672 :     for (int coldefpos = 0; coldefpos < list_length(columns); coldefpos++)
    2534             :     {
    2535      193816 :         ColumnDef  *coldef = list_nth_node(ColumnDef, columns, coldefpos);
    2536             : 
    2537      193816 :         if (!is_partition && coldef->typeName == NULL)
    2538             :         {
    2539             :             /*
    2540             :              * Typed table column option that does not belong to a column from
    2541             :              * the type.  This works because the columns from the type come
    2542             :              * first in the list.  (We omit this check for partition column
    2543             :              * lists; those are processed separately below.)
    2544             :              */
    2545           6 :             ereport(ERROR,
    2546             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    2547             :                      errmsg("column \"%s\" does not exist",
    2548             :                             coldef->colname)));
    2549             :         }
    2550             : 
    2551             :         /* restpos scans all entries beyond coldef; incr is in loop body */
    2552     6160484 :         for (int restpos = coldefpos + 1; restpos < list_length(columns);)
    2553             :         {
    2554     5966692 :             ColumnDef  *restdef = list_nth_node(ColumnDef, columns, restpos);
    2555             : 
    2556     5966692 :             if (strcmp(coldef->colname, restdef->colname) == 0)
    2557             :             {
    2558          50 :                 if (coldef->is_from_type)
    2559             :                 {
    2560             :                     /*
    2561             :                      * merge the column options into the column from the type
    2562             :                      */
    2563          32 :                     coldef->is_not_null = restdef->is_not_null;
    2564          32 :                     coldef->raw_default = restdef->raw_default;
    2565          32 :                     coldef->cooked_default = restdef->cooked_default;
    2566          32 :                     coldef->constraints = restdef->constraints;
    2567          32 :                     coldef->is_from_type = false;
    2568          32 :                     columns = list_delete_nth_cell(columns, restpos);
    2569             :                 }
    2570             :                 else
    2571          18 :                     ereport(ERROR,
    2572             :                             (errcode(ERRCODE_DUPLICATE_COLUMN),
    2573             :                              errmsg("column \"%s\" specified more than once",
    2574             :                                     coldef->colname)));
    2575             :             }
    2576             :             else
    2577     5966642 :                 restpos++;
    2578             :         }
    2579             :     }
    2580             : 
    2581             :     /*
    2582             :      * In case of a partition, there are no new column definitions, only dummy
    2583             :      * ColumnDefs created for column constraints.  Set them aside for now and
    2584             :      * process them at the end.
    2585             :      */
    2586       52856 :     if (is_partition)
    2587             :     {
    2588        8250 :         saved_columns = columns;
    2589        8250 :         columns = NIL;
    2590             :     }
    2591             : 
    2592             :     /*
    2593             :      * Scan the parents left-to-right, and merge their attributes to form a
    2594             :      * list of inherited columns (inh_columns).
    2595             :      */
    2596       52856 :     child_attno = 0;
    2597       63088 :     foreach(lc, supers)
    2598             :     {
    2599       10304 :         Oid         parent = lfirst_oid(lc);
    2600             :         Relation    relation;
    2601             :         TupleDesc   tupleDesc;
    2602             :         TupleConstr *constr;
    2603             :         AttrMap    *newattmap;
    2604             :         List       *inherited_defaults;
    2605             :         List       *cols_with_defaults;
    2606             :         List       *nnconstrs;
    2607             :         ListCell   *lc1;
    2608             :         ListCell   *lc2;
    2609             :         Bitmapset  *pkattrs;
    2610       10304 :         Bitmapset  *nncols = NULL;
    2611             : 
    2612             :         /* caller already got lock */
    2613       10304 :         relation = table_open(parent, NoLock);
    2614             : 
    2615             :         /*
    2616             :          * Check for active uses of the parent partitioned table in the
    2617             :          * current transaction, such as being used in some manner by an
    2618             :          * enclosing command.
    2619             :          */
    2620       10304 :         if (is_partition)
    2621        8250 :             CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
    2622             : 
    2623             :         /*
    2624             :          * We do not allow partitioned tables and partitions to participate in
    2625             :          * regular inheritance.
    2626             :          */
    2627       10298 :         if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !is_partition)
    2628           6 :             ereport(ERROR,
    2629             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2630             :                      errmsg("cannot inherit from partitioned table \"%s\"",
    2631             :                             RelationGetRelationName(relation))));
    2632       10292 :         if (relation->rd_rel->relispartition && !is_partition)
    2633           6 :             ereport(ERROR,
    2634             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2635             :                      errmsg("cannot inherit from partition \"%s\"",
    2636             :                             RelationGetRelationName(relation))));
    2637             : 
    2638       10286 :         if (relation->rd_rel->relkind != RELKIND_RELATION &&
    2639        8246 :             relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
    2640        8226 :             relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
    2641           0 :             ereport(ERROR,
    2642             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2643             :                      errmsg("inherited relation \"%s\" is not a table or foreign table",
    2644             :                             RelationGetRelationName(relation))));
    2645             : 
    2646             :         /*
    2647             :          * If the parent is permanent, so must be all of its partitions.  Note
    2648             :          * that inheritance allows that case.
    2649             :          */
    2650       10286 :         if (is_partition &&
    2651        8244 :             relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
    2652             :             relpersistence == RELPERSISTENCE_TEMP)
    2653           6 :             ereport(ERROR,
    2654             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2655             :                      errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
    2656             :                             RelationGetRelationName(relation))));
    2657             : 
    2658             :         /* Permanent rels cannot inherit from temporary ones */
    2659       10280 :         if (relpersistence != RELPERSISTENCE_TEMP &&
    2660        9938 :             relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
    2661          24 :             ereport(ERROR,
    2662             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2663             :                      errmsg(!is_partition
    2664             :                             ? "cannot inherit from temporary relation \"%s\""
    2665             :                             : "cannot create a permanent relation as partition of temporary relation \"%s\"",
    2666             :                             RelationGetRelationName(relation))));
    2667             : 
    2668             :         /* If existing rel is temp, it must belong to this session */
    2669       10256 :         if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
    2670         294 :             !relation->rd_islocaltemp)
    2671           0 :             ereport(ERROR,
    2672             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2673             :                      errmsg(!is_partition
    2674             :                             ? "cannot inherit from temporary relation of another session"
    2675             :                             : "cannot create as partition of temporary relation of another session")));
    2676             : 
    2677             :         /*
    2678             :          * We should have an UNDER permission flag for this, but for now,
    2679             :          * demand that creator of a child table own the parent.
    2680             :          */
    2681       10256 :         if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), GetUserId()))
    2682           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(relation->rd_rel->relkind),
    2683           0 :                            RelationGetRelationName(relation));
    2684             : 
    2685       10256 :         tupleDesc = RelationGetDescr(relation);
    2686       10256 :         constr = tupleDesc->constr;
    2687             : 
    2688             :         /*
    2689             :          * newattmap->attnums[] will contain the child-table attribute numbers
    2690             :          * for the attributes of this parent table.  (They are not the same
    2691             :          * for parents after the first one, nor if we have dropped columns.)
    2692             :          */
    2693       10256 :         newattmap = make_attrmap(tupleDesc->natts);
    2694             : 
    2695             :         /* We can't process inherited defaults until newattmap is complete. */
    2696       10256 :         inherited_defaults = cols_with_defaults = NIL;
    2697             : 
    2698             :         /*
    2699             :          * All columns that are part of the parent's primary key need to be
    2700             :          * NOT NULL; if partition just the attnotnull bit, otherwise a full
    2701             :          * constraint (if they don't have one already).  Also, we request
    2702             :          * attnotnull on columns that have a not-null constraint that's not
    2703             :          * marked NO INHERIT.
    2704             :          */
    2705       10256 :         pkattrs = RelationGetIndexAttrBitmap(relation,
    2706             :                                              INDEX_ATTR_BITMAP_PRIMARY_KEY);
    2707       10256 :         nnconstrs = RelationGetNotNullConstraints(RelationGetRelid(relation), true);
    2708       11104 :         foreach(lc1, nnconstrs)
    2709         848 :             nncols = bms_add_member(nncols,
    2710         848 :                                     ((CookedConstraint *) lfirst(lc1))->attnum);
    2711             : 
    2712       32052 :         for (AttrNumber parent_attno = 1; parent_attno <= tupleDesc->natts;
    2713       21796 :              parent_attno++)
    2714             :         {
    2715       21820 :             Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
    2716             :                                                         parent_attno - 1);
    2717       21820 :             char       *attributeName = NameStr(attribute->attname);
    2718             :             int         exist_attno;
    2719             :             ColumnDef  *newdef;
    2720             :             ColumnDef  *mergeddef;
    2721             : 
    2722             :             /*
    2723             :              * Ignore dropped columns in the parent.
    2724             :              */
    2725       21820 :             if (attribute->attisdropped)
    2726         192 :                 continue;       /* leave newattmap->attnums entry as zero */
    2727             : 
    2728             :             /*
    2729             :              * Create new column definition
    2730             :              */
    2731       21628 :             newdef = makeColumnDef(attributeName, attribute->atttypid,
    2732             :                                    attribute->atttypmod, attribute->attcollation);
    2733       21628 :             newdef->storage = attribute->attstorage;
    2734       21628 :             newdef->generated = attribute->attgenerated;
    2735       21628 :             if (CompressionMethodIsValid(attribute->attcompression))
    2736          24 :                 newdef->compression =
    2737          24 :                     pstrdup(GetCompressionMethodName(attribute->attcompression));
    2738             : 
    2739             :             /*
    2740             :              * Regular inheritance children are independent enough not to
    2741             :              * inherit identity columns.  But partitions are integral part of
    2742             :              * a partitioned table and inherit identity column.
    2743             :              */
    2744       21628 :             if (is_partition)
    2745       17732 :                 newdef->identity = attribute->attidentity;
    2746             : 
    2747             :             /*
    2748             :              * Does it match some previously considered column from another
    2749             :              * parent?
    2750             :              */
    2751       21628 :             exist_attno = findAttrByName(attributeName, inh_columns);
    2752       21628 :             if (exist_attno > 0)
    2753             :             {
    2754             :                 /*
    2755             :                  * Yes, try to merge the two column definitions.
    2756             :                  */
    2757         296 :                 mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
    2758             : 
    2759         272 :                 newattmap->attnums[parent_attno - 1] = exist_attno;
    2760             : 
    2761             :                 /*
    2762             :                  * Partitions have only one parent, so conflict should never
    2763             :                  * occur.
    2764             :                  */
    2765             :                 Assert(!is_partition);
    2766             :             }
    2767             :             else
    2768             :             {
    2769             :                 /*
    2770             :                  * No, create a new inherited column
    2771             :                  */
    2772       21332 :                 newdef->inhcount = 1;
    2773       21332 :                 newdef->is_local = false;
    2774       21332 :                 inh_columns = lappend(inh_columns, newdef);
    2775             : 
    2776       21332 :                 newattmap->attnums[parent_attno - 1] = ++child_attno;
    2777             : 
    2778       21332 :                 mergeddef = newdef;
    2779             :             }
    2780             : 
    2781             :             /*
    2782             :              * mark attnotnull if parent has it and it's not NO INHERIT
    2783             :              */
    2784       42360 :             if (bms_is_member(parent_attno, nncols) ||
    2785       20756 :                 bms_is_member(parent_attno - FirstLowInvalidHeapAttributeNumber,
    2786             :                               pkattrs))
    2787        2134 :                 mergeddef->is_not_null = true;
    2788             : 
    2789             :             /*
    2790             :              * In regular inheritance, columns in the parent's primary key get
    2791             :              * an extra not-null constraint.  Partitioning doesn't need this,
    2792             :              * because the PK itself is going to be cloned to the partition.
    2793             :              */
    2794       25476 :             if (!is_partition &&
    2795        3872 :                 bms_is_member(parent_attno -
    2796             :                               FirstLowInvalidHeapAttributeNumber,
    2797             :                               pkattrs))
    2798             :             {
    2799             :                 CookedConstraint *nn;
    2800             : 
    2801         256 :                 nn = palloc(sizeof(CookedConstraint));
    2802         256 :                 nn->contype = CONSTR_NOTNULL;
    2803         256 :                 nn->conoid = InvalidOid;
    2804         256 :                 nn->name = NULL;
    2805         256 :                 nn->attnum = newattmap->attnums[parent_attno - 1];
    2806         256 :                 nn->expr = NULL;
    2807         256 :                 nn->skip_validation = false;
    2808         256 :                 nn->is_local = false;
    2809         256 :                 nn->inhcount = 1;
    2810         256 :                 nn->is_no_inherit = false;
    2811             : 
    2812         256 :                 nnconstraints = lappend(nnconstraints, nn);
    2813             :             }
    2814             : 
    2815             :             /*
    2816             :              * Locate default/generation expression if any
    2817             :              */
    2818       21604 :             if (attribute->atthasdef)
    2819             :             {
    2820             :                 Node       *this_default;
    2821             : 
    2822         650 :                 this_default = TupleDescGetDefault(tupleDesc, parent_attno);
    2823         650 :                 if (this_default == NULL)
    2824           0 :                     elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
    2825             :                          parent_attno, RelationGetRelationName(relation));
    2826             : 
    2827             :                 /*
    2828             :                  * If it's a GENERATED default, it might contain Vars that
    2829             :                  * need to be mapped to the inherited column(s)' new numbers.
    2830             :                  * We can't do that till newattmap is ready, so just remember
    2831             :                  * all the inherited default expressions for the moment.
    2832             :                  */
    2833         650 :                 inherited_defaults = lappend(inherited_defaults, this_default);
    2834         650 :                 cols_with_defaults = lappend(cols_with_defaults, mergeddef);
    2835             :             }
    2836             :         }
    2837             : 
    2838             :         /*
    2839             :          * Now process any inherited default expressions, adjusting attnos
    2840             :          * using the completed newattmap map.
    2841             :          */
    2842       10882 :         forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
    2843             :         {
    2844         650 :             Node       *this_default = (Node *) lfirst(lc1);
    2845         650 :             ColumnDef  *def = (ColumnDef *) lfirst(lc2);
    2846             :             bool        found_whole_row;
    2847             : 
    2848             :             /* Adjust Vars to match new table's column numbering */
    2849         650 :             this_default = map_variable_attnos(this_default,
    2850             :                                                1, 0,
    2851             :                                                newattmap,
    2852             :                                                InvalidOid, &found_whole_row);
    2853             : 
    2854             :             /*
    2855             :              * For the moment we have to reject whole-row variables.  We could
    2856             :              * convert them, if we knew the new table's rowtype OID, but that
    2857             :              * hasn't been assigned yet.  (A variable could only appear in a
    2858             :              * generation expression, so the error message is correct.)
    2859             :              */
    2860         650 :             if (found_whole_row)
    2861           0 :                 ereport(ERROR,
    2862             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2863             :                          errmsg("cannot convert whole-row table reference"),
    2864             :                          errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
    2865             :                                    def->colname,
    2866             :                                    RelationGetRelationName(relation))));
    2867             : 
    2868             :             /*
    2869             :              * If we already had a default from some prior parent, check to
    2870             :              * see if they are the same.  If so, no problem; if not, mark the
    2871             :              * column as having a bogus default.  Below, we will complain if
    2872             :              * the bogus default isn't overridden by the child columns.
    2873             :              */
    2874             :             Assert(def->raw_default == NULL);
    2875         650 :             if (def->cooked_default == NULL)
    2876         620 :                 def->cooked_default = this_default;
    2877          30 :             else if (!equal(def->cooked_default, this_default))
    2878             :             {
    2879          24 :                 def->cooked_default = &bogus_marker;
    2880          24 :                 have_bogus_defaults = true;
    2881             :             }
    2882             :         }
    2883             : 
    2884             :         /*
    2885             :          * Now copy the CHECK constraints of this parent, adjusting attnos
    2886             :          * using the completed newattmap map.  Identically named constraints
    2887             :          * are merged if possible, else we throw error.
    2888             :          */
    2889       10232 :         if (constr && constr->num_check > 0)
    2890             :         {
    2891         304 :             ConstrCheck *check = constr->check;
    2892             : 
    2893         638 :             for (int i = 0; i < constr->num_check; i++)
    2894             :             {
    2895         334 :                 char       *name = check[i].ccname;
    2896             :                 Node       *expr;
    2897             :                 bool        found_whole_row;
    2898             : 
    2899             :                 /* ignore if the constraint is non-inheritable */
    2900         334 :                 if (check[i].ccnoinherit)
    2901          48 :                     continue;
    2902             : 
    2903             :                 /* Adjust Vars to match new table's column numbering */
    2904         286 :                 expr = map_variable_attnos(stringToNode(check[i].ccbin),
    2905             :                                            1, 0,
    2906             :                                            newattmap,
    2907             :                                            InvalidOid, &found_whole_row);
    2908             : 
    2909             :                 /*
    2910             :                  * For the moment we have to reject whole-row variables. We
    2911             :                  * could convert them, if we knew the new table's rowtype OID,
    2912             :                  * but that hasn't been assigned yet.
    2913             :                  */
    2914         286 :                 if (found_whole_row)
    2915           0 :                     ereport(ERROR,
    2916             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2917             :                              errmsg("cannot convert whole-row table reference"),
    2918             :                              errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
    2919             :                                        name,
    2920             :                                        RelationGetRelationName(relation))));
    2921             : 
    2922         286 :                 constraints = MergeCheckConstraint(constraints, name, expr);
    2923             :             }
    2924             :         }
    2925             : 
    2926             :         /*
    2927             :          * Also copy the not-null constraints from this parent.  The
    2928             :          * attnotnull markings were already installed above.
    2929             :          */
    2930       11080 :         foreach(lc1, nnconstrs)
    2931             :         {
    2932         848 :             CookedConstraint *nn = lfirst(lc1);
    2933             : 
    2934             :             Assert(nn->contype == CONSTR_NOTNULL);
    2935             : 
    2936         848 :             nn->attnum = newattmap->attnums[nn->attnum - 1];
    2937         848 :             nn->is_local = false;
    2938         848 :             nn->inhcount = 1;
    2939             : 
    2940         848 :             nnconstraints = lappend(nnconstraints, nn);
    2941             :         }
    2942             : 
    2943       10232 :         free_attrmap(newattmap);
    2944             : 
    2945             :         /*
    2946             :          * Close the parent rel, but keep our lock on it until xact commit.
    2947             :          * That will prevent someone else from deleting or ALTERing the parent
    2948             :          * before the child is committed.
    2949             :          */
    2950       10232 :         table_close(relation, NoLock);
    2951             :     }
    2952             : 
    2953             :     /*
    2954             :      * If we had no inherited attributes, the result columns are just the
    2955             :      * explicitly declared columns.  Otherwise, we need to merge the declared
    2956             :      * columns into the inherited column list.  Although, we never have any
    2957             :      * explicitly declared columns if the table is a partition.
    2958             :      */
    2959       52784 :     if (inh_columns != NIL)
    2960             :     {
    2961        9906 :         int         newcol_attno = 0;
    2962             : 
    2963       10684 :         foreach(lc, columns)
    2964             :         {
    2965         826 :             ColumnDef  *newdef = lfirst_node(ColumnDef, lc);
    2966         826 :             char       *attributeName = newdef->colname;
    2967             :             int         exist_attno;
    2968             : 
    2969             :             /*
    2970             :              * Partitions have only one parent and have no column definitions
    2971             :              * of their own, so conflict should never occur.
    2972             :              */
    2973             :             Assert(!is_partition);
    2974             : 
    2975         826 :             newcol_attno++;
    2976             : 
    2977             :             /*
    2978             :              * Does it match some inherited column?
    2979             :              */
    2980         826 :             exist_attno = findAttrByName(attributeName, inh_columns);
    2981         826 :             if (exist_attno > 0)
    2982             :             {
    2983             :                 /*
    2984             :                  * Yes, try to merge the two column definitions.
    2985             :                  */
    2986         268 :                 MergeChildAttribute(inh_columns, exist_attno, newcol_attno, newdef);
    2987             :             }
    2988             :             else
    2989             :             {
    2990             :                 /*
    2991             :                  * No, attach new column unchanged to result columns.
    2992             :                  */
    2993         558 :                 inh_columns = lappend(inh_columns, newdef);
    2994             :             }
    2995             :         }
    2996             : 
    2997        9858 :         columns = inh_columns;
    2998             : 
    2999             :         /*
    3000             :          * Check that we haven't exceeded the legal # of columns after merging
    3001             :          * in inherited columns.
    3002             :          */
    3003        9858 :         if (list_length(columns) > MaxHeapAttributeNumber)
    3004           0 :             ereport(ERROR,
    3005             :                     (errcode(ERRCODE_TOO_MANY_COLUMNS),
    3006             :                      errmsg("tables can have at most %d columns",
    3007             :                             MaxHeapAttributeNumber)));
    3008             :     }
    3009             : 
    3010             :     /*
    3011             :      * Now that we have the column definition list for a partition, we can
    3012             :      * check whether the columns referenced in the column constraint specs
    3013             :      * actually exist.  Also, merge column defaults.
    3014             :      */
    3015       52736 :     if (is_partition)
    3016             :     {
    3017        8416 :         foreach(lc, saved_columns)
    3018             :         {
    3019         208 :             ColumnDef  *restdef = lfirst(lc);
    3020         208 :             bool        found = false;
    3021             :             ListCell   *l;
    3022             : 
    3023         784 :             foreach(l, columns)
    3024             :             {
    3025         588 :                 ColumnDef  *coldef = lfirst(l);
    3026             : 
    3027         588 :                 if (strcmp(coldef->colname, restdef->colname) == 0)
    3028             :                 {
    3029         208 :                     found = true;
    3030             : 
    3031             :                     /*
    3032             :                      * Check for conflicts related to generated columns.
    3033             :                      *
    3034             :                      * Same rules as above: generated-ness has to match the
    3035             :                      * parent, but the contents of the generation expression
    3036             :                      * can be different.
    3037             :                      */
    3038         208 :                     if (coldef->generated)
    3039             :                     {
    3040         106 :                         if (restdef->raw_default && !restdef->generated)
    3041           6 :                             ereport(ERROR,
    3042             :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3043             :                                      errmsg("column \"%s\" inherits from generated column but specifies default",
    3044             :                                             restdef->colname)));
    3045         100 :                         if (restdef->identity)
    3046           0 :                             ereport(ERROR,
    3047             :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3048             :                                      errmsg("column \"%s\" inherits from generated column but specifies identity",
    3049             :                                             restdef->colname)));
    3050             :                     }
    3051             :                     else
    3052             :                     {
    3053         102 :                         if (restdef->generated)
    3054           6 :                             ereport(ERROR,
    3055             :                                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3056             :                                      errmsg("child column \"%s\" specifies generation expression",
    3057             :                                             restdef->colname),
    3058             :                                      errhint("A child table column cannot be generated unless its parent column is.")));
    3059             :                     }
    3060             : 
    3061             :                     /*
    3062             :                      * Override the parent's default value for this column
    3063             :                      * (coldef->cooked_default) with the partition's local
    3064             :                      * definition (restdef->raw_default), if there's one. It
    3065             :                      * should be physically impossible to get a cooked default
    3066             :                      * in the local definition or a raw default in the
    3067             :                      * inherited definition, but make sure they're nulls, for
    3068             :                      * future-proofing.
    3069             :                      */
    3070             :                     Assert(restdef->cooked_default == NULL);
    3071             :                     Assert(coldef->raw_default == NULL);
    3072         196 :                     if (restdef->raw_default)
    3073             :                     {
    3074         124 :                         coldef->raw_default = restdef->raw_default;
    3075         124 :                         coldef->cooked_default = NULL;
    3076             :                     }
    3077             :                 }
    3078             :             }
    3079             : 
    3080             :             /* complain for constraints on columns not in parent */
    3081         196 :             if (!found)
    3082           0 :                 ereport(ERROR,
    3083             :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    3084             :                          errmsg("column \"%s\" does not exist",
    3085             :                                 restdef->colname)));
    3086             :         }
    3087             :     }
    3088             : 
    3089             :     /*
    3090             :      * If we found any conflicting parent default values, check to make sure
    3091             :      * they were overridden by the child.
    3092             :      */
    3093       52724 :     if (have_bogus_defaults)
    3094             :     {
    3095          54 :         foreach(lc, columns)
    3096             :         {
    3097          42 :             ColumnDef  *def = lfirst(lc);
    3098             : 
    3099          42 :             if (def->cooked_default == &bogus_marker)
    3100             :             {
    3101          12 :                 if (def->generated)
    3102           6 :                     ereport(ERROR,
    3103             :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3104             :                              errmsg("column \"%s\" inherits conflicting generation expressions",
    3105             :                                     def->colname),
    3106             :                              errhint("To resolve the conflict, specify a generation expression explicitly.")));
    3107             :                 else
    3108           6 :                     ereport(ERROR,
    3109             :                             (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3110             :                              errmsg("column \"%s\" inherits conflicting default values",
    3111             :                                     def->colname),
    3112             :                              errhint("To resolve the conflict, specify a default explicitly.")));
    3113             :             }
    3114             :         }
    3115             :     }
    3116             : 
    3117       52712 :     *supconstr = constraints;
    3118       52712 :     *supnotnulls = nnconstraints;
    3119             : 
    3120       52712 :     return columns;
    3121             : }
    3122             : 
    3123             : 
    3124             : /*
    3125             :  * MergeCheckConstraint
    3126             :  *      Try to merge an inherited CHECK constraint with previous ones
    3127             :  *
    3128             :  * If we inherit identically-named constraints from multiple parents, we must
    3129             :  * merge them, or throw an error if they don't have identical definitions.
    3130             :  *
    3131             :  * constraints is a list of CookedConstraint structs for previous constraints.
    3132             :  *
    3133             :  * If the new constraint matches an existing one, then the existing
    3134             :  * constraint's inheritance count is updated.  If there is a conflict (same
    3135             :  * name but different expression), throw an error.  If the constraint neither
    3136             :  * matches nor conflicts with an existing one, a new constraint is appended to
    3137             :  * the list.
    3138             :  */
    3139             : static List *
    3140         286 : MergeCheckConstraint(List *constraints, const char *name, Node *expr)
    3141             : {
    3142             :     ListCell   *lc;
    3143             :     CookedConstraint *newcon;
    3144             : 
    3145         316 :     foreach(lc, constraints)
    3146             :     {
    3147          72 :         CookedConstraint *ccon = (CookedConstraint *) lfirst(lc);
    3148             : 
    3149             :         Assert(ccon->contype == CONSTR_CHECK);
    3150             : 
    3151             :         /* Non-matching names never conflict */
    3152          72 :         if (strcmp(ccon->name, name) != 0)
    3153          30 :             continue;
    3154             : 
    3155          42 :         if (equal(expr, ccon->expr))
    3156             :         {
    3157             :             /* OK to merge constraint with existing */
    3158          42 :             ccon->inhcount++;
    3159          42 :             if (ccon->inhcount < 0)
    3160           0 :                 ereport(ERROR,
    3161             :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3162             :                         errmsg("too many inheritance parents"));
    3163          42 :             return constraints;
    3164             :         }
    3165             : 
    3166           0 :         ereport(ERROR,
    3167             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    3168             :                  errmsg("check constraint name \"%s\" appears multiple times but with different expressions",
    3169             :                         name)));
    3170             :     }
    3171             : 
    3172             :     /*
    3173             :      * Constraint couldn't be merged with an existing one and also didn't
    3174             :      * conflict with an existing one, so add it as a new one to the list.
    3175             :      */
    3176         244 :     newcon = palloc0_object(CookedConstraint);
    3177         244 :     newcon->contype = CONSTR_CHECK;
    3178         244 :     newcon->name = pstrdup(name);
    3179         244 :     newcon->expr = expr;
    3180         244 :     newcon->inhcount = 1;
    3181         244 :     return lappend(constraints, newcon);
    3182             : }
    3183             : 
    3184             : /*
    3185             :  * MergeChildAttribute
    3186             :  *      Merge given child attribute definition into given inherited attribute.
    3187             :  *
    3188             :  * Input arguments:
    3189             :  * 'inh_columns' is the list of inherited ColumnDefs.
    3190             :  * 'exist_attno' is the number of the inherited attribute in inh_columns
    3191             :  * 'newcol_attno' is the attribute number in child table's schema definition
    3192             :  * 'newdef' is the column/attribute definition from the child table.
    3193             :  *
    3194             :  * The ColumnDef in 'inh_columns' list is modified.  The child attribute's
    3195             :  * ColumnDef remains unchanged.
    3196             :  *
    3197             :  * Notes:
    3198             :  * - The attribute is merged according to the rules laid out in the prologue
    3199             :  *   of MergeAttributes().
    3200             :  * - If matching inherited attribute exists but the child attribute can not be
    3201             :  *   merged into it, the function throws respective errors.
    3202             :  * - A partition can not have its own column definitions. Hence this function
    3203             :  *   is applicable only to a regular inheritance child.
    3204             :  */
    3205             : static void
    3206         268 : MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
    3207             : {
    3208         268 :     char       *attributeName = newdef->colname;
    3209             :     ColumnDef  *inhdef;
    3210             :     Oid         inhtypeid,
    3211             :                 newtypeid;
    3212             :     int32       inhtypmod,
    3213             :                 newtypmod;
    3214             :     Oid         inhcollid,
    3215             :                 newcollid;
    3216             : 
    3217         268 :     if (exist_attno == newcol_attno)
    3218         240 :         ereport(NOTICE,
    3219             :                 (errmsg("merging column \"%s\" with inherited definition",
    3220             :                         attributeName)));
    3221             :     else
    3222          28 :         ereport(NOTICE,
    3223             :                 (errmsg("moving and merging column \"%s\" with inherited definition", attributeName),
    3224             :                  errdetail("User-specified column moved to the position of the inherited column.")));
    3225             : 
    3226         268 :     inhdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
    3227             : 
    3228             :     /*
    3229             :      * Must have the same type and typmod
    3230             :      */
    3231         268 :     typenameTypeIdAndMod(NULL, inhdef->typeName, &inhtypeid, &inhtypmod);
    3232         268 :     typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
    3233         268 :     if (inhtypeid != newtypeid || inhtypmod != newtypmod)
    3234          12 :         ereport(ERROR,
    3235             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3236             :                  errmsg("column \"%s\" has a type conflict",
    3237             :                         attributeName),
    3238             :                  errdetail("%s versus %s",
    3239             :                            format_type_with_typemod(inhtypeid, inhtypmod),
    3240             :                            format_type_with_typemod(newtypeid, newtypmod))));
    3241             : 
    3242             :     /*
    3243             :      * Must have the same collation
    3244             :      */
    3245         256 :     inhcollid = GetColumnDefCollation(NULL, inhdef, inhtypeid);
    3246         256 :     newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
    3247         256 :     if (inhcollid != newcollid)
    3248           6 :         ereport(ERROR,
    3249             :                 (errcode(ERRCODE_COLLATION_MISMATCH),
    3250             :                  errmsg("column \"%s\" has a collation conflict",
    3251             :                         attributeName),
    3252             :                  errdetail("\"%s\" versus \"%s\"",
    3253             :                            get_collation_name(inhcollid),
    3254             :                            get_collation_name(newcollid))));
    3255             : 
    3256             :     /*
    3257             :      * Identity is never inherited by a regular inheritance child. Pick
    3258             :      * child's identity definition if there's one.
    3259             :      */
    3260         250 :     inhdef->identity = newdef->identity;
    3261             : 
    3262             :     /*
    3263             :      * Copy storage parameter
    3264             :      */
    3265         250 :     if (inhdef->storage == 0)
    3266           0 :         inhdef->storage = newdef->storage;
    3267         250 :     else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
    3268           6 :         ereport(ERROR,
    3269             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3270             :                  errmsg("column \"%s\" has a storage parameter conflict",
    3271             :                         attributeName),
    3272             :                  errdetail("%s versus %s",
    3273             :                            storage_name(inhdef->storage),
    3274             :                            storage_name(newdef->storage))));
    3275             : 
    3276             :     /*
    3277             :      * Copy compression parameter
    3278             :      */
    3279         244 :     if (inhdef->compression == NULL)
    3280         238 :         inhdef->compression = newdef->compression;
    3281           6 :     else if (newdef->compression != NULL)
    3282             :     {
    3283           6 :         if (strcmp(inhdef->compression, newdef->compression) != 0)
    3284           6 :             ereport(ERROR,
    3285             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3286             :                      errmsg("column \"%s\" has a compression method conflict",
    3287             :                             attributeName),
    3288             :                      errdetail("%s versus %s", inhdef->compression, newdef->compression)));
    3289             :     }
    3290             : 
    3291             :     /*
    3292             :      * Merge of not-null constraints = OR 'em together
    3293             :      */
    3294         238 :     inhdef->is_not_null |= newdef->is_not_null;
    3295             : 
    3296             :     /*
    3297             :      * Check for conflicts related to generated columns.
    3298             :      *
    3299             :      * If the parent column is generated, the child column will be made a
    3300             :      * generated column if it isn't already.  If it is a generated column,
    3301             :      * we'll take its generation expression in preference to the parent's.  We
    3302             :      * must check that the child column doesn't specify a default value or
    3303             :      * identity, which matches the rules for a single column in
    3304             :      * parse_utilcmd.c.
    3305             :      *
    3306             :      * Conversely, if the parent column is not generated, the child column
    3307             :      * can't be either.  (We used to allow that, but it results in being able
    3308             :      * to override the generation expression via UPDATEs through the parent.)
    3309             :      */
    3310         238 :     if (inhdef->generated)
    3311             :     {
    3312          26 :         if (newdef->raw_default && !newdef->generated)
    3313           6 :             ereport(ERROR,
    3314             :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3315             :                      errmsg("column \"%s\" inherits from generated column but specifies default",
    3316             :                             inhdef->colname)));
    3317          20 :         if (newdef->identity)
    3318           6 :             ereport(ERROR,
    3319             :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3320             :                      errmsg("column \"%s\" inherits from generated column but specifies identity",
    3321             :                             inhdef->colname)));
    3322             :     }
    3323             :     else
    3324             :     {
    3325         212 :         if (newdef->generated)
    3326           6 :             ereport(ERROR,
    3327             :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
    3328             :                      errmsg("child column \"%s\" specifies generation expression",
    3329             :                             inhdef->colname),
    3330             :                      errhint("A child table column cannot be generated unless its parent column is.")));
    3331             :     }
    3332             : 
    3333             :     /*
    3334             :      * If new def has a default, override previous default
    3335             :      */
    3336         220 :     if (newdef->raw_default != NULL)
    3337             :     {
    3338          18 :         inhdef->raw_default = newdef->raw_default;
    3339          18 :         inhdef->cooked_default = newdef->cooked_default;
    3340             :     }
    3341             : 
    3342             :     /* Mark the column as locally defined */
    3343         220 :     inhdef->is_local = true;
    3344         220 : }
    3345             : 
    3346             : /*
    3347             :  * MergeInheritedAttribute
    3348             :  *      Merge given parent attribute definition into specified attribute
    3349             :  *      inherited from the previous parents.
    3350             :  *
    3351             :  * Input arguments:
    3352             :  * 'inh_columns' is the list of previously inherited ColumnDefs.
    3353             :  * 'exist_attno' is the number the existing matching attribute in inh_columns.
    3354             :  * 'newdef' is the new parent column/attribute definition to be merged.
    3355             :  *
    3356             :  * The matching ColumnDef in 'inh_columns' list is modified and returned.
    3357             :  *
    3358             :  * Notes:
    3359             :  * - The attribute is merged according to the rules laid out in the prologue
    3360             :  *   of MergeAttributes().
    3361             :  * - If matching inherited attribute exists but the new attribute can not be
    3362             :  *   merged into it, the function throws respective errors.
    3363             :  * - A partition inherits from only a single parent. Hence this function is
    3364             :  *   applicable only to a regular inheritance.
    3365             :  */
    3366             : static ColumnDef *
    3367         296 : MergeInheritedAttribute(List *inh_columns,
    3368             :                         int exist_attno,
    3369             :                         const ColumnDef *newdef)
    3370             : {
    3371         296 :     char       *attributeName = newdef->colname;
    3372             :     ColumnDef  *prevdef;
    3373             :     Oid         prevtypeid,
    3374             :                 newtypeid;
    3375             :     int32       prevtypmod,
    3376             :                 newtypmod;
    3377             :     Oid         prevcollid,
    3378             :                 newcollid;
    3379             : 
    3380         296 :     ereport(NOTICE,
    3381             :             (errmsg("merging multiple inherited definitions of column \"%s\"",
    3382             :                     attributeName)));
    3383         296 :     prevdef = list_nth_node(ColumnDef, inh_columns, exist_attno - 1);
    3384             : 
    3385             :     /*
    3386             :      * Must have the same type and typmod
    3387             :      */
    3388         296 :     typenameTypeIdAndMod(NULL, prevdef->typeName, &prevtypeid, &prevtypmod);
    3389         296 :     typenameTypeIdAndMod(NULL, newdef->typeName, &newtypeid, &newtypmod);
    3390         296 :     if (prevtypeid != newtypeid || prevtypmod != newtypmod)
    3391           0 :         ereport(ERROR,
    3392             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3393             :                  errmsg("inherited column \"%s\" has a type conflict",
    3394             :                         attributeName),
    3395             :                  errdetail("%s versus %s",
    3396             :                            format_type_with_typemod(prevtypeid, prevtypmod),
    3397             :                            format_type_with_typemod(newtypeid, newtypmod))));
    3398             : 
    3399             :     /*
    3400             :      * Must have the same collation
    3401             :      */
    3402         296 :     prevcollid = GetColumnDefCollation(NULL, prevdef, prevtypeid);
    3403         296 :     newcollid = GetColumnDefCollation(NULL, newdef, newtypeid);
    3404         296 :     if (prevcollid != newcollid)
    3405           0 :         ereport(ERROR,
    3406             :                 (errcode(ERRCODE_COLLATION_MISMATCH),
    3407             :                  errmsg("inherited column \"%s\" has a collation conflict",
    3408             :                         attributeName),
    3409             :                  errdetail("\"%s\" versus \"%s\"",
    3410             :                            get_collation_name(prevcollid),
    3411             :                            get_collation_name(newcollid))));
    3412             : 
    3413             :     /*
    3414             :      * Copy/check storage parameter
    3415             :      */
    3416         296 :     if (prevdef->storage == 0)
    3417           0 :         prevdef->storage = newdef->storage;
    3418         296 :     else if (prevdef->storage != newdef->storage)
    3419           6 :         ereport(ERROR,
    3420             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3421             :                  errmsg("inherited column \"%s\" has a storage parameter conflict",
    3422             :                         attributeName),
    3423             :                  errdetail("%s versus %s",
    3424             :                            storage_name(prevdef->storage),
    3425             :                            storage_name(newdef->storage))));
    3426             : 
    3427             :     /*
    3428             :      * Copy/check compression parameter
    3429             :      */
    3430         290 :     if (prevdef->compression == NULL)
    3431         284 :         prevdef->compression = newdef->compression;
    3432           6 :     else if (strcmp(prevdef->compression, newdef->compression) != 0)
    3433           6 :         ereport(ERROR,
    3434             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3435             :                  errmsg("column \"%s\" has a compression method conflict",
    3436             :                         attributeName),
    3437             :                  errdetail("%s versus %s", prevdef->compression, newdef->compression)));
    3438             : 
    3439             :     /*
    3440             :      * Check for GENERATED conflicts
    3441             :      */
    3442         284 :     if (prevdef->generated != newdef->generated)
    3443          12 :         ereport(ERROR,
    3444             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3445             :                  errmsg("inherited column \"%s\" has a generation conflict",
    3446             :                         attributeName)));
    3447             : 
    3448             :     /*
    3449             :      * Default and other constraints are handled by the caller.
    3450             :      */
    3451             : 
    3452         272 :     prevdef->inhcount++;
    3453         272 :     if (prevdef->inhcount < 0)
    3454           0 :         ereport(ERROR,
    3455             :                 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3456             :                 errmsg("too many inheritance parents"));
    3457             : 
    3458         272 :     return prevdef;
    3459             : }
    3460             : 
    3461             : /*
    3462             :  * StoreCatalogInheritance
    3463             :  *      Updates the system catalogs with proper inheritance information.
    3464             :  *
    3465             :  * supers is a list of the OIDs of the new relation's direct ancestors.
    3466             :  */
    3467             : static void
    3468       52166 : StoreCatalogInheritance(Oid relationId, List *supers,
    3469             :                         bool child_is_partition)
    3470             : {
    3471             :     Relation    relation;
    3472             :     int32       seqNumber;
    3473             :     ListCell   *entry;
    3474             : 
    3475             :     /*
    3476             :      * sanity checks
    3477             :      */
    3478             :     Assert(OidIsValid(relationId));
    3479             : 
    3480       52166 :     if (supers == NIL)
    3481       42656 :         return;
    3482             : 
    3483             :     /*
    3484             :      * Store INHERITS information in pg_inherits using direct ancestors only.
    3485             :      * Also enter dependencies on the direct ancestors, and make sure they are
    3486             :      * marked with relhassubclass = true.
    3487             :      *
    3488             :      * (Once upon a time, both direct and indirect ancestors were found here
    3489             :      * and then entered into pg_ipl.  Since that catalog doesn't exist
    3490             :      * anymore, there's no need to look for indirect ancestors.)
    3491             :      */
    3492        9510 :     relation = table_open(InheritsRelationId, RowExclusiveLock);
    3493             : 
    3494        9510 :     seqNumber = 1;
    3495       19280 :     foreach(entry, supers)
    3496             :     {
    3497        9770 :         Oid         parentOid = lfirst_oid(entry);
    3498             : 
    3499        9770 :         StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation,
    3500             :                                  child_is_partition);
    3501        9770 :         seqNumber++;
    3502             :     }
    3503             : 
    3504        9510 :     table_close(relation, RowExclusiveLock);
    3505             : }
    3506             : 
    3507             : /*
    3508             :  * Make catalog entries showing relationId as being an inheritance child
    3509             :  * of parentOid.  inhRelation is the already-opened pg_inherits catalog.
    3510             :  */
    3511             : static void
    3512       12374 : StoreCatalogInheritance1(Oid relationId, Oid parentOid,
    3513             :                          int32 seqNumber, Relation inhRelation,
    3514             :                          bool child_is_partition)
    3515             : {
    3516             :     ObjectAddress childobject,
    3517             :                 parentobject;
    3518             : 
    3519             :     /* store the pg_inherits row */
    3520       12374 :     StoreSingleInheritance(relationId, parentOid, seqNumber);
    3521             : 
    3522             :     /*
    3523             :      * Store a dependency too
    3524             :      */
    3525       12374 :     parentobject.classId = RelationRelationId;
    3526       12374 :     parentobject.objectId = parentOid;
    3527       12374 :     parentobject.objectSubId = 0;
    3528       12374 :     childobject.classId = RelationRelationId;
    3529       12374 :     childobject.objectId = relationId;
    3530       12374 :     childobject.objectSubId = 0;
    3531             : 
    3532       12374 :     recordDependencyOn(&childobject, &parentobject,
    3533             :                        child_dependency_type(child_is_partition));
    3534             : 
    3535             :     /*
    3536             :      * Post creation hook of this inheritance. Since object_access_hook
    3537             :      * doesn't take multiple object identifiers, we relay oid of parent
    3538             :      * relation using auxiliary_id argument.
    3539             :      */
    3540       12374 :     InvokeObjectPostAlterHookArg(InheritsRelationId,
    3541             :                                  relationId, 0,
    3542             :                                  parentOid, false);
    3543             : 
    3544             :     /*
    3545             :      * Mark the parent as having subclasses.
    3546             :      */
    3547       12374 :     SetRelationHasSubclass(parentOid, true);
    3548       12374 : }
    3549             : 
    3550             : /*
    3551             :  * Look for an existing column entry with the given name.
    3552             :  *
    3553             :  * Returns the index (starting with 1) if attribute already exists in columns,
    3554             :  * 0 if it doesn't.
    3555             :  */
    3556             : static int
    3557       22454 : findAttrByName(const char *attributeName, const List *columns)
    3558             : {
    3559             :     ListCell   *lc;
    3560       22454 :     int         i = 1;
    3561             : 
    3562       41966 :     foreach(lc, columns)
    3563             :     {
    3564       20076 :         if (strcmp(attributeName, lfirst_node(ColumnDef, lc)->colname) == 0)
    3565         564 :             return i;
    3566             : 
    3567       19512 :         i++;
    3568             :     }
    3569       21890 :     return 0;
    3570             : }
    3571             : 
    3572             : 
    3573             : /*
    3574             :  * SetRelationHasSubclass
    3575             :  *      Set the value of the relation's relhassubclass field in pg_class.
    3576             :  *
    3577             :  * NOTE: caller must be holding an appropriate lock on the relation.
    3578             :  * ShareUpdateExclusiveLock is sufficient.
    3579             :  *
    3580             :  * NOTE: an important side-effect of this operation is that an SI invalidation
    3581             :  * message is sent out to all backends --- including me --- causing plans
    3582             :  * referencing the relation to be rebuilt with the new list of children.
    3583             :  * This must happen even if we find that no change is needed in the pg_class
    3584             :  * row.
    3585             :  */
    3586             : void
    3587       15666 : SetRelationHasSubclass(Oid relationId, bool relhassubclass)
    3588             : {
    3589             :     Relation    relationRelation;
    3590             :     HeapTuple   tuple;
    3591             :     Form_pg_class classtuple;
    3592             : 
    3593             :     /*
    3594             :      * Fetch a modifiable copy of the tuple, modify it, update pg_class.
    3595             :      */
    3596       15666 :     relationRelation = table_open(RelationRelationId, RowExclusiveLock);
    3597       15666 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
    3598       15666 :     if (!HeapTupleIsValid(tuple))
    3599           0 :         elog(ERROR, "cache lookup failed for relation %u", relationId);
    3600       15666 :     classtuple = (Form_pg_class) GETSTRUCT(tuple);
    3601             : 
    3602       15666 :     if (classtuple->relhassubclass != relhassubclass)
    3603             :     {
    3604        7338 :         classtuple->relhassubclass = relhassubclass;
    3605        7338 :         CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
    3606             :     }
    3607             :     else
    3608             :     {
    3609             :         /* no need to change tuple, but force relcache rebuild anyway */
    3610        8328 :         CacheInvalidateRelcacheByTuple(tuple);
    3611             :     }
    3612             : 
    3613       15666 :     heap_freetuple(tuple);
    3614       15666 :     table_close(relationRelation, RowExclusiveLock);
    3615       15666 : }
    3616             : 
    3617             : /*
    3618             :  * CheckRelationTableSpaceMove
    3619             :  *      Check if relation can be moved to new tablespace.
    3620             :  *
    3621             :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
    3622             :  *
    3623             :  * Returns true if the relation can be moved to the new tablespace; raises
    3624             :  * an error if it is not possible to do the move; returns false if the move
    3625             :  * would have no effect.
    3626             :  */
    3627             : bool
    3628         226 : CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
    3629             : {
    3630             :     Oid         oldTableSpaceId;
    3631             : 
    3632             :     /*
    3633             :      * No work if no change in tablespace.  Note that MyDatabaseTableSpace is
    3634             :      * stored as 0.
    3635             :      */
    3636         226 :     oldTableSpaceId = rel->rd_rel->reltablespace;
    3637         226 :     if (newTableSpaceId == oldTableSpaceId ||
    3638         218 :         (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
    3639          10 :         return false;
    3640             : 
    3641             :     /*
    3642             :      * We cannot support moving mapped relations into different tablespaces.
    3643             :      * (In particular this eliminates all shared catalogs.)
    3644             :      */
    3645         216 :     if (RelationIsMapped(rel))
    3646           0 :         ereport(ERROR,
    3647             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3648             :                  errmsg("cannot move system relation \"%s\"",
    3649             :                         RelationGetRelationName(rel))));
    3650             : 
    3651             :     /* Cannot move a non-shared relation into pg_global */
    3652         216 :     if (newTableSpaceId == GLOBALTABLESPACE_OID)
    3653          12 :         ereport(ERROR,
    3654             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3655             :                  errmsg("only shared relations can be placed in pg_global tablespace")));
    3656             : 
    3657             :     /*
    3658             :      * Do not allow moving temp tables of other backends ... their local
    3659             :      * buffer manager is not going to cope.
    3660             :      */
    3661         204 :     if (RELATION_IS_OTHER_TEMP(rel))
    3662           0 :         ereport(ERROR,
    3663             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3664             :                  errmsg("cannot move temporary tables of other sessions")));
    3665             : 
    3666         204 :     return true;
    3667             : }
    3668             : 
    3669             : /*
    3670             :  * SetRelationTableSpace
    3671             :  *      Set new reltablespace and relfilenumber in pg_class entry.
    3672             :  *
    3673             :  * newTableSpaceId is the new tablespace for the relation, and
    3674             :  * newRelFilenumber its new filenumber.  If newRelFilenumber is
    3675             :  * InvalidRelFileNumber, this field is not updated.
    3676             :  *
    3677             :  * NOTE: The caller must hold AccessExclusiveLock on the relation.
    3678             :  *
    3679             :  * The caller of this routine had better check if a relation can be
    3680             :  * moved to this new tablespace by calling CheckRelationTableSpaceMove()
    3681             :  * first, and is responsible for making the change visible with
    3682             :  * CommandCounterIncrement().
    3683             :  */
    3684             : void
    3685         204 : SetRelationTableSpace(Relation rel,
    3686             :                       Oid newTableSpaceId,
    3687             :                       RelFileNumber newRelFilenumber)
    3688             : {
    3689             :     Relation    pg_class;
    3690             :     HeapTuple   tuple;
    3691             :     Form_pg_class rd_rel;
    3692         204 :     Oid         reloid = RelationGetRelid(rel);
    3693             : 
    3694             :     Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
    3695             : 
    3696             :     /* Get a modifiable copy of the relation's pg_class row. */
    3697         204 :     pg_class = table_open(RelationRelationId, RowExclusiveLock);
    3698             : 
    3699         204 :     tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
    3700         204 :     if (!HeapTupleIsValid(tuple))
    3701           0 :         elog(ERROR, "cache lookup failed for relation %u", reloid);
    3702         204 :     rd_rel = (Form_pg_class) GETSTRUCT(tuple);
    3703             : 
    3704             :     /* Update the pg_class row. */
    3705         408 :     rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
    3706         204 :         InvalidOid : newTableSpaceId;
    3707         204 :     if (RelFileNumberIsValid(newRelFilenumber))
    3708         160 :         rd_rel->relfilenode = newRelFilenumber;
    3709         204 :     CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
    3710             : 
    3711             :     /*
    3712             :      * Record dependency on tablespace.  This is only required for relations
    3713             :      * that have no physical storage.
    3714             :      */
    3715         204 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
    3716          30 :         changeDependencyOnTablespace(RelationRelationId, reloid,
    3717             :                                      rd_rel->reltablespace);
    3718             : 
    3719         204 :     heap_freetuple(tuple);
    3720         204 :     table_close(pg_class, RowExclusiveLock);
    3721         204 : }
    3722             : 
    3723             : /*
    3724             :  *      renameatt_check         - basic sanity checks before attribute rename
    3725             :  */
    3726             : static void
    3727         986 : renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
    3728             : {
    3729         986 :     char        relkind = classform->relkind;
    3730             : 
    3731         986 :     if (classform->reloftype && !recursing)
    3732           6 :         ereport(ERROR,
    3733             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3734             :                  errmsg("cannot rename column of typed table")));
    3735             : 
    3736             :     /*
    3737             :      * Renaming the columns of sequences or toast tables doesn't actually
    3738             :      * break anything from the system's point of view, since internal
    3739             :      * references are by attnum.  But it doesn't seem right to allow users to
    3740             :      * change names that are hardcoded into the system, hence the following
    3741             :      * restriction.
    3742             :      */
    3743         980 :     if (relkind != RELKIND_RELATION &&
    3744          84 :         relkind != RELKIND_VIEW &&
    3745          84 :         relkind != RELKIND_MATVIEW &&
    3746          36 :         relkind != RELKIND_COMPOSITE_TYPE &&
    3747          36 :         relkind != RELKIND_INDEX &&
    3748          36 :         relkind != RELKIND_PARTITIONED_INDEX &&
    3749           0 :         relkind != RELKIND_FOREIGN_TABLE &&
    3750             :         relkind != RELKIND_PARTITIONED_TABLE)
    3751           0 :         ereport(ERROR,
    3752             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3753             :                  errmsg("cannot rename columns of relation \"%s\"",
    3754             :                         NameStr(classform->relname)),
    3755             :                  errdetail_relkind_not_supported(relkind)));
    3756             : 
    3757             :     /*
    3758             :      * permissions checking.  only the owner of a class can change its schema.
    3759             :      */
    3760         980 :     if (!object_ownercheck(RelationRelationId, myrelid, GetUserId()))
    3761           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)),
    3762           0 :                        NameStr(classform->relname));
    3763         980 :     if (!allowSystemTableMods && IsSystemClass(myrelid, classform))
    3764           2 :         ereport(ERROR,
    3765             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3766             :                  errmsg("permission denied: \"%s\" is a system catalog",
    3767             :                         NameStr(classform->relname))));
    3768         978 : }
    3769             : 
    3770             : /*
    3771             :  *      renameatt_internal      - workhorse for renameatt
    3772             :  *
    3773             :  * Return value is the attribute number in the 'myrelid' relation.
    3774             :  */
    3775             : static AttrNumber
    3776         540 : renameatt_internal(Oid myrelid,
    3777             :                    const char *oldattname,
    3778             :                    const char *newattname,
    3779             :                    bool recurse,
    3780             :                    bool recursing,
    3781             :                    int expected_parents,
    3782             :                    DropBehavior behavior)
    3783             : {
    3784             :     Relation    targetrelation;
    3785             :     Relation    attrelation;
    3786             :     HeapTuple   atttup;
    3787             :     Form_pg_attribute attform;
    3788             :     AttrNumber  attnum;
    3789             : 
    3790             :     /*
    3791             :      * Grab an exclusive lock on the target table, which we will NOT release
    3792             :      * until end of transaction.
    3793             :      */
    3794         540 :     targetrelation = relation_open(myrelid, AccessExclusiveLock);
    3795         540 :     renameatt_check(myrelid, RelationGetForm(targetrelation), recursing);
    3796             : 
    3797             :     /*
    3798             :      * if the 'recurse' flag is set then we are supposed to rename this
    3799             :      * attribute in all classes that inherit from 'relname' (as well as in
    3800             :      * 'relname').
    3801             :      *
    3802             :      * any permissions or problems with duplicate attributes will cause the
    3803             :      * whole transaction to abort, which is what we want -- all or nothing.
    3804             :      */
    3805         540 :     if (recurse)
    3806             :     {
    3807             :         List       *child_oids,
    3808             :                    *child_numparents;
    3809             :         ListCell   *lo,
    3810             :                    *li;
    3811             : 
    3812             :         /*
    3813             :          * we need the number of parents for each child so that the recursive
    3814             :          * calls to renameatt() can determine whether there are any parents
    3815             :          * outside the inheritance hierarchy being processed.
    3816             :          */
    3817         236 :         child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
    3818             :                                          &child_numparents);
    3819             : 
    3820             :         /*
    3821             :          * find_all_inheritors does the recursive search of the inheritance
    3822             :          * hierarchy, so all we have to do is process all of the relids in the
    3823             :          * list that it returns.
    3824             :          */
    3825         710 :         forboth(lo, child_oids, li, child_numparents)
    3826             :         {
    3827         504 :             Oid         childrelid = lfirst_oid(lo);
    3828         504 :             int         numparents = lfirst_int(li);
    3829             : 
    3830         504 :             if (childrelid == myrelid)
    3831         236 :                 continue;
    3832             :             /* note we need not recurse again */
    3833         268 :             renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
    3834             :         }
    3835             :     }
    3836             :     else
    3837             :     {
    3838             :         /*
    3839             :          * If we are told not to recurse, there had better not be any child
    3840             :          * tables; else the rename would put them out of step.
    3841             :          *
    3842             :          * expected_parents will only be 0 if we are not already recursing.
    3843             :          */
    3844         340 :         if (expected_parents == 0 &&
    3845          36 :             find_inheritance_children(myrelid, NoLock) != NIL)
    3846          12 :             ereport(ERROR,
    3847             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3848             :                      errmsg("inherited column \"%s\" must be renamed in child tables too",
    3849             :                             oldattname)));
    3850             :     }
    3851             : 
    3852             :     /* rename attributes in typed tables of composite type */
    3853         498 :     if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
    3854             :     {
    3855             :         List       *child_oids;
    3856             :         ListCell   *lo;
    3857             : 
    3858          24 :         child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
    3859          24 :                                                    RelationGetRelationName(targetrelation),
    3860             :                                                    behavior);
    3861             : 
    3862          24 :         foreach(lo, child_oids)
    3863           6 :             renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
    3864             :     }
    3865             : 
    3866         492 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
    3867             : 
    3868         492 :     atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
    3869         492 :     if (!HeapTupleIsValid(atttup))
    3870          24 :         ereport(ERROR,
    3871             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    3872             :                  errmsg("column \"%s\" does not exist",
    3873             :                         oldattname)));
    3874         468 :     attform = (Form_pg_attribute) GETSTRUCT(atttup);
    3875             : 
    3876         468 :     attnum = attform->attnum;
    3877         468 :     if (attnum <= 0)
    3878           0 :         ereport(ERROR,
    3879             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3880             :                  errmsg("cannot rename system column \"%s\"",
    3881             :                         oldattname)));
    3882             : 
    3883             :     /*
    3884             :      * if the attribute is inherited, forbid the renaming.  if this is a
    3885             :      * top-level call to renameatt(), then expected_parents will be 0, so the
    3886             :      * effect of this code will be to prohibit the renaming if the attribute
    3887             :      * is inherited at all.  if this is a recursive call to renameatt(),
    3888             :      * expected_parents will be the number of parents the current relation has
    3889             :      * within the inheritance hierarchy being processed, so we'll prohibit the
    3890             :      * renaming only if there are additional parents from elsewhere.
    3891             :      */
    3892         468 :     if (attform->attinhcount > expected_parents)
    3893          30 :         ereport(ERROR,
    3894             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    3895             :                  errmsg("cannot rename inherited column \"%s\"",
    3896             :                         oldattname)));
    3897             : 
    3898             :     /* new name should not already exist */
    3899         438 :     (void) check_for_column_name_collision(targetrelation, newattname, false);
    3900             : 
    3901             :     /* apply the update */
    3902         426 :     namestrcpy(&(attform->attname), newattname);
    3903             : 
    3904         426 :     CatalogTupleUpdate(attrelation, &atttup->t_self, atttup);
    3905             : 
    3906         426 :     InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
    3907             : 
    3908         426 :     heap_freetuple(atttup);
    3909             : 
    3910         426 :     table_close(attrelation, RowExclusiveLock);
    3911             : 
    3912         426 :     relation_close(targetrelation, NoLock); /* close rel but keep lock */
    3913             : 
    3914         426 :     return attnum;
    3915             : }
    3916             : 
    3917             : /*
    3918             :  * Perform permissions and integrity checks before acquiring a relation lock.
    3919             :  */
    3920             : static void
    3921         406 : RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid,
    3922             :                                    void *arg)
    3923             : {
    3924             :     HeapTuple   tuple;
    3925             :     Form_pg_class form;
    3926             : 
    3927         406 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    3928         406 :     if (!HeapTupleIsValid(tuple))
    3929          38 :         return;                 /* concurrently dropped */
    3930         368 :     form = (Form_pg_class) GETSTRUCT(tuple);
    3931         368 :     renameatt_check(relid, form, false);
    3932         360 :     ReleaseSysCache(tuple);
    3933             : }
    3934             : 
    3935             : /*
    3936             :  *      renameatt       - changes the name of an attribute in a relation
    3937             :  *
    3938             :  * The returned ObjectAddress is that of the renamed column.
    3939             :  */
    3940             : ObjectAddress
    3941         304 : renameatt(RenameStmt *stmt)
    3942             : {
    3943             :     Oid         relid;
    3944             :     AttrNumber  attnum;
    3945             :     ObjectAddress address;
    3946             : 
    3947             :     /* lock level taken here should match renameatt_internal */
    3948         304 :     relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
    3949         304 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
    3950             :                                      RangeVarCallbackForRenameAttribute,
    3951             :                                      NULL);
    3952             : 
    3953         290 :     if (!OidIsValid(relid))
    3954             :     {
    3955          24 :         ereport(NOTICE,
    3956             :                 (errmsg("relation \"%s\" does not exist, skipping",
    3957             :                         stmt->relation->relname)));
    3958          24 :         return InvalidObjectAddress;
    3959             :     }
    3960             : 
    3961             :     attnum =
    3962         266 :         renameatt_internal(relid,
    3963         266 :                            stmt->subname,    /* old att name */
    3964         266 :                            stmt->newname,    /* new att name */
    3965         266 :                            stmt->relation->inh, /* recursive? */
    3966             :                            false,   /* recursing? */
    3967             :                            0,   /* expected inhcount */
    3968             :                            stmt->behavior);
    3969             : 
    3970         182 :     ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
    3971             : 
    3972         182 :     return address;
    3973             : }
    3974             : 
    3975             : /*
    3976             :  * same logic as renameatt_internal
    3977             :  */
    3978             : static ObjectAddress
    3979          84 : rename_constraint_internal(Oid myrelid,
    3980             :                            Oid mytypid,
    3981             :                            const char *oldconname,
    3982             :                            const char *newconname,
    3983             :                            bool recurse,
    3984             :                            bool recursing,
    3985             :                            int expected_parents)
    3986             : {
    3987          84 :     Relation    targetrelation = NULL;
    3988             :     Oid         constraintOid;
    3989             :     HeapTuple   tuple;
    3990             :     Form_pg_constraint con;
    3991             :     ObjectAddress address;
    3992             : 
    3993             :     Assert(!myrelid || !mytypid);
    3994             : 
    3995          84 :     if (mytypid)
    3996             :     {
    3997           6 :         constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
    3998             :     }
    3999             :     else
    4000             :     {
    4001          78 :         targetrelation = relation_open(myrelid, AccessExclusiveLock);
    4002             : 
    4003             :         /*
    4004             :          * don't tell it whether we're recursing; we allow changing typed
    4005             :          * tables here
    4006             :          */
    4007          78 :         renameatt_check(myrelid, RelationGetForm(targetrelation), false);
    4008             : 
    4009          78 :         constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
    4010             :     }
    4011             : 
    4012          84 :     tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
    4013          84 :     if (!HeapTupleIsValid(tuple))
    4014           0 :         elog(ERROR, "cache lookup failed for constraint %u",
    4015             :              constraintOid);
    4016          84 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
    4017             : 
    4018          84 :     if (myrelid &&
    4019          78 :         (con->contype == CONSTRAINT_CHECK ||
    4020          18 :          con->contype == CONSTRAINT_NOTNULL) &&
    4021          60 :         !con->connoinherit)
    4022             :     {
    4023          48 :         if (recurse)
    4024             :         {
    4025             :             List       *child_oids,
    4026             :                        *child_numparents;
    4027             :             ListCell   *lo,
    4028             :                        *li;
    4029             : 
    4030          30 :             child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
    4031             :                                              &child_numparents);
    4032             : 
    4033          72 :             forboth(lo, child_oids, li, child_numparents)
    4034             :             {
    4035          42 :                 Oid         childrelid = lfirst_oid(lo);
    4036          42 :                 int         numparents = lfirst_int(li);
    4037             : 
    4038          42 :                 if (childrelid == myrelid)
    4039          30 :                     continue;
    4040             : 
    4041          12 :                 rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
    4042             :             }
    4043             :         }
    4044             :         else
    4045             :         {
    4046          24 :             if (expected_parents == 0 &&
    4047           6 :                 find_inheritance_children(myrelid, NoLock) != NIL)
    4048           6 :                 ereport(ERROR,
    4049             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4050             :                          errmsg("inherited constraint \"%s\" must be renamed in child tables too",
    4051             :                                 oldconname)));
    4052             :         }
    4053             : 
    4054          42 :         if (con->coninhcount > expected_parents)
    4055           6 :             ereport(ERROR,
    4056             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    4057             :                      errmsg("cannot rename inherited constraint \"%s\"",
    4058             :                             oldconname)));
    4059             :     }
    4060             : 
    4061          72 :     if (con->conindid
    4062          18 :         && (con->contype == CONSTRAINT_PRIMARY
    4063           6 :             || con->contype == CONSTRAINT_UNIQUE
    4064           0 :             || con->contype == CONSTRAINT_EXCLUSION))
    4065             :         /* rename the index; this renames the constraint as well */
    4066          18 :         RenameRelationInternal(con->conindid, newconname, false, true);
    4067             :     else
    4068          54 :         RenameConstraintById(constraintOid, newconname);
    4069             : 
    4070          72 :     ObjectAddressSet(address, ConstraintRelationId, constraintOid);
    4071             : 
    4072          72 :     ReleaseSysCache(tuple);
    4073             : 
    4074          72 :     if (targetrelation)
    4075             :     {
    4076             :         /*
    4077             :          * Invalidate relcache so as others can see the new constraint name.
    4078             :          */
    4079          66 :         CacheInvalidateRelcache(targetrelation);
    4080             : 
    4081          66 :         relation_close(targetrelation, NoLock); /* close rel but keep lock */
    4082             :     }
    4083             : 
    4084          72 :     return address;
    4085             : }
    4086             : 
    4087             : ObjectAddress
    4088          78 : RenameConstraint(RenameStmt *stmt)
    4089             : {
    4090          78 :     Oid         relid = InvalidOid;
    4091          78 :     Oid         typid = InvalidOid;
    4092             : 
    4093          78 :     if (stmt->renameType == OBJECT_DOMCONSTRAINT)
    4094             :     {
    4095             :         Relation    rel;
    4096             :         HeapTuple   tup;
    4097             : 
    4098           6 :         typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
    4099           6 :         rel = table_open(TypeRelationId, RowExclusiveLock);
    4100           6 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    4101           6 :         if (!HeapTupleIsValid(tup))
    4102           0 :             elog(ERROR, "cache lookup failed for type %u", typid);
    4103           6 :         checkDomainOwner(tup);
    4104           6 :         ReleaseSysCache(tup);
    4105           6 :         table_close(rel, NoLock);
    4106             :     }
    4107             :     else
    4108             :     {
    4109             :         /* lock level taken here should match rename_constraint_internal */
    4110          72 :         relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
    4111          72 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
    4112             :                                          RangeVarCallbackForRenameAttribute,
    4113             :                                          NULL);
    4114          72 :         if (!OidIsValid(relid))
    4115             :         {
    4116           6 :             ereport(NOTICE,
    4117             :                     (errmsg("relation \"%s\" does not exist, skipping",
    4118             :                             stmt->relation->relname)));
    4119           6 :             return InvalidObjectAddress;
    4120             :         }
    4121             :     }
    4122             : 
    4123             :     return
    4124          72 :         rename_constraint_internal(relid, typid,
    4125          72 :                                    stmt->subname,
    4126          72 :                                    stmt->newname,
    4127         138 :                                    (stmt->relation &&
    4128          66 :                                     stmt->relation->inh), /* recursive? */
    4129             :                                    false,   /* recursing? */
    4130             :                                    0 /* expected inhcount */ );
    4131             : }
    4132             : 
    4133             : /*
    4134             :  * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
    4135             :  * RENAME
    4136             :  */
    4137             : ObjectAddress
    4138         510 : RenameRelation(RenameStmt *stmt)
    4139             : {
    4140         510 :     bool        is_index_stmt = stmt->renameType == OBJECT_INDEX;
    4141             :     Oid         relid;
    4142             :     ObjectAddress address;
    4143             : 
    4144             :     /*
    4145             :      * Grab an exclusive lock on the target table, index, sequence, view,
    4146             :      * materialized view, or foreign table, which we will NOT release until
    4147             :      * end of transaction.
    4148             :      *
    4149             :      * Lock level used here should match RenameRelationInternal, to avoid lock
    4150             :      * escalation.  However, because ALTER INDEX can be used with any relation
    4151             :      * type, we mustn't believe without verification.
    4152             :      */
    4153             :     for (;;)
    4154          12 :     {
    4155             :         LOCKMODE    lockmode;
    4156             :         char        relkind;
    4157             :         bool        obj_is_index;
    4158             : 
    4159         522 :         lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
    4160             : 
    4161         522 :         relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
    4162         522 :                                          stmt->missing_ok ? RVR_MISSING_OK : 0,
    4163             :                                          RangeVarCallbackForAlterRelation,
    4164             :                                          (void *) stmt);
    4165             : 
    4166         472 :         if (!OidIsValid(relid))
    4167             :         {
    4168          18 :             ereport(NOTICE,
    4169             :                     (errmsg("relation \"%s\" does not exist, skipping",
    4170             :                             stmt->relation->relname)));
    4171          18 :             return InvalidObjectAddress;
    4172             :         }
    4173             : 
    4174             :         /*
    4175             :          * We allow mismatched statement and object types (e.g., ALTER INDEX
    4176             :          * to rename a table), but we might've used the wrong lock level.  If
    4177             :          * that happens, retry with the correct lock level.  We don't bother
    4178             :          * if we already acquired AccessExclusiveLock with an index, however.
    4179             :          */
    4180         454 :         relkind = get_rel_relkind(relid);
    4181         454 :         obj_is_index = (relkind == RELKIND_INDEX ||
    4182             :                         relkind == RELKIND_PARTITIONED_INDEX);
    4183         454 :         if (obj_is_index || is_index_stmt == obj_is_index)
    4184             :             break;
    4185             : 
    4186          12 :         UnlockRelationOid(relid, lockmode);
    4187          12 :         is_index_stmt = obj_is_index;
    4188             :     }
    4189             : 
    4190             :     /* Do the work */
    4191         442 :     RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
    4192             : 
    4193         430 :     ObjectAddressSet(address, RelationRelationId, relid);
    4194             : 
    4195         430 :     return address;
    4196             : }
    4197             : 
    4198             : /*
    4199             :  *      RenameRelationInternal - change the name of a relation
    4200             :  */
    4201             : void
    4202        1330 : RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
    4203             : {
    4204             :     Relation    targetrelation;
    4205             :     Relation    relrelation;    /* for RELATION relation */
    4206             :     HeapTuple   reltup;
    4207             :     Form_pg_class relform;
    4208             :     Oid         namespaceId;
    4209             : 
    4210             :     /*
    4211             :      * Grab a lock on the target relation, which we will NOT release until end
    4212             :      * of transaction.  We need at least a self-exclusive lock so that
    4213             :      * concurrent DDL doesn't overwrite the rename if they start updating
    4214             :      * while still seeing the old version.  The lock also guards against
    4215             :      * triggering relcache reloads in concurrent sessions, which might not
    4216             :      * handle this information changing under them.  For indexes, we can use a
    4217             :      * reduced lock level because RelationReloadIndexInfo() handles indexes
    4218             :      * specially.
    4219             :      */
    4220        1330 :     targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
    4221        1330 :     namespaceId = RelationGetNamespace(targetrelation);
    4222             : 
    4223             :     /*
    4224             :      * Find relation's pg_class tuple, and make sure newrelname isn't in use.
    4225             :      */
    4226        1330 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
    4227             : 
    4228        1330 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
    4229        1330 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
    4230           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
    4231        1330 :     relform = (Form_pg_class) GETSTRUCT(reltup);
    4232             : 
    4233        1330 :     if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
    4234          12 :         ereport(ERROR,
    4235             :                 (errcode(ERRCODE_DUPLICATE_TABLE),
    4236             :                  errmsg("relation \"%s\" already exists",
    4237             :                         newrelname)));
    4238             : 
    4239             :     /*
    4240             :      * RenameRelation is careful not to believe the caller's idea of the
    4241             :      * relation kind being handled.  We don't have to worry about this, but
    4242             :      * let's not be totally oblivious to it.  We can process an index as
    4243             :      * not-an-index, but not the other way around.
    4244             :      */
    4245             :     Assert(!is_index ||
    4246             :            is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
    4247             :                         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
    4248             : 
    4249             :     /*
    4250             :      * Update pg_class tuple with new relname.  (Scribbling on reltup is OK
    4251             :      * because it's a copy...)
    4252             :      */
    4253        1318 :     namestrcpy(&(relform->relname), newrelname);
    4254             : 
    4255        1318 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
    4256             : 
    4257        1318 :     InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
    4258             :                                  InvalidOid, is_internal);
    4259             : 
    4260        1318 :     heap_freetuple(reltup);
    4261        1318 :     table_close(relrelation, RowExclusiveLock);
    4262             : 
    4263             :     /*
    4264             :      * Also rename the associated type, if any.
    4265             :      */
    4266        1318 :     if (OidIsValid(targetrelation->rd_rel->reltype))
    4267         154 :         RenameTypeInternal(targetrelation->rd_rel->reltype,
    4268             :                            newrelname, namespaceId);
    4269             : 
    4270             :     /*
    4271             :      * Also rename the associated constraint, if any.
    4272             :      */
    4273        1318 :     if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
    4274         718 :         targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
    4275             :     {
    4276         618 :         Oid         constraintId = get_index_constraint(myrelid);
    4277             : 
    4278         618 :         if (OidIsValid(constraintId))
    4279          36 :             RenameConstraintById(constraintId, newrelname);
    4280             :     }
    4281             : 
    4282             :     /*
    4283             :      * Close rel, but keep lock!
    4284             :      */
    4285        1318 :     relation_close(targetrelation, NoLock);
    4286        1318 : }
    4287             : 
    4288             : /*
    4289             :  *      ResetRelRewrite - reset relrewrite
    4290             :  */
    4291             : void
    4292         412 : ResetRelRewrite(Oid myrelid)
    4293             : {
    4294             :     Relation    relrelation;    /* for RELATION relation */
    4295             :     HeapTuple   reltup;
    4296             :     Form_pg_class relform;
    4297             : 
    4298             :     /*
    4299             :      * Find relation's pg_class tuple.
    4300             :      */
    4301         412 :     relrelation = table_open(RelationRelationId, RowExclusiveLock);
    4302             : 
    4303         412 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
    4304         412 :     if (!HeapTupleIsValid(reltup))  /* shouldn't happen */
    4305           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
    4306         412 :     relform = (Form_pg_class) GETSTRUCT(reltup);
    4307             : 
    4308             :     /*
    4309             :      * Update pg_class tuple.
    4310             :      */
    4311         412 :     relform->relrewrite = InvalidOid;
    4312             : 
    4313         412 :     CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
    4314             : 
    4315         412 :     heap_freetuple(reltup);
    4316         412 :     table_close(relrelation, RowExclusiveLock);
    4317         412 : }
    4318             : 
    4319             : /*
    4320             :  * Disallow ALTER TABLE (and similar commands) when the current backend has
    4321             :  * any open reference to the target table besides the one just acquired by
    4322             :  * the calling command; this implies there's an open cursor or active plan.
    4323             :  * We need this check because our lock doesn't protect us against stomping
    4324             :  * on our own foot, only other people's feet!
    4325             :  *
    4326             :  * For ALTER TABLE, the only case known to cause serious trouble is ALTER
    4327             :  * COLUMN TYPE, and some changes are obviously pretty benign, so this could
    4328             :  * possibly be relaxed to only error out for certain types of alterations.
    4329             :  * But the use-case for allowing any of these things is not obvious, so we
    4330             :  * won't work hard at it for now.
    4331             :  *
    4332             :  * We also reject these commands if there are any pending AFTER trigger events
    4333             :  * for the rel.  This is certainly necessary for the rewriting variants of
    4334             :  * ALTER TABLE, because they don't preserve tuple TIDs and so the pending
    4335             :  * events would try to fetch the wrong tuples.  It might be overly cautious
    4336             :  * in other cases, but again it seems better to err on the side of paranoia.
    4337             :  *
    4338             :  * REINDEX calls this with "rel" referencing the index to be rebuilt; here
    4339             :  * we are worried about active indexscans on the index.  The trigger-event
    4340             :  * check can be skipped, since we are doing no damage to the parent table.
    4341             :  *
    4342             :  * The statement name (eg, "ALTER TABLE") is passed for use in error messages.
    4343             :  */
    4344             : void
    4345      136604 : CheckTableNotInUse(Relation rel, const char *stmt)
    4346             : {
    4347             :     int         expected_refcnt;
    4348             : 
    4349      136604 :     expected_refcnt = rel->rd_isnailed ? 2 : 1;
    4350      136604 :     if (rel->rd_refcnt != expected_refcnt)
    4351          24 :         ereport(ERROR,
    4352             :                 (errcode(ERRCODE_OBJECT_IN_USE),
    4353             :         /* translator: first %s is a SQL command, eg ALTER TABLE */
    4354             :                  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
    4355             :                         stmt, RelationGetRelationName(rel))));
    4356             : 
    4357      136580 :     if (rel->rd_rel->relkind != RELKIND_INDEX &&
    4358      214078 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
    4359      106008 :         AfterTriggerPendingOnRel(RelationGetRelid(rel)))
    4360          18 :         ereport(ERROR,
    4361             :                 (errcode(ERRCODE_OBJECT_IN_USE),
    4362             :         /* translator: first %s is a SQL command, eg ALTER TABLE */
    4363             :                  errmsg("cannot %s \"%s\" because it has pending trigger events",
    4364             :                         stmt, RelationGetRelationName(rel))));
    4365      136562 : }
    4366             : 
    4367             : /*
    4368             :  * AlterTableLookupRelation
    4369             :  *      Look up, and lock, the OID for the relation named by an alter table
    4370             :  *      statement.
    4371             :  */
    4372             : Oid
    4373       34476 : AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode)
    4374             : {
    4375       68868 :     return RangeVarGetRelidExtended(stmt->relation, lockmode,
    4376       34476 :                                     stmt->missing_ok ? RVR_MISSING_OK : 0,
    4377             :                                     RangeVarCallbackForAlterRelation,
    4378             :                                     (void *) stmt);
    4379             : }
    4380             : 
    4381             : /*
    4382             :  * AlterTable
    4383             :  *      Execute ALTER TABLE, which can be a list of subcommands
    4384             :  *
    4385             :  * ALTER TABLE is performed in three phases:
    4386             :  *      1. Examine subcommands and perform pre-transformation checking.
    4387             :  *      2. Validate and transform subcommands, and update system catalogs.
    4388             :  *      3. Scan table(s) to check new constraints, and optionally recopy
    4389             :  *         the data into new table(s).
    4390             :  * Phase 3 is not performed unless one or more of the subcommands requires
    4391             :  * it.  The intention of this design is to allow multiple independent
    4392             :  * updates of the table schema to be performed with only one pass over the
    4393             :  * data.
    4394             :  *
    4395             :  * ATPrepCmd performs phase 1.  A "work queue" entry is created for
    4396             :  * each table to be affected (there may be multiple affected tables if the
    4397             :  * commands traverse a table inheritance hierarchy).  Also we do preliminary
    4398             :  * validation of the subcommands.  Because earlier subcommands may change
    4399             :  * the catalog state seen by later commands, there are limits to what can
    4400             :  * be done in this phase.  Generally, this phase acquires table locks,
    4401             :  * checks permissions and relkind, and recurses to find child tables.
    4402             :  *
    4403             :  * ATRewriteCatalogs performs phase 2 for each affected table.
    4404             :  * Certain subcommands need to be performed before others to avoid
    4405             :  * unnecessary conflicts; for example, DROP COLUMN should come before
    4406             :  * ADD COLUMN.  Therefore phase 1 divides the subcommands into multiple
    4407             :  * lists, one for each logical "pass" of phase 2.
    4408             :  *
    4409             :  * ATRewriteTables performs phase 3 for those tables that need it.
    4410             :  *
    4411             :  * For most subcommand types, phases 2 and 3 do no explicit recursion,
    4412             :  * since phase 1 already does it.  However, for certain subcommand types
    4413             :  * it is only possible to determine how to recurse at phase 2 time; for
    4414             :  * those cases, phase 1 sets the cmd->recurse flag.
    4415             :  *
    4416             :  * Thanks to the magic of MVCC, an error anywhere along the way rolls back
    4417             :  * the whole operation; we don't have to do anything special to clean up.
    4418             :  *
    4419             :  * The caller must lock the relation, with an appropriate lock level
    4420             :  * for the subcommands requested, using AlterTableGetLockLevel(stmt->cmds)
    4421             :  * or higher. We pass the lock level down
    4422             :  * so that we can apply it recursively to inherited tables. Note that the
    4423             :  * lock level we want as we recurse might well be higher than required for
    4424             :  * that specific subcommand. So we pass down the overall lock requirement,
    4425             :  * rather than reassess it at lower levels.
    4426             :  *
    4427             :  * The caller also provides a "context" which is to be passed back to
    4428             :  * utility.c when we need to execute a subcommand such as CREATE INDEX.
    4429             :  * Some of the fields therein, such as the relid, are used here as well.
    4430             :  */
    4431             : void
    4432       34254 : AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode,
    4433             :            AlterTableUtilityContext *context)
    4434             : {
    4435             :     Relation    rel;
    4436             : 
    4437             :     /* Caller is required to provide an adequate lock. */
    4438       34254 :     rel = relation_open(context->relid, NoLock);
    4439             : 
    4440       34254 :     CheckTableNotInUse(rel, "ALTER TABLE");
    4441             : 
    4442       34236 :     ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
    4443       31010 : }
    4444             : 
    4445             : /*
    4446             :  * AlterTableInternal
    4447             :  *
    4448             :  * ALTER TABLE with target specified by OID
    4449             :  *
    4450             :  * We do not reject if the relation is already open, because it's quite
    4451             :  * likely that one or more layers of caller have it open.  That means it
    4452             :  * is unsafe to use this entry point for alterations that could break
    4453             :  * existing query plans.  On the assumption it's not used for such, we
    4454             :  * don't have to reject pending AFTER triggers, either.
    4455             :  *
    4456             :  * Also, since we don't have an AlterTableUtilityContext, this cannot be
    4457             :  * used for any subcommand types that require parse transformation or
    4458             :  * could generate subcommands that have to be passed to ProcessUtility.
    4459             :  */
    4460             : void
    4461         278 : AlterTableInternal(Oid relid, List *cmds, bool recurse)
    4462             : {
    4463             :     Relation    rel;
    4464         278 :     LOCKMODE    lockmode = AlterTableGetLockLevel(cmds);
    4465             : 
    4466         278 :     rel = relation_open(relid, lockmode);
    4467             : 
    4468         278 :     EventTriggerAlterTableRelid(relid);
    4469             : 
    4470         278 :     ATController(NULL, rel, cmds, recurse, lockmode, NULL);
    4471         278 : }
    4472             : 
    4473             : /*
    4474             :  * AlterTableGetLockLevel
    4475             :  *
    4476             :  * Sets the overall lock level required for the supplied list of subcommands.
    4477             :  * Policy for doing this set according to needs of AlterTable(), see
    4478             :  * comments there for overall explanation.
    4479             :  *
    4480             :  * Function is called before and after parsing, so it must give same
    4481             :  * answer each time it is called. Some subcommands are transformed
    4482             :  * into other subcommand types, so the transform must never be made to a
    4483             :  * lower lock level than previously assigned. All transforms are noted below.
    4484             :  *
    4485             :  * Since this is called before we lock the table we cannot use table metadata
    4486             :  * to influence the type of lock we acquire.
    4487             :  *
    4488             :  * There should be no lockmodes hardcoded into the subcommand functions. All
    4489             :  * lockmode decisions for ALTER TABLE are made here only. The one exception is
    4490             :  * ALTER TABLE RENAME which is treated as a different statement type T_RenameStmt
    4491             :  * and does not travel through this section of code and cannot be combined with
    4492             :  * any of the subcommands given here.
    4493             :  *
    4494             :  * Note that Hot Standby only knows about AccessExclusiveLocks on the primary
    4495             :  * so any changes that might affect SELECTs running on standbys need to use
    4496             :  * AccessExclusiveLocks even if you think a lesser lock would do, unless you
    4497             :  * have a solution for that also.
    4498             :  *
    4499             :  * Also note that pg_dump uses only an AccessShareLock, meaning that anything
    4500             :  * that takes a lock less than AccessExclusiveLock can change object definitions
    4501             :  * while pg_dump is running. Be careful to check that the appropriate data is
    4502             :  * derived by pg_dump using an MVCC snapshot, rather than syscache lookups,
    4503             :  * otherwise we might end up with an inconsistent dump that can't restore.
    4504             :  */
    4505             : LOCKMODE
    4506       34754 : AlterTableGetLockLevel(List *cmds)
    4507             : {
    4508             :     /*
    4509             :      * This only works if we read catalog tables using MVCC snapshots.
    4510             :      */
    4511             :     ListCell   *lcmd;
    4512       34754 :     LOCKMODE    lockmode = ShareUpdateExclusiveLock;
    4513             : 
    4514       71464 :     foreach(lcmd, cmds)
    4515             :     {
    4516       36710 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
    4517       36710 :         LOCKMODE    cmd_lockmode = AccessExclusiveLock; /* default for compiler */
    4518             : 
    4519       36710 :         switch (cmd->subtype)
    4520             :         {
    4521             :                 /*
    4522             :                  * These subcommands rewrite the heap, so require full locks.
    4523             :                  */
    4524        3216 :             case AT_AddColumn:  /* may rewrite heap, in some cases and visible
    4525             :                                  * to SELECT */
    4526             :             case AT_SetAccessMethod:    /* must rewrite heap */
    4527             :             case AT_SetTableSpace:  /* must rewrite heap */
    4528             :             case AT_AlterColumnType:    /* must rewrite heap */
    4529        3216 :                 cmd_lockmode = AccessExclusiveLock;
    4530        3216 :                 break;
    4531             : 
    4532             :                 /*
    4533             :                  * These subcommands may require addition of toast tables. If
    4534             :                  * we add a toast table to a table currently being scanned, we
    4535             :                  * might miss data added to the new toast table by concurrent
    4536             :                  * insert transactions.
    4537             :                  */
    4538         212 :             case AT_SetStorage: /* may add toast tables, see
    4539             :                                  * ATRewriteCatalogs() */
    4540         212 :                 cmd_lockmode = AccessExclusiveLock;
    4541         212 :                 break;
    4542             : 
    4543             :                 /*
    4544             :                  * Removing constraints can affect SELECTs that have been
    4545             :                  * optimized assuming the constraint holds true. See also
    4546             :                  * CloneFkReferenced.
    4547             :                  */
    4548        1228 :             case AT_DropConstraint: /* as DROP INDEX */
    4549             :             case AT_DropNotNull:    /* may change some SQL plans */
    4550        1228 :                 cmd_lockmode = AccessExclusiveLock;
    4551        1228 :                 break;
    4552             : 
    4553             :                 /*
    4554             :                  * Subcommands that may be visible to concurrent SELECTs
    4555             :                  */
    4556        1710 :             case AT_DropColumn: /* change visible to SELECT */
    4557             :             case AT_AddColumnToView:    /* CREATE VIEW */
    4558             :             case AT_DropOids:   /* used to equiv to DropColumn */
    4559             :             case AT_EnableAlwaysRule:   /* may change SELECT rules */
    4560             :             case AT_EnableReplicaRule:  /* may change SELECT rules */
    4561             :             case AT_EnableRule: /* may change SELECT rules */
    4562             :             case AT_DisableRule:    /* may change SELECT rules */
    4563        1710 :                 cmd_lockmode = AccessExclusiveLock;
    4564        1710 :                 break;
    4565             : 
    4566             :                 /*
    4567             :                  * Changing owner may remove implicit SELECT privileges
    4568             :                  */
    4569        1820 :             case AT_ChangeOwner:    /* change visible to SELECT */
    4570        1820 :                 cmd_lockmode = AccessExclusiveLock;
    4571        1820 :                 break;
    4572             : 
    4573             :                 /*
    4574             :                  * Changing foreign table options may affect optimization.
    4575             :                  */
    4576         238 :             case AT_GenericOptions:
    4577             :             case AT_AlterColumnGenericOptions:
    4578         238 :                 cmd_lockmode = AccessExclusiveLock;
    4579         238 :                 break;
    4580             : 
    4581             :                 /*
    4582             :                  * These subcommands affect write operations only.
    4583             :                  */
    4584         340 :             case AT_EnableTrig:
    4585             :             case AT_EnableAlwaysTrig:
    4586             :             case AT_EnableReplicaTrig:
    4587             :             case AT_EnableTrigAll:
    4588             :             case AT_EnableTrigUser:
    4589             :             case AT_DisableTrig:
    4590             :             case AT_DisableTrigAll:
    4591             :             case AT_DisableTrigUser:
    4592         340 :                 cmd_lockmode = ShareRowExclusiveLock;
    4593         340 :                 break;
    4594             : 
    4595             :                 /*
    4596             :                  * These subcommands affect write operations only. XXX
    4597             :                  * Theoretically, these could be ShareRowExclusiveLock.
    4598             :                  */
    4599        9540 :             case AT_ColumnDefault:
    4600             :             case AT_CookedColumnDefault:
    4601             :             case AT_AlterConstraint:
    4602             :             case AT_AddIndex:   /* from ADD CONSTRAINT */
    4603             :             case AT_AddIndexConstraint:
    4604             :             case AT_ReplicaIdentity:
    4605             :             case AT_SetNotNull:
    4606             :             case AT_SetAttNotNull:
    4607             :             case AT_EnableRowSecurity:
    4608             :             case AT_DisableRowSecurity:
    4609             :             case AT_ForceRowSecurity:
    4610             :             case AT_NoForceRowSecurity:
    4611             :             case AT_AddIdentity:
    4612             :             case AT_DropIdentity:
    4613             :             case AT_SetIdentity:
    4614             :             case AT_SetExpression:
    4615             :             case AT_DropExpression:
    4616             :             case AT_SetCompression:
    4617        9540 :                 cmd_lockmode = AccessExclusiveLock;
    4618        9540 :                 break;
    4619             : 
    4620       12804 :             case AT_AddConstraint:
    4621             :             case AT_ReAddConstraint:    /* becomes AT_AddConstraint */
    4622             :             case AT_ReAddDomainConstraint:  /* becomes AT_AddConstraint */
    4623       12804 :                 if (IsA(cmd->def, Constraint))
    4624             :                 {
    4625       12804 :                     Constraint *con = (Constraint *) cmd->def;
    4626             : 
    4627       12804 :                     switch (con->contype)
    4628             :                     {
    4629        9496 :                         case CONSTR_EXCLUSION:
    4630             :                         case CONSTR_PRIMARY:
    4631             :                         case CONSTR_UNIQUE:
    4632             : 
    4633             :                             /*
    4634             :                              * Cases essentially the same as CREATE INDEX. We
    4635             :                              * could reduce the lock strength to ShareLock if
    4636             :                              * we can work out how to allow concurrent catalog
    4637             :                              * updates. XXX Might be set down to
    4638             :                              * ShareRowExclusiveLock but requires further
    4639             :                              * analysis.
    4640             :                              */
    4641        9496 :                             cmd_lockmode = AccessExclusiveLock;
    4642        9496 :                             break;
    4643        2386 :                         case CONSTR_FOREIGN:
    4644             : 
    4645             :                             /*
    4646             :                              * We add triggers to both tables when we add a
    4647             :                              * Foreign Key, so the lock level must be at least
    4648             :                              * as strong as CREATE TRIGGER.
    4649             :                              */
    4650        2386 :                             cmd_lockmode = ShareRowExclusiveLock;
    4651        2386 :                             break;
    4652             : 
    4653         922 :                         default:
    4654         922 :                             cmd_lockmode = AccessExclusiveLock;
    4655             :                     }
    4656           0 :                 }
    4657       12804 :                 break;
    4658             : 
    4659             :                 /*
    4660             :                  * These subcommands affect inheritance behaviour. Queries
    4661             :                  * started before us will continue to see the old inheritance
    4662             :                  * behaviour, while queries started after we commit will see
    4663             :                  * new behaviour. No need to prevent reads or writes to the
    4664             :                  * subtable while we hook it up though. Changing the TupDesc
    4665             :                  * may be a problem, so keep highest lock.
    4666             :                  */
    4667         370 :             case AT_AddInherit:
    4668             :             case AT_DropInherit:
    4669         370 :                 cmd_lockmode = AccessExclusiveLock;
    4670         370 :                 break;
    4671             : 
    4672             :                 /*
    4673             :                  * These subcommands affect implicit row type conversion. They
    4674             :                  * have affects similar to CREATE/DROP CAST on queries. don't
    4675             :                  * provide for invalidating parse trees as a result of such
    4676             :                  * changes, so we keep these at AccessExclusiveLock.
    4677             :                  */
    4678          72 :             case AT_AddOf:
    4679             :             case AT_DropOf:
    4680          72 :                 cmd_lockmode = AccessExclusiveLock;
    4681          72 :                 break;
    4682             : 
    4683             :                 /*
    4684             :                  * Only used by CREATE OR REPLACE VIEW which must conflict
    4685             :                  * with an SELECTs currently using the view.
    4686             :                  */
    4687         194 :             case AT_ReplaceRelOptions:
    4688         194 :                 cmd_lockmode = AccessExclusiveLock;
    4689         194 :                 break;
    4690             : 
    4691             :                 /*
    4692             :                  * These subcommands affect general strategies for performance
    4693             :                  * and maintenance, though don't change the semantic results
    4694             :                  * from normal data reads and writes. Delaying an ALTER TABLE
    4695             :                  * behind currently active writes only delays the point where
    4696             :                  * the new strategy begins to take effect, so there is no
    4697             :                  * benefit in waiting. In this case the minimum restriction
    4698             :                  * applies: we don't currently allow concurrent catalog
    4699             :                  * updates.
    4700             :                  */
    4701         234 :             case AT_SetStatistics:  /* Uses MVCC in getTableAttrs() */
    4702             :             case AT_ClusterOn:  /* Uses MVCC in getIndexes() */
    4703             :             case AT_DropCluster:    /* Uses MVCC in getIndexes() */
    4704             :             case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
    4705             :             case AT_ResetOptions:   /* Uses MVCC in getTableAttrs() */
    4706         234 :                 cmd_lockmode = ShareUpdateExclusiveLock;
    4707         234 :                 break;
    4708             : 
    4709          88 :             case AT_SetLogged:
    4710             :             case AT_SetUnLogged:
    4711          88 :                 cmd_lockmode = AccessExclusiveLock;
    4712          88 :                 break;
    4713             : 
    4714         388 :             case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
    4715         388 :                 cmd_lockmode = ShareUpdateExclusiveLock;
    4716         388 :                 break;
    4717             : 
    4718             :                 /*
    4719             :                  * Rel options are more complex than first appears. Options
    4720             :                  * are set here for tables, views and indexes; for historical
    4721             :                  * reasons these can all be used with ALTER TABLE, so we can't
    4722             :                  * decide between them using the basic grammar.
    4723             :                  */
    4724         740 :             case AT_SetRelOptions:  /* Uses MVCC in getIndexes() and
    4725             :                                      * getTables() */
    4726             :             case AT_ResetRelOptions:    /* Uses MVCC in getIndexes() and
    4727             :                                          * getTables() */
    4728         740 :                 cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
    4729         740 :                 break;
    4730             : 
    4731        2602 :             case AT_AttachPartition:
    4732        2602 :                 cmd_lockmode = ShareUpdateExclusiveLock;
    4733        2602 :                 break;
    4734             : 
    4735         528 :             case AT_DetachPartition:
    4736         528 :                 if (((PartitionCmd *) cmd->def)->concurrent)
    4737         158 :                     cmd_lockmode = ShareUpdateExclusiveLock;
    4738             :                 else
    4739         370 :                     cmd_lockmode = AccessExclusiveLock;
    4740         528 :                 break;
    4741             : 
    4742          14 :             case AT_DetachPartitionFinalize:
    4743          14 :                 cmd_lockmode = ShareUpdateExclusiveLock;
    4744          14 :                 break;
    4745             : 
    4746         252 :             case AT_SplitPartition:
    4747         252 :                 cmd_lockmode = AccessExclusiveLock;
    4748         252 :                 break;
    4749             : 
    4750         120 :             case AT_MergePartitions:
    4751         120 :                 cmd_lockmode = AccessExclusiveLock;
    4752         120 :                 break;
    4753             : 
    4754           0 :             default:            /* oops */
    4755           0 :                 elog(ERROR, "unrecognized alter table type: %d",
    4756             :                      (int) cmd->subtype);
    4757             :                 break;
    4758             :         }
    4759             : 
    4760             :         /*
    4761             :          * Take the greatest lockmode from any subcommand
    4762             :          */
    4763       36710 :         if (cmd_lockmode > lockmode)
    4764       30804 :             lockmode = cmd_lockmode;
    4765             :     }
    4766             : 
    4767       34754 :     return lockmode;
    4768             : }
    4769             : 
    4770             : /*
    4771             :  * ATController provides top level control over the phases.
    4772             :  *
    4773             :  * parsetree is passed in to allow it to be passed to event triggers
    4774             :  * when requested.
    4775             :  */
    4776             : static void
    4777       34514 : ATController(AlterTableStmt *parsetree,
    4778             :              Relation rel, List *cmds, bool recurse, LOCKMODE lockmode,
    4779             :              AlterTableUtilityContext *context)
    4780             : {
    4781       34514 :     List       *wqueue = NIL;
    4782             :     ListCell   *lcmd;
    4783             : 
    4784             :     /* Phase 1: preliminary examination of commands, create work queue */
    4785       70706 :     foreach(lcmd, cmds)
    4786             :     {
    4787       36464 :         AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
    4788             : 
    4789       36464 :         ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
    4790             :     }
    4791             : 
    4792             :     /* Close the relation, but keep lock until commit */
    4793       34242 :     relation_close(rel, NoLock);
    4794             : 
    4795             :     /* Phase 2: update system catalogs */
    4796       34242 :     ATRewriteCatalogs(&wqueue, lockmode, context);
    4797             : 
    4798             :     /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
    4799       31612 :     ATRewriteTables(parsetree, &wqueue, lockmode, context);
    4800       31288 : }
    4801             : 
    4802             : /*
    4803             :  * ATPrepCmd
    4804             :  *
    4805             :  * Traffic cop for ALTER TABLE Phase 1 operations, including simple
    4806             :  * recursion and permission checks.
    4807             :  *
    4808             :  * Caller must have acquired appropriate lock type on relation already.
    4809             :  * This lock should be held until commit.
    4810             :  */
    4811             : static void
    4812       37098 : ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
    4813             :           bool recurse, bool recursing, LOCKMODE lockmode,
    4814             :           AlterTableUtilityContext *context)
    4815             : {
    4816             :     AlteredTableInfo *tab;
    4817       37098 :     AlterTablePass pass = AT_PASS_UNSET;
    4818             : 
    4819             :     /* Find or create work queue entry for this table */
    4820       37098 :     tab = ATGetQueueEntry(wqueue, rel);
    4821             : 
    4822             :     /*
    4823             :      * Disallow any ALTER TABLE other than ALTER TABLE DETACH FINALIZE on
    4824             :      * partitions that are pending detach.
    4825             :      */
    4826       37098 :     if (rel->rd_rel->relispartition &&
    4827        2616 :         cmd->subtype != AT_DetachPartitionFinalize &&
    4828        1308 :         PartitionHasPendingDetach(RelationGetRelid(rel)))
    4829           2 :         ereport(ERROR,
    4830             :                 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    4831             :                 errmsg("cannot alter partition \"%s\" with an incomplete detach",
    4832             :                        RelationGetRelationName(rel)),
    4833             :                 errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation."));
    4834             : 
    4835             :     /*
    4836             :      * Copy the original subcommand for each table, so we can scribble on it.
    4837             :      * This avoids conflicts when different child tables need to make
    4838             :      * different parse transformations (for example, the same column may have
    4839             :      * different column numbers in different children).
    4840             :      */
    4841       37096 :     cmd = copyObject(cmd);
    4842             : 
    4843             :     /*
    4844             :      * Do permissions and relkind checking, recursion to child tables if
    4845             :      * needed, and any additional phase-1 processing needed.  (But beware of
    4846             :      * adding any processing that looks at table details that another
    4847             :      * subcommand could change.  In some cases we reject multiple subcommands
    4848             :      * that could try to change the same state in contrary ways.)
    4849             :      */
    4850       37096 :     switch (cmd->subtype)
    4851             :     {
    4852        1956 :         case AT_AddColumn:      /* ADD COLUMN */
    4853        1956 :             ATSimplePermissions(cmd->subtype, rel,
    4854             :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
    4855        1956 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
    4856             :                             lockmode, context);
    4857             :             /* Recursion occurs during execution phase */
    4858        1944 :             pass = AT_PASS_ADD_COL;
    4859        1944 :             break;
    4860          24 :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
    4861          24 :             ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
    4862          24 :             ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
    4863             :                             lockmode, context);
    4864             :             /* Recursion occurs during execution phase */
    4865          24 :             pass = AT_PASS_ADD_COL;
    4866          24 :             break;
    4867         590 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
    4868             : 
    4869             :             /*
    4870             :              * We allow defaults on views so that INSERT into a view can have
    4871             :              * default-ish behavior.  This works because the rewriter
    4872             :              * substitutes default values into INSERTs before it expands
    4873             :              * rules.
    4874             :              */
    4875         590 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
    4876         590 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4877             :             /* No command-specific prep needed */
    4878         590 :             pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
    4879         590 :             break;
    4880         110 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
    4881             :             /* This is currently used only in CREATE TABLE */
    4882             :             /* (so the permission check really isn't necessary) */
    4883         110 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4884             :             /* This command never recurses */
    4885         110 :             pass = AT_PASS_ADD_OTHERCONSTR;
    4886         110 :             break;
    4887         154 :         case AT_AddIdentity:
    4888         154 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
    4889             :             /* Set up recursion for phase 2; no other prep needed */
    4890         154 :             if (recurse)
    4891         148 :                 cmd->recurse = true;
    4892         154 :             pass = AT_PASS_ADD_OTHERCONSTR;
    4893         154 :             break;
    4894          62 :         case AT_SetIdentity:
    4895          62 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
    4896             :             /* Set up recursion for phase 2; no other prep needed */
    4897          62 :             if (recurse)
    4898          56 :                 cmd->recurse = true;
    4899             :             /* This should run after AddIdentity, so do it in MISC pass */
    4900          62 :             pass = AT_PASS_MISC;
    4901          62 :             break;
    4902          56 :         case AT_DropIdentity:
    4903          56 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
    4904             :             /* Set up recursion for phase 2; no other prep needed */
    4905          56 :             if (recurse)
    4906          50 :                 cmd->recurse = true;
    4907          56 :             pass = AT_PASS_DROP;
    4908          56 :             break;
    4909         244 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
    4910         244 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4911             :             /* Set up recursion for phase 2; no other prep needed */
    4912         238 :             if (recurse)
    4913         226 :                 cmd->recurse = true;
    4914         238 :             pass = AT_PASS_DROP;
    4915         238 :             break;
    4916         366 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
    4917         366 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4918             :             /* Set up recursion for phase 2; no other prep needed */
    4919         360 :             if (recurse)
    4920         330 :                 cmd->recurse = true;
    4921         360 :             pass = AT_PASS_COL_ATTRS;
    4922         360 :             break;
    4923        7278 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull without adding
    4924             :                                  * a constraint */
    4925        7278 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4926             :             /* Need command-specific recursion decision */
    4927        7278 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4928        7278 :             pass = AT_PASS_COL_ATTRS;
    4929        7278 :             break;
    4930          84 :         case AT_SetExpression:  /* ALTER COLUMN SET EXPRESSION */
    4931          84 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4932          84 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4933          84 :             pass = AT_PASS_SET_EXPRESSION;
    4934          84 :             break;
    4935          44 :         case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
    4936          44 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4937          44 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4938          44 :             ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
    4939          32 :             pass = AT_PASS_DROP;
    4940          32 :             break;
    4941         164 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
    4942         164 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE);
    4943         164 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4944             :             /* No command-specific prep needed */
    4945         164 :             pass = AT_PASS_MISC;
    4946         164 :             break;
    4947          44 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
    4948             :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
    4949          44 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
    4950             :             /* This command never recurses */
    4951          32 :             pass = AT_PASS_MISC;
    4952          32 :             break;
    4953         234 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
    4954         234 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
    4955         234 :             ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
    4956             :             /* No command-specific prep needed */
    4957         234 :             pass = AT_PASS_MISC;
    4958         234 :             break;
    4959          66 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
    4960          66 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
    4961             :             /* This command never recurses */
    4962             :             /* No command-specific prep needed */
    4963          66 :             pass = AT_PASS_MISC;
    4964          66 :             break;
    4965        1616 :         case AT_DropColumn:     /* DROP COLUMN */
    4966        1616 :             ATSimplePermissions(cmd->subtype, rel,
    4967             :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
    4968        1610 :             ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd,
    4969             :                              lockmode, context);
    4970             :             /* Recursion occurs during execution phase */
    4971        1598 :             pass = AT_PASS_DROP;
    4972        1598 :             break;
    4973           0 :         case AT_AddIndex:       /* ADD INDEX */
    4974           0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    4975             :             /* This command never recurses */
    4976             :             /* No command-specific prep needed */
    4977           0 :             pass = AT_PASS_ADD_INDEX;
    4978           0 :             break;
    4979       12858 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
    4980       12858 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4981             :             /* Recursion occurs during execution phase */
    4982             :             /* No command-specific prep needed except saving recurse flag */
    4983       12858 :             if (recurse)
    4984       12508 :                 cmd->recurse = true;
    4985       12858 :             pass = AT_PASS_ADD_CONSTR;
    4986       12858 :             break;
    4987           0 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
    4988           0 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    4989             :             /* This command never recurses */
    4990             :             /* No command-specific prep needed */
    4991           0 :             pass = AT_PASS_ADD_INDEXCONSTR;
    4992           0 :             break;
    4993         946 :         case AT_DropConstraint: /* DROP CONSTRAINT */
    4994         946 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    4995         946 :             ATCheckPartitionsNotInUse(rel, lockmode);
    4996             :             /* Other recursion occurs during execution phase */
    4997             :             /* No command-specific prep needed except saving recurse flag */
    4998         940 :             if (recurse)
    4999         708 :                 cmd->recurse = true;
    5000         940 :             pass = AT_PASS_DROP;
    5001         940 :             break;
    5002        1128 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
    5003        1128 :             ATSimplePermissions(cmd->subtype, rel,
    5004             :                                 ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE);
    5005             :             /* See comments for ATPrepAlterColumnType */
    5006        1128 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, recurse, lockmode,
    5007             :                                       AT_PASS_UNSET, context);
    5008             :             Assert(cmd != NULL);
    5009             :             /* Performs own recursion */
    5010        1122 :             ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd,
    5011             :                                   lockmode, context);
    5012         978 :             pass = AT_PASS_ALTER_TYPE;
    5013         978 :             break;
    5014         164 :         case AT_AlterColumnGenericOptions:
    5015         164 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
    5016             :             /* This command never recurses */
    5017             :             /* No command-specific prep needed */
    5018         164 :             pass = AT_PASS_MISC;
    5019         164 :             break;
    5020        1796 :         case AT_ChangeOwner:    /* ALTER OWNER */
    5021             :             /* This command never recurses */
    5022             :             /* No command-specific prep needed */
    5023        1796 :             pass = AT_PASS_MISC;
    5024        1796 :             break;
    5025          64 :         case AT_ClusterOn:      /* CLUSTER ON */
    5026             :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
    5027          64 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
    5028             :             /* These commands never recurse */
    5029             :             /* No command-specific prep needed */
    5030          64 :             pass = AT_PASS_MISC;
    5031          64 :             break;
    5032          38 :         case AT_SetLogged:      /* SET LOGGED */
    5033          38 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
    5034          38 :             if (tab->chgPersistence)
    5035           0 :                 ereport(ERROR,
    5036             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5037             :                          errmsg("cannot change persistence setting twice")));
    5038          38 :             tab->chgPersistence = ATPrepChangePersistence(rel, true);
    5039             :             /* force rewrite if necessary; see comment in ATRewriteTables */
    5040          32 :             if (tab->chgPersistence)
    5041             :             {
    5042          26 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
    5043          26 :                 tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
    5044             :             }
    5045          32 :             pass = AT_PASS_MISC;
    5046          32 :             break;
    5047          50 :         case AT_SetUnLogged:    /* SET UNLOGGED */
    5048          50 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE);
    5049          50 :             if (tab->chgPersistence)
    5050           0 :                 ereport(ERROR,
    5051             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5052             :                          errmsg("cannot change persistence setting twice")));
    5053          50 :             tab->chgPersistence = ATPrepChangePersistence(rel, false);
    5054             :             /* force rewrite if necessary; see comment in ATRewriteTables */
    5055          44 :             if (tab->chgPersistence)
    5056             :             {
    5057          38 :                 tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
    5058          38 :                 tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
    5059             :             }
    5060          44 :             pass = AT_PASS_MISC;
    5061          44 :             break;
    5062           6 :         case AT_DropOids:       /* SET WITHOUT OIDS */
    5063           6 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    5064           6 :             pass = AT_PASS_DROP;
    5065           6 :             break;
    5066         128 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
    5067         128 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
    5068             : 
    5069             :             /* check if another access method change was already requested */
    5070         128 :             if (tab->chgAccessMethod)
    5071          18 :                 ereport(ERROR,
    5072             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5073             :                          errmsg("cannot have multiple SET ACCESS METHOD subcommands")));
    5074             : 
    5075         110 :             ATPrepSetAccessMethod(tab, rel, cmd->name);
    5076         110 :             pass = AT_PASS_MISC;    /* does not matter; no work in Phase 2 */
    5077         110 :             break;
    5078         158 :         case AT_SetTableSpace:  /* SET TABLESPACE */
    5079         158 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
    5080             :                                 ATT_PARTITIONED_INDEX);
    5081             :             /* This command never recurses */
    5082         158 :             ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
    5083         158 :             pass = AT_PASS_MISC;    /* doesn't actually matter */
    5084         158 :             break;
    5085         934 :         case AT_SetRelOptions:  /* SET (...) */
    5086             :         case AT_ResetRelOptions:    /* RESET (...) */
    5087             :         case AT_ReplaceRelOptions:  /* reset them all, then set just these */
    5088         934 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
    5089             :             /* This command never recurses */
    5090             :             /* No command-specific prep needed */
    5091         934 :             pass = AT_PASS_MISC;
    5092         934 :             break;
    5093         326 :         case AT_AddInherit:     /* INHERIT */
    5094         326 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    5095             :             /* This command never recurses */
    5096         326 :             ATPrepAddInherit(rel);
    5097         308 :             pass = AT_PASS_MISC;
    5098         308 :             break;
    5099          44 :         case AT_DropInherit:    /* NO INHERIT */
    5100          44 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    5101             :             /* This command never recurses */
    5102             :             /* No command-specific prep needed */
    5103          44 :             pass = AT_PASS_MISC;
    5104          44 :             break;
    5105         132 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
    5106         132 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5107             :             /* Recursion occurs during execution phase */
    5108         126 :             pass = AT_PASS_MISC;
    5109         126 :             break;
    5110         388 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
    5111         388 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    5112             :             /* Recursion occurs during execution phase */
    5113             :             /* No command-specific prep needed except saving recurse flag */
    5114         388 :             if (recurse)
    5115         388 :                 cmd->recurse = true;
    5116         388 :             pass = AT_PASS_MISC;
    5117         388 :             break;
    5118         430 :         case AT_ReplicaIdentity:    /* REPLICA IDENTITY ... */
    5119         430 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_MATVIEW);
    5120         430 :             pass = AT_PASS_MISC;
    5121             :             /* This command never recurses */
    5122             :             /* No command-specific prep needed */
    5123         430 :             break;
    5124         340 :         case AT_EnableTrig:     /* ENABLE TRIGGER variants */
    5125             :         case AT_EnableAlwaysTrig:
    5126             :         case AT_EnableReplicaTrig:
    5127             :         case AT_EnableTrigAll:
    5128             :         case AT_EnableTrigUser:
    5129             :         case AT_DisableTrig:    /* DISABLE TRIGGER variants */
    5130             :         case AT_DisableTrigAll:
    5131             :         case AT_DisableTrigUser:
    5132         340 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    5133             :             /* Set up recursion for phase 2; no other prep needed */
    5134         340 :             if (recurse)
    5135         312 :                 cmd->recurse = true;
    5136         340 :             pass = AT_PASS_MISC;
    5137         340 :             break;
    5138         520 :         case AT_EnableRule:     /* ENABLE/DISABLE RULE variants */
    5139             :         case AT_EnableAlwaysRule:
    5140             :         case AT_EnableReplicaRule:
    5141             :         case AT_DisableRule:
    5142             :         case AT_AddOf:          /* OF */
    5143             :         case AT_DropOf:         /* NOT OF */
    5144             :         case AT_EnableRowSecurity:
    5145             :         case AT_DisableRowSecurity:
    5146             :         case AT_ForceRowSecurity:
    5147             :         case AT_NoForceRowSecurity:
    5148         520 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5149             :             /* These commands never recurse */
    5150             :             /* No command-specific prep needed */
    5151         520 :             pass = AT_PASS_MISC;
    5152         520 :             break;
    5153          50 :         case AT_GenericOptions:
    5154          50 :             ATSimplePermissions(cmd->subtype, rel, ATT_FOREIGN_TABLE);
    5155             :             /* No command-specific prep needed */
    5156          50 :             pass = AT_PASS_MISC;
    5157          50 :             break;
    5158        2590 :         case AT_AttachPartition:
    5159        2590 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_PARTITIONED_INDEX);
    5160             :             /* No command-specific prep needed */
    5161        2590 :             pass = AT_PASS_MISC;
    5162        2590 :             break;
    5163         528 :         case AT_DetachPartition:
    5164         528 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5165             :             /* No command-specific prep needed */
    5166         522 :             pass = AT_PASS_MISC;
    5167         522 :             break;
    5168          14 :         case AT_DetachPartitionFinalize:
    5169          14 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5170             :             /* No command-specific prep needed */
    5171          14 :             pass = AT_PASS_MISC;
    5172          14 :             break;
    5173         252 :         case AT_SplitPartition:
    5174         252 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5175             :             /* No command-specific prep needed */
    5176         252 :             pass = AT_PASS_MISC;
    5177         252 :             break;
    5178         120 :         case AT_MergePartitions:
    5179         120 :             ATSimplePermissions(cmd->subtype, rel, ATT_TABLE);
    5180             :             /* No command-specific prep needed */
    5181         120 :             pass = AT_PASS_MISC;
    5182         120 :             break;
    5183           0 :         default:                /* oops */
    5184           0 :             elog(ERROR, "unrecognized alter table type: %d",
    5185             :                  (int) cmd->subtype);
    5186             :             pass = AT_PASS_UNSET;   /* keep compiler quiet */
    5187             :             break;
    5188             :     }
    5189             :     Assert(pass > AT_PASS_UNSET);
    5190             : 
    5191             :     /* Add the subcommand to the appropriate list for phase 2 */
    5192       36814 :     tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd);
    5193       36814 : }
    5194             : 
    5195             : /*
    5196             :  * ATRewriteCatalogs
    5197             :  *
    5198             :  * Traffic cop for ALTER TABLE Phase 2 operations.  Subcommands are
    5199             :  * dispatched in a "safe" execution order (designed to avoid unnecessary
    5200             :  * conflicts).
    5201             :  */
    5202             : static void
    5203       34242 : ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
    5204             :                   AlterTableUtilityContext *context)
    5205             : {
    5206             :     ListCell   *ltab;
    5207             : 
    5208             :     /*
    5209             :      * We process all the tables "in parallel", one pass at a time.  This is
    5210             :      * needed because we may have to propagate work from one table to another
    5211             :      * (specifically, ALTER TYPE on a foreign key's PK has to dispatch the
    5212             :      * re-adding of the foreign key constraint to the other table).  Work can
    5213             :      * only be propagated into later passes, however.
    5214             :      */
    5215      433954 :     for (AlterTablePass pass = 0; pass < AT_NUM_PASSES; pass++)
    5216             :     {
    5217             :         /* Go through each table that needs to be processed */
    5218      815854 :         foreach(ltab, *wqueue)
    5219             :         {
    5220      416142 :             AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
    5221      416142 :             List       *subcmds = tab->subcmds[pass];
    5222             :             ListCell   *lcmd;
    5223             : 
    5224      416142 :             if (subcmds == NIL)
    5225      362022 :                 continue;
    5226             : 
    5227             :             /*
    5228             :              * Open the relation and store it in tab.  This allows subroutines
    5229             :              * close and reopen, if necessary.  Appropriate lock was obtained
    5230             :              * by phase 1, needn't get it again.
    5231             :              */
    5232       54120 :             tab->rel = relation_open(tab->relid, NoLock);
    5233             : 
    5234      109210 :             foreach(lcmd, subcmds)
    5235       57720 :                 ATExecCmd(wqueue, tab,
    5236       57720 :                           lfirst_node(AlterTableCmd, lcmd),
    5237             :                           lockmode, pass, context);
    5238             : 
    5239             :             /*
    5240             :              * After the ALTER TYPE or SET EXPRESSION pass, do cleanup work
    5241             :              * (this is not done in ATExecAlterColumnType since it should be
    5242             :              * done only once if multiple columns of a table are altered).
    5243             :              */
    5244       51490 :             if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
    5245         960 :                 ATPostAlterTypeCleanup(wqueue, tab, lockmode);
    5246             : 
    5247       51490 :             if (tab->rel)
    5248             :             {
    5249       51490 :                 relation_close(tab->rel, NoLock);
    5250       51490 :                 tab->rel = NULL;
    5251             :             }
    5252             :         }
    5253             :     }
    5254             : 
    5255             :     /* Check to see if a toast table must be added. */
    5256       66934 :     foreach(ltab, *wqueue)
    5257             :     {
    5258       35322 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
    5259             : 
    5260             :         /*
    5261             :          * If the table is source table of ATTACH PARTITION command, we did
    5262             :          * not modify anything about it that will change its toasting
    5263             :          * requirement, so no need to check.
    5264             :          */
    5265       35322 :         if (((tab->relkind == RELKIND_RELATION ||
    5266        6416 :               tab->relkind == RELKIND_PARTITIONED_TABLE) &&
    5267       33484 :              tab->partition_constraint == NULL) ||
    5268        3758 :             tab->relkind == RELKIND_MATVIEW)
    5269       31614 :             AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
    5270             :     }
    5271       31612 : }
    5272             : 
    5273             : /*
    5274             :  * ATExecCmd: dispatch a subcommand to appropriate execution routine
    5275             :  */
    5276             : static void
    5277       57720 : ATExecCmd(List **wqueue, AlteredTableInfo *tab,
    5278             :           AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass,
    5279             :           AlterTableUtilityContext *context)
    5280             : {
    5281       57720 :     ObjectAddress address = InvalidObjectAddress;
    5282       57720 :     Relation    rel = tab->rel;
    5283             : 
    5284       57720 :     switch (cmd->subtype)
    5285             :     {
    5286        1962 :         case AT_AddColumn:      /* ADD COLUMN */
    5287             :         case AT_AddColumnToView:    /* add column via CREATE OR REPLACE VIEW */
    5288        1962 :             address = ATExecAddColumn(wqueue, tab, rel, &cmd,
    5289        1962 :                                       cmd->recurse, false,
    5290             :                                       lockmode, cur_pass, context);
    5291        1848 :             break;
    5292         566 :         case AT_ColumnDefault:  /* ALTER COLUMN DEFAULT */
    5293         566 :             address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
    5294         506 :             break;
    5295         110 :         case AT_CookedColumnDefault:    /* add a pre-cooked default */
    5296         110 :             address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
    5297         110 :             break;
    5298         148 :         case AT_AddIdentity:
    5299         148 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5300             :                                       cur_pass, context);
    5301             :             Assert(cmd != NULL);
    5302         142 :             address = ATExecAddIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
    5303         100 :             break;
    5304          62 :         case AT_SetIdentity:
    5305          62 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5306             :                                       cur_pass, context);
    5307             :             Assert(cmd != NULL);
    5308          62 :             address = ATExecSetIdentity(rel, cmd->name, cmd->def, lockmode, cmd->recurse, false);
    5309          38 :             break;
    5310          56 :         case AT_DropIdentity:
    5311          56 :             address = ATExecDropIdentity(rel, cmd->name, cmd->missing_ok, lockmode, cmd->recurse, false);
    5312          38 :             break;
    5313         238 :         case AT_DropNotNull:    /* ALTER COLUMN DROP NOT NULL */
    5314         238 :             address = ATExecDropNotNull(rel, cmd->name, cmd->recurse, lockmode);
    5315         130 :             break;
    5316         360 :         case AT_SetNotNull:     /* ALTER COLUMN SET NOT NULL */
    5317         360 :             address = ATExecSetNotNull(wqueue, rel, NULL, cmd->name,
    5318         360 :                                        cmd->recurse, false, NULL, lockmode);
    5319         330 :             break;
    5320       14424 :         case AT_SetAttNotNull:  /* set pg_attribute.attnotnull */
    5321       14424 :             address = ATExecSetAttNotNull(wqueue, rel, cmd->name, lockmode);
    5322       14406 :             break;
    5323          84 :         case AT_SetExpression:
    5324          84 :             address = ATExecSetExpression(tab, rel, cmd->name, cmd->def, lockmode);
    5325          78 :             break;
    5326          32 :         case AT_DropExpression:
    5327          32 :             address = ATExecDropExpression(rel, cmd->name, cmd->missing_ok, lockmode);
    5328          26 :             break;
    5329         164 :         case AT_SetStatistics:  /* ALTER COLUMN SET STATISTICS */
    5330         164 :             address = ATExecSetStatistics(rel, cmd->name, cmd->num, cmd->def, lockmode);
    5331         116 :             break;
    5332          26 :         case AT_SetOptions:     /* ALTER COLUMN SET ( options ) */
    5333          26 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode);
    5334          26 :             break;
    5335           6 :         case AT_ResetOptions:   /* ALTER COLUMN RESET ( options ) */
    5336           6 :             address = ATExecSetOptions(rel, cmd->name, cmd->def, true, lockmode);
    5337           6 :             break;
    5338         234 :         case AT_SetStorage:     /* ALTER COLUMN SET STORAGE */
    5339         234 :             address = ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
    5340         222 :             break;
    5341          66 :         case AT_SetCompression: /* ALTER COLUMN SET COMPRESSION */
    5342          66 :             address = ATExecSetCompression(rel, cmd->name, cmd->def,
    5343             :                                            lockmode);
    5344          60 :             break;
    5345        1598 :         case AT_DropColumn:     /* DROP COLUMN */
    5346        1598 :             address = ATExecDropColumn(wqueue, rel, cmd->name,
    5347        1598 :                                        cmd->behavior, cmd->recurse, false,
    5348        1598 :                                        cmd->missing_ok, lockmode,
    5349             :                                        NULL);
    5350        1424 :             break;
    5351        1018 :         case AT_AddIndex:       /* ADD INDEX */
    5352        1018 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, false,
    5353             :                                      lockmode);
    5354         890 :             break;
    5355         434 :         case AT_ReAddIndex:     /* ADD INDEX */
    5356         434 :             address = ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true,
    5357             :                                      lockmode);
    5358         434 :             break;
    5359          14 :         case AT_ReAddStatistics:    /* ADD STATISTICS */
    5360          14 :             address = ATExecAddStatistics(tab, rel, (CreateStatsStmt *) cmd->def,
    5361             :                                           true, lockmode);
    5362          14 :             break;
    5363       16510 :         case AT_AddConstraint:  /* ADD CONSTRAINT */
    5364             :             /* Transform the command only during initial examination */
    5365       16510 :             if (cur_pass == AT_PASS_ADD_CONSTR)
    5366       12828 :                 cmd = ATParseTransformCmd(wqueue, tab, rel, cmd,
    5367       12858 :                                           cmd->recurse, lockmode,
    5368             :                                           cur_pass, context);
    5369             :             /* Depending on constraint type, might be no more work to do now */
    5370       16480 :             if (cmd != NULL)
    5371             :                 address =
    5372        3652 :                     ATExecAddConstraint(wqueue, tab, rel,
    5373        3652 :                                         (Constraint *) cmd->def,
    5374        3652 :                                         cmd->recurse, false, lockmode);
    5375       15926 :             break;
    5376         188 :         case AT_ReAddConstraint:    /* Re-add pre-existing check constraint */
    5377             :             address =
    5378         188 :                 ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
    5379             :                                     true, true, lockmode);
    5380         176 :             break;
    5381          14 :         case AT_ReAddDomainConstraint:  /* Re-add pre-existing domain check
    5382             :                                          * constraint */
    5383             :             address =
    5384          14 :                 AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
    5385          14 :                                          ((AlterDomainStmt *) cmd->def)->def,
    5386             :                                          NULL);
    5387           8 :             break;
    5388          54 :         case AT_ReAddComment:   /* Re-add existing comment */
    5389          54 :             address = CommentObject((CommentStmt *) cmd->def);
    5390          54 :             break;
    5391        8434 :         case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */
    5392        8434 :             address = ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def,
    5393             :                                                lockmode);
    5394        8422 :             break;
    5395         126 :         case AT_AlterConstraint:    /* ALTER CONSTRAINT */
    5396         126 :             address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
    5397         114 :             break;
    5398         388 :         case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
    5399         388 :             address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
    5400             :                                                false, lockmode);
    5401         388 :             break;
    5402         940 :         case AT_DropConstraint: /* DROP CONSTRAINT */
    5403         940 :             ATExecDropConstraint(rel, cmd->name, cmd->behavior,
    5404         940 :                                  cmd->recurse,
    5405         940 :                                  cmd->missing_ok, lockmode);
    5406         742 :             break;
    5407         948 :         case AT_AlterColumnType:    /* ALTER COLUMN TYPE */
    5408             :             /* parse transformation was done earlier */
    5409         948 :             address = ATExecAlterColumnType(tab, rel, cmd, lockmode);
    5410         912 :             break;
    5411         164 :         case AT_AlterColumnGenericOptions:  /* ALTER COLUMN OPTIONS */
    5412             :             address =
    5413         164 :                 ATExecAlterColumnGenericOptions(rel, cmd->name,
    5414         164 :                                                 (List *) cmd->def, lockmode);
    5415         158 :             break;
    5416        1796 :         case AT_ChangeOwner:    /* ALTER OWNER */
    5417        1790 :             ATExecChangeOwner(RelationGetRelid(rel),
    5418        1796 :                               get_rolespec_oid(cmd->newowner, false),
    5419             :                               false, lockmode);
    5420        1778 :             break;
    5421          64 :         case AT_ClusterOn:      /* CLUSTER ON */
    5422          64 :             address = ATExecClusterOn(rel, cmd->name, lockmode);
    5423          58 :             break;
    5424          18 :         case AT_DropCluster:    /* SET WITHOUT CLUSTER */
    5425          18 :             ATExecDropCluster(rel, lockmode);
    5426          12 :             break;
    5427          76 :         case AT_SetLogged:      /* SET LOGGED */
    5428             :         case AT_SetUnLogged:    /* SET UNLOGGED */
    5429          76 :             break;
    5430           6 :         case AT_DropOids:       /* SET WITHOUT OIDS */
    5431             :             /* nothing to do here, oid columns don't exist anymore */
    5432           6 :             break;
    5433          92 :         case AT_SetAccessMethod:    /* SET ACCESS METHOD */
    5434             : 
    5435             :             /*
    5436             :              * Only do this for partitioned tables, for which this is just a
    5437             :              * catalog change.  Tables with storage are handled by Phase 3.
    5438             :              */
    5439          92 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
    5440          50 :                 tab->chgAccessMethod)
    5441          44 :                 ATExecSetAccessMethodNoStorage(rel, tab->newAccessMethod);
    5442          92 :             break;
    5443         158 :         case AT_SetTableSpace:  /* SET TABLESPACE */
    5444             : 
    5445             :             /*
    5446             :              * Only do this for partitioned tables and indexes, for which this
    5447             :              * is just a catalog change.  Other relation types which have
    5448             :              * storage are handled by Phase 3.
    5449             :              */
    5450         158 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
    5451         146 :                 rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
    5452          36 :                 ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
    5453             : 
    5454         152 :             break;
    5455         934 :         case AT_SetRelOptions:  /* SET (...) */
    5456             :         case AT_ResetRelOptions:    /* RESET (...) */
    5457             :         case AT_ReplaceRelOptions:  /* replace entire option list */
    5458         934 :             ATExecSetRelOptions(rel, (List *) cmd->def, cmd->subtype, lockmode);
    5459         882 :             break;
    5460         122 :         case AT_EnableTrig:     /* ENABLE TRIGGER name */
    5461         122 :             ATExecEnableDisableTrigger(rel, cmd->name,
    5462             :                                        TRIGGER_FIRES_ON_ORIGIN, false,
    5463         122 :                                        cmd->recurse,
    5464             :                                        lockmode);
    5465         122 :             break;
    5466          40 :         case AT_EnableAlwaysTrig:   /* ENABLE ALWAYS TRIGGER name */
    5467          40 :             ATExecEnableDisableTrigger(rel, cmd->name,
    5468             :                                        TRIGGER_FIRES_ALWAYS, false,
    5469          40 :                                        cmd->recurse,
    5470             :                                        lockmode);
    5471          40 :             break;
    5472          16 :         case AT_EnableReplicaTrig:  /* ENABLE REPLICA TRIGGER name */
    5473          16 :             ATExecEnableDisableTrigger(rel, cmd->name,
    5474             :                                        TRIGGER_FIRES_ON_REPLICA, false,
    5475          16 :                                        cmd->recurse,
    5476             :                                        lockmode);
    5477          16 :             break;
    5478         138 :         case AT_DisableTrig:    /* DISABLE TRIGGER name */
    5479         138 :             ATExecEnableDisableTrigger(rel, cmd->name,
    5480             :                                        TRIGGER_DISABLED, false,
    5481         138 :                                        cmd->recurse,
    5482             :                                        lockmode);
    5483         138 :             break;
    5484           0 :         case AT_EnableTrigAll:  /* ENABLE TRIGGER ALL */
    5485           0 :             ATExecEnableDisableTrigger(rel, NULL,
    5486             :                                        TRIGGER_FIRES_ON_ORIGIN, false,
    5487           0 :                                        cmd->recurse,
    5488             :                                        lockmode);
    5489           0 :             break;
    5490          12 :         case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
    5491          12 :             ATExecEnableDisableTrigger(rel, NULL,
    5492             :                                        TRIGGER_DISABLED, false,
    5493          12 :                                        cmd->recurse,
    5494             :                                        lockmode);
    5495          12 :             break;
    5496           0 :         case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
    5497           0 :             ATExecEnableDisableTrigger(rel, NULL,
    5498             :                                        TRIGGER_FIRES_ON_ORIGIN, true,
    5499           0 :                                        cmd->recurse,
    5500             :                                        lockmode);
    5501           0 :             break;
    5502          12 :         case AT_DisableTrigUser:    /* DISABLE TRIGGER USER */
    5503          12 :             ATExecEnableDisableTrigger(rel, NULL,
    5504             :                                        TRIGGER_DISABLED, true,
    5505          12 :                                        cmd->recurse,
    5506             :                                        lockmode);
    5507          12 :             break;
    5508             : 
    5509           8 :         case AT_EnableRule:     /* ENABLE RULE name */
    5510           8 :             ATExecEnableDisableRule(rel, cmd->name,
    5511             :                                     RULE_FIRES_ON_ORIGIN, lockmode);
    5512           8 :             break;
    5513           0 :         case AT_EnableAlwaysRule:   /* ENABLE ALWAYS RULE name */
    5514           0 :             ATExecEnableDisableRule(rel, cmd->name,
    5515             :                                     RULE_FIRES_ALWAYS, lockmode);
    5516           0 :             break;
    5517           6 :         case AT_EnableReplicaRule:  /* ENABLE REPLICA RULE name */
    5518           6 :             ATExecEnableDisableRule(rel, cmd->name,
    5519             :                                     RULE_FIRES_ON_REPLICA, lockmode);
    5520           6 :             break;
    5521          32 :         case AT_DisableRule:    /* DISABLE RULE name */
    5522          32 :             ATExecEnableDisableRule(rel, cmd->name,
    5523             :                                     RULE_DISABLED, lockmode);
    5524          32 :             break;
    5525             : 
    5526         308 :         case AT_AddInherit:
    5527         308 :             address = ATExecAddInherit(rel, (RangeVar *) cmd->def, lockmode);
    5528         224 :             break;
    5529          44 :         case AT_DropInherit:
    5530          44 :             address = ATExecDropInherit(rel, (RangeVar *) cmd->def, lockmode);
    5531          38 :             break;
    5532          66 :         case AT_AddOf:
    5533          66 :             address = ATExecAddOf(rel, (TypeName *) cmd->def, lockmode);
    5534          30 :             break;
    5535           6 :         case AT_DropOf:
    5536           6 :             ATExecDropOf(rel, lockmode);
    5537           6 :             break;
    5538         448 :         case AT_ReplicaIdentity:
    5539         448 :             ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
    5540         400 :             break;
    5541         278 :         case AT_EnableRowSecurity:
    5542         278 :             ATExecSetRowSecurity(rel, true);
    5543         278 :             break;
    5544          10 :         case AT_DisableRowSecurity:
    5545          10 :             ATExecSetRowSecurity(rel, false);
    5546          10 :             break;
    5547          82 :         case AT_ForceRowSecurity:
    5548          82 :             ATExecForceNoForceRowSecurity(rel, true);
    5549          82 :             break;
    5550          32 :         case AT_NoForceRowSecurity:
    5551          32 :             ATExecForceNoForceRowSecurity(rel, false);
    5552          32 :             break;
    5553          50 :         case AT_GenericOptions:
    5554          50 :             ATExecGenericOptions(rel, (List *) cmd->def);
    5555          48 :             break;
    5556        2590 :         case AT_AttachPartition:
    5557        2590 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5558             :                                       cur_pass, context);
    5559             :             Assert(cmd != NULL);
    5560        2560 :             if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    5561        2176 :                 address = ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def,
    5562             :                                                 context);
    5563             :             else
    5564         384 :                 address = ATExecAttachPartitionIdx(wqueue, rel,
    5565         384 :                                                    ((PartitionCmd *) cmd->def)->name);
    5566        2218 :             break;
    5567         522 :         case AT_DetachPartition:
    5568         522 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5569             :                                       cur_pass, context);
    5570             :             Assert(cmd != NULL);
    5571             :             /* ATPrepCmd ensures it must be a table */
    5572             :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    5573         516 :             address = ATExecDetachPartition(wqueue, tab, rel,
    5574         516 :                                             ((PartitionCmd *) cmd->def)->name,
    5575         516 :                                             ((PartitionCmd *) cmd->def)->concurrent);
    5576         386 :             break;
    5577          14 :         case AT_DetachPartitionFinalize:
    5578          14 :             address = ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
    5579          14 :             break;
    5580         252 :         case AT_SplitPartition:
    5581         252 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5582             :                                       cur_pass, context);
    5583             :             Assert(cmd != NULL);
    5584             :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    5585         120 :             ATExecSplitPartition(wqueue, tab, rel, (PartitionCmd *) cmd->def,
    5586             :                                  context);
    5587         114 :             break;
    5588         120 :         case AT_MergePartitions:
    5589         120 :             cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
    5590             :                                       cur_pass, context);
    5591             :             Assert(cmd != NULL);
    5592             :             Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    5593          66 :             ATExecMergePartitions(wqueue, tab, rel, (PartitionCmd *) cmd->def,
    5594             :                                   context);
    5595          66 :             break;
    5596           0 :         default:                /* oops */
    5597           0 :             elog(ERROR, "unrecognized alter table type: %d",
    5598             :                  (int) cmd->subtype);
    5599             :             break;
    5600             :     }
    5601             : 
    5602             :     /*
    5603             :      * Report the subcommand to interested event triggers.
    5604             :      */
    5605       55090 :     if (cmd)
    5606       42262 :         EventTriggerCollectAlterTableSubcmd((Node *) cmd, address);
    5607             : 
    5608             :     /*
    5609             :      * Bump the command counter to ensure the next subcommand in the sequence
    5610             :      * can see the changes so far
    5611             :      */
    5612       55090 :     CommandCounterIncrement();
    5613       55090 : }
    5614             : 
    5615             : /*
    5616             :  * ATParseTransformCmd: perform parse transformation for one subcommand
    5617             :  *
    5618             :  * Returns the transformed subcommand tree, if there is one, else NULL.
    5619             :  *
    5620             :  * The parser may hand back additional AlterTableCmd(s) and/or other
    5621             :  * utility statements, either before or after the original subcommand.
    5622             :  * Other AlterTableCmds are scheduled into the appropriate slot of the
    5623             :  * AlteredTableInfo (they had better be for later passes than the current one).
    5624             :  * Utility statements that are supposed to happen before the AlterTableCmd
    5625             :  * are executed immediately.  Those that are supposed to happen afterwards
    5626             :  * are added to the tab->afterStmts list to be done at the very end.
    5627             :  */
    5628             : static AlterTableCmd *
    5629       19522 : ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
    5630             :                     AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
    5631             :                     AlterTablePass cur_pass, AlterTableUtilityContext *context)
    5632             : {
    5633       19522 :     AlterTableCmd *newcmd = NULL;
    5634       19522 :     AlterTableStmt *atstmt = makeNode(AlterTableStmt);
    5635             :     List       *beforeStmts;
    5636             :     List       *afterStmts;
    5637             :     ListCell   *lc;
    5638             : 
    5639             :     /* Gin up an AlterTableStmt with just this subcommand and this table */
    5640       19522 :     atstmt->relation =
    5641       19522 :         makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
    5642       19522 :                      pstrdup(RelationGetRelationName(rel)),
    5643             :                      -1);
    5644       19522 :     atstmt->relation->inh = recurse;
    5645       19522 :     atstmt->cmds = list_make1(cmd);
    5646       19522 :     atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
    5647       19522 :     atstmt->missing_ok = false;
    5648             : 
    5649             :     /* Transform the AlterTableStmt */
    5650       19522 :     atstmt = transformAlterTableStmt(RelationGetRelid(rel),
    5651             :                                      atstmt,
    5652             :                                      context->queryString,
    5653             :                                      &beforeStmts,
    5654             :                                      &afterStmts);
    5655             : 
    5656             :     /* Execute any statements that should happen before these subcommand(s) */
    5657       19702 :     foreach(lc, beforeStmts)
    5658             :     {
    5659         444 :         Node       *stmt = (Node *) lfirst(lc);
    5660             : 
    5661         444 :         ProcessUtilityForAlterTable(stmt, context);
    5662         432 :         CommandCounterIncrement();
    5663             :     }
    5664             : 
    5665             :     /* Examine the transformed subcommands and schedule them appropriately */
    5666       45974 :     foreach(lc, atstmt->cmds)
    5667             :     {
    5668       26716 :         AlterTableCmd *cmd2 = lfirst_node(AlterTableCmd, lc);
    5669             :         AlterTablePass pass;
    5670             : 
    5671             :         /*
    5672             :          * This switch need only cover the subcommand types that can be added
    5673             :          * by parse_utilcmd.c; otherwise, we'll use the default strategy of
    5674             :          * executing the subcommand immediately, as a substitute for the
    5675             :          * original subcommand.  (Note, however, that this does cause
    5676             :          * AT_AddConstraint subcommands to be rescheduled into later passes,
    5677             :          * which is important for index and foreign key constraints.)
    5678             :          *
    5679             :          * We assume we needn't do any phase-1 checks for added subcommands.
    5680             :          */
    5681       26716 :         switch (cmd2->subtype)
    5682             :         {
    5683        7146 :             case AT_SetAttNotNull:
    5684        7146 :                 ATSimpleRecursion(wqueue, rel, cmd2, recurse, lockmode, context);
    5685        7146 :                 pass = AT_PASS_COL_ATTRS;
    5686        7146 :                 break;
    5687        1036 :             case AT_AddIndex:
    5688             : 
    5689             :                 /*
    5690             :                  * A primary key on a inheritance parent needs supporting NOT
    5691             :                  * NULL constraint on its children; enqueue commands to create
    5692             :                  * those or mark them inherited if they already exist.
    5693             :                  */
    5694        1036 :                 ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
    5695        1036 :                 pass = AT_PASS_ADD_INDEX;
    5696        1036 :                 break;
    5697        8434 :             case AT_AddIndexConstraint:
    5698             :                 /* as above */
    5699        8434 :                 ATPrepAddPrimaryKey(wqueue, rel, cmd2, lockmode, context);
    5700        8434 :                 pass = AT_PASS_ADD_INDEXCONSTR;
    5701        8434 :                 break;
    5702        3670 :             case AT_AddConstraint:
    5703             :                 /* Recursion occurs during execution phase */
    5704        3670 :                 if (recurse)
    5705        3620 :                     cmd2->recurse = true;
    5706        3670 :                 switch (castNode(Constraint, cmd2->def)->contype)
    5707             :                 {
    5708           0 :                     case CONSTR_PRIMARY:
    5709             :                     case CONSTR_UNIQUE:
    5710             :                     case CONSTR_EXCLUSION:
    5711           0 :                         pass = AT_PASS_ADD_INDEXCONSTR;
    5712           0 :                         break;
    5713        3670 :                     default:
    5714        3670 :                         pass = AT_PASS_ADD_OTHERCONSTR;
    5715        3670 :                         break;
    5716             :                 }
    5717        3670 :                 break;
    5718           0 :             case AT_AlterColumnGenericOptions:
    5719             :                 /* This command never recurses */
    5720             :                 /* No command-specific prep needed */
    5721           0 :                 pass = AT_PASS_MISC;
    5722           0 :                 break;
    5723        6430 :             default:
    5724        6430 :                 pass = cur_pass;
    5725        6430 :                 break;
    5726             :         }
    5727             : 
    5728       26716 :         if (pass < cur_pass)
    5729             :         {
    5730             :             /* Cannot schedule into a pass we already finished */
    5731           0 :             elog(ERROR, "ALTER TABLE scheduling failure: too late for pass %d",
    5732             :                  pass);
    5733             :         }
    5734       26716 :         else if (pass > cur_pass)
    5735             :         {
    5736             :             /* OK, queue it up for later */
    5737       20286 :             tab->subcmds[pass] = lappend(tab->subcmds[pass], cmd2);
    5738             :         }
    5739             :         else
    5740             :         {
    5741             :             /*
    5742             :              * We should see at most one subcommand for the current pass,
    5743             :              * which is the transformed version of the original subcommand.
    5744             :              */
    5745        6430 :             if (newcmd == NULL && cmd->subtype == cmd2->subtype)
    5746             :             {
    5747             :                 /* Found the transformed version of our subcommand */
    5748        6430 :                 newcmd = cmd2;
    5749             :             }
    5750             :             else
    5751           0 :                 elog(ERROR, "ALTER TABLE scheduling failure: bogus item for pass %d",
    5752             :                      pass);
    5753             :         }
    5754             :     }
    5755             : 
    5756             :     /* Queue up any after-statements to happen at the end */
    5757       19258 :     tab->afterStmts = list_concat(tab->afterStmts, afterStmts);
    5758             : 
    5759       19258 :     return newcmd;
    5760             : }
    5761             : 
    5762             : /*
    5763             :  * ATRewriteTables: ALTER TABLE phase 3
    5764             :  */
    5765             : static void
    5766       31612 : ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
    5767             :                 AlterTableUtilityContext *context)
    5768             : {
    5769             :     ListCell   *ltab;
    5770             : 
    5771             :     /* Go through each table that needs to be checked or rewritten */
    5772       66678 :     foreach(ltab, *wqueue)
    5773             :     {
    5774       35310 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
    5775             : 
    5776             :         /* Relations without storage may be ignored here */
    5777       35310 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
    5778        6130 :             continue;
    5779             : 
    5780             :         /*
    5781             :          * If we change column data types, the operation has to be propagated
    5782             :          * to tables that use this table's rowtype as a column type.
    5783             :          * tab->newvals will also be non-NULL in the case where we're adding a
    5784             :          * column with a default.  We choose to forbid that case as well,
    5785             :          * since composite types might eventually support defaults.
    5786             :          *
    5787             :          * (Eventually we'll probably need to check for composite type
    5788             :          * dependencies even when we're just scanning the table without a
    5789             :          * rewrite, but at the moment a composite type does not enforce any
    5790             :          * constraints, so it's not necessary/appropriate to enforce them just
    5791             :          * during ALTER.)
    5792             :          */
    5793       29180 :         if (tab->newvals != NIL || tab->rewrite > 0)
    5794             :         {
    5795             :             Relation    rel;
    5796             : 
    5797        1456 :             rel = table_open(tab->relid, NoLock);
    5798        1456 :             find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
    5799        1444 :             table_close(rel, NoLock);
    5800             :         }
    5801             : 
    5802             :         /*
    5803             :          * We only need to rewrite the table if at least one column needs to
    5804             :          * be recomputed, or we are changing its persistence or access method.
    5805             :          *
    5806             :          * There are two reasons for requiring a rewrite when changing
    5807             :          * persistence: on one hand, we need to ensure that the buffers
    5808             :          * belonging to each of the two relations are marked with or without
    5809             :          * BM_PERMANENT properly.  On the other hand, since rewriting creates
    5810             :          * and assigns a new relfilenumber, we automatically create or drop an
    5811             :          * init fork for the relation as appropriate.
    5812             :          */
    5813       29168 :         if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE)
    5814         848 :         {
    5815             :             /* Build a temporary relation and copy data */
    5816             :             Relation    OldHeap;
    5817             :             Oid         OIDNewHeap;
    5818             :             Oid         NewAccessMethod;
    5819             :             Oid         NewTableSpace;
    5820             :             char        persistence;
    5821             : 
    5822         886 :             OldHeap = table_open(tab->relid, NoLock);
    5823             : 
    5824             :             /*
    5825             :              * We don't support rewriting of system catalogs; there are too
    5826             :              * many corner cases and too little benefit.  In particular this
    5827             :              * is certainly not going to work for mapped catalogs.
    5828             :              */
    5829         886 :             if (IsSystemRelation(OldHeap))
    5830           0 :                 ereport(ERROR,
    5831             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5832             :                          errmsg("cannot rewrite system relation \"%s\"",
    5833             :                                 RelationGetRelationName(OldHeap))));
    5834             : 
    5835         886 :             if (RelationIsUsedAsCatalogTable(OldHeap))
    5836           2 :                 ereport(ERROR,
    5837             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5838             :                          errmsg("cannot rewrite table \"%s\" used as a catalog table",
    5839             :                                 RelationGetRelationName(OldHeap))));
    5840             : 
    5841             :             /*
    5842             :              * Don't allow rewrite on temp tables of other backends ... their
    5843             :              * local buffer manager is not going to cope.
    5844             :              */
    5845         884 :             if (RELATION_IS_OTHER_TEMP(OldHeap))
    5846           0 :                 ereport(ERROR,
    5847             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5848             :                          errmsg("cannot rewrite temporary tables of other sessions")));
    5849             : 
    5850             :             /*
    5851             :              * Select destination tablespace (same as original unless user
    5852             :              * requested a change)
    5853             :              */
    5854         884 :             if (tab->newTableSpace)
    5855           0 :                 NewTableSpace = tab->newTableSpace;
    5856             :             else
    5857         884 :                 NewTableSpace = OldHeap->rd_rel->reltablespace;
    5858             : 
    5859             :             /*
    5860             :              * Select destination access method (same as original unless user
    5861             :              * requested a change)
    5862             :              */
    5863         884 :             if (tab->chgAccessMethod)
    5864          36 :                 NewAccessMethod = tab->newAccessMethod;
    5865             :             else
    5866         848 :                 NewAccessMethod = OldHeap->rd_rel->relam;
    5867             : 
    5868             :             /*
    5869             :              * Select persistence of transient table (same as original unless
    5870             :              * user requested a change)
    5871             :              */
    5872         884 :             persistence = tab->chgPersistence ?
    5873         832 :                 tab->newrelpersistence : OldHeap->rd_rel->relpersistence;
    5874             : 
    5875         884 :             table_close(OldHeap, NoLock);
    5876             : 
    5877             :             /*
    5878             :              * Fire off an Event Trigger now, before actually rewriting the
    5879             :              * table.
    5880             :              *
    5881             :              * We don't support Event Trigger for nested commands anywhere,
    5882             :              * here included, and parsetree is given NULL when coming from
    5883             :              * AlterTableInternal.
    5884             :              *
    5885             :              * And fire it only once.
    5886             :              */
    5887         884 :             if (parsetree)
    5888         884 :                 EventTriggerTableRewrite((Node *) parsetree,
    5889             :                                          tab->relid,
    5890             :                                          tab->rewrite);
    5891             : 
    5892             :             /*
    5893             :              * Create transient table that will receive the modified data.
    5894             :              *
    5895             :              * Ensure it is marked correctly as logged or unlogged.  We have
    5896             :              * to do this here so that buffers for the new relfilenumber will
    5897             :              * have the right persistence set, and at the same time ensure
    5898             :              * that the original filenumbers's buffers will get read in with
    5899             :              * the correct setting (i.e. the original one).  Otherwise a
    5900             :              * rollback after the rewrite would possibly result with buffers
    5901             :              * for the original filenumbers having the wrong persistence
    5902             :              * setting.
    5903             :              *
    5904             :              * NB: This relies on swap_relation_files() also swapping the
    5905             :              * persistence. That wouldn't work for pg_class, but that can't be
    5906             :              * unlogged anyway.
    5907             :              */
    5908         878 :             OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod,
    5909             :                                        persistence, lockmode);
    5910             : 
    5911             :             /*
    5912             :              * Copy the heap data into the new table with the desired
    5913             :              * modifications, and test the current data within the table
    5914             :              * against new constraints generated by ALTER TABLE commands.
    5915             :              */
    5916         878 :             ATRewriteTable(tab, OIDNewHeap, lockmode);
    5917             : 
    5918             :             /*
    5919             :              * Swap the physical files of the old and new heaps, then rebuild
    5920             :              * indexes and discard the old heap.  We can use RecentXmin for
    5921             :              * the table's new relfrozenxid because we rewrote all the tuples
    5922             :              * in ATRewriteTable, so no older Xid remains in the table.  Also,
    5923             :              * we never try to swap toast tables by content, since we have no
    5924             :              * interest in letting this code work on system catalogs.
    5925             :              */
    5926         854 :             finish_heap_swap(tab->relid, OIDNewHeap,
    5927             :                              false, false, true,
    5928         854 :                              !OidIsValid(tab->newTableSpace),
    5929             :                              RecentXmin,
    5930             :                              ReadNextMultiXactId(),
    5931             :                              persistence);
    5932             : 
    5933         848 :             InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0);
    5934             :         }
    5935       28282 :         else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE)
    5936             :         {
    5937          12 :             if (tab->chgPersistence)
    5938          12 :                 SequenceChangePersistence(tab->relid, tab->newrelpersistence);
    5939             :         }
    5940             :         else
    5941             :         {
    5942             :             /*
    5943             :              * If required, test the current data within the table against new
    5944             :              * constraints generated by ALTER TABLE commands, but don't
    5945             :              * rebuild data.
    5946             :              */
    5947       28270 :             if (tab->constraints != NIL || tab->verify_new_notnull ||
    5948       25604 :                 tab->partition_constraint != NULL)
    5949        4450 :                 ATRewriteTable(tab, InvalidOid, lockmode);
    5950             : 
    5951             :             /*
    5952             :              * If we had SET TABLESPACE but no reason to reconstruct tuples,
    5953             :              * just do a block-by-block copy.
    5954             :              */
    5955       28076 :             if (tab->newTableSpace)
    5956         122 :                 ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
    5957             :         }
    5958             : 
    5959             :         /*
    5960             :          * Also change persistence of owned sequences, so that it matches the
    5961             :          * table persistence.
    5962             :          */
    5963       28936 :         if (tab->chgPersistence)
    5964             :         {
    5965          64 :             List       *seqlist = getOwnedSequences(tab->relid);
    5966             :             ListCell   *lc;
    5967             : 
    5968         112 :             foreach(lc, seqlist)
    5969             :             {
    5970          48 :                 Oid         seq_relid = lfirst_oid(lc);
    5971             : 
    5972          48 :                 SequenceChangePersistence(seq_relid, tab->newrelpersistence);
    5973             :             }
    5974             :         }
    5975             :     }
    5976             : 
    5977             :     /*
    5978             :      * Foreign key constraints are checked in a final pass, since (a) it's
    5979             :      * generally best to examine each one separately, and (b) it's at least
    5980             :      * theoretically possible that we have changed both relations of the
    5981             :      * foreign key, and we'd better have finished both rewrites before we try
    5982             :      * to read the tables.
    5983             :      */
    5984       66230 :     foreach(ltab, *wqueue)
    5985             :     {
    5986       34942 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
    5987       34942 :         Relation    rel = NULL;
    5988             :         ListCell   *lcon;
    5989             : 
    5990             :         /* Relations without storage may be ignored here too */
    5991       34942 :         if (!RELKIND_HAS_STORAGE(tab->relkind))
    5992        6056 :             continue;
    5993             : 
    5994       30542 :         foreach(lcon, tab->constraints)
    5995             :         {
    5996        1736 :             NewConstraint *con = lfirst(lcon);
    5997             : 
    5998        1736 :             if (con->contype == CONSTR_FOREIGN)
    5999             :             {
    6000        1084 :                 Constraint *fkconstraint = (Constraint *) con->qual;
    6001             :                 Relation    refrel;
    6002             : 
    6003        1084 :                 if (rel == NULL)
    6004             :                 {
    6005             :                     /* Long since locked, no need for another */
    6006        1072 :                     rel = table_open(tab->relid, NoLock);
    6007             :                 }
    6008             : 
    6009        1084 :                 refrel = table_open(con->refrelid, RowShareLock);
    6010             : 
    6011        1084 :                 validateForeignKeyConstraint(fkconstraint->conname, rel, refrel,
    6012             :                                              con->refindid,
    6013             :                                              con->conid,
    6014        1084 :                                              con->conwithperiod);
    6015             : 
    6016             :                 /*
    6017             :                  * No need to mark the constraint row as validated, we did
    6018             :                  * that when we inserted the row earlier.
    6019             :                  */
    6020             : 
    6021        1004 :                 table_close(refrel, NoLock);
    6022             :             }
    6023             :         }
    6024             : 
    6025       28806 :         if (rel)
    6026         992 :             table_close(rel, NoLock);
    6027             :     }
    6028             : 
    6029             :     /* Finally, run any afterStmts that were queued up */
    6030       66112 :     foreach(ltab, *wqueue)
    6031             :     {
    6032       34824 :         AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
    6033             :         ListCell   *lc;
    6034             : 
    6035       34910 :         foreach(lc, tab->afterStmts)
    6036             :         {
    6037          86 :             Node       *stmt = (Node *) lfirst(lc);
    6038             : 
    6039          86 :             ProcessUtilityForAlterTable(stmt, context);
    6040          86 :             CommandCounterIncrement();
    6041             :         }
    6042             :     }
    6043       31288 : }
    6044             : 
    6045             : /*
    6046             :  * ATRewriteTable: scan or rewrite one table
    6047             :  *
    6048             :  * OIDNewHeap is InvalidOid if we don't need to rewrite
    6049             :  */
    6050             : static void
    6051        5328 : ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
    6052             : {
    6053             :     Relation    oldrel;
    6054             :     Relation    newrel;
    6055             :     TupleDesc   oldTupDesc;
    6056             :     TupleDesc   newTupDesc;
    6057        5328 :     bool        needscan = false;
    6058             :     List       *notnull_attrs;
    6059             :     int         i;
    6060             :     ListCell   *l;
    6061             :     EState     *estate;
    6062             :     CommandId   mycid;
    6063             :     BulkInsertState bistate;
    6064             :     int         ti_options;
    6065        5328 :     ExprState  *partqualstate = NULL;
    6066             : 
    6067             :     /*
    6068             :      * Open the relation(s).  We have surely already locked the existing
    6069             :      * table.
    6070             :      */
    6071        5328 :     oldrel = table_open(tab->relid, NoLock);
    6072        5328 :     oldTupDesc = tab->oldDesc;
    6073        5328 :     newTupDesc = RelationGetDescr(oldrel);  /* includes all mods */
    6074             : 
    6075        5328 :     if (OidIsValid(OIDNewHeap))
    6076         878 :         newrel = table_open(OIDNewHeap, lockmode);
    6077             :     else
    6078        4450 :         newrel = NULL;
    6079             : 
    6080             :     /*
    6081             :      * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
    6082             :      * is empty, so don't bother using it.
    6083             :      */
    6084        5328 :     if (newrel)
    6085             :     {
    6086         878 :         mycid = GetCurrentCommandId(true);
    6087         878 :         bistate = GetBulkInsertState();
    6088         878 :         ti_options = TABLE_INSERT_SKIP_FSM;
    6089             :     }
    6090             :     else
    6091             :     {
    6092             :         /* keep compiler quiet about using these uninitialized */
    6093        4450 :         mycid = 0;
    6094        4450 :         bistate = NULL;
    6095        4450 :         ti_options = 0;
    6096             :     }
    6097             : 
    6098             :     /*
    6099             :      * Generate the constraint and default execution states
    6100             :      */
    6101             : 
    6102        5328 :     estate = CreateExecutorState();
    6103             : 
    6104             :     /* Build the needed expression execution states */
    6105        7160 :     foreach(l, tab->constraints)
    6106             :     {
    6107        1832 :         NewConstraint *con = lfirst(l);
    6108             : 
    6109        1832 :         switch (con->contype)
    6110             :         {
    6111         742 :             case CONSTR_CHECK:
    6112         742 :                 needscan = true;
    6113         742 :                 con->qualstate = ExecPrepareExpr((Expr *) con->qual, estate);
    6114         742 :                 break;
    6115        1090 :             case CONSTR_FOREIGN:
    6116             :                 /* Nothing to do here */
    6117        1090 :                 break;
    6118           0 :             default:
    6119           0 :                 elog(ERROR, "unrecognized constraint type: %d",
    6120             :                      (int) con->contype);
    6121             :         }
    6122             :     }
    6123             : 
    6124             :     /* Build expression execution states for partition check quals */
    6125        5328 :     if (tab->partition_constraint)
    6126             :     {
    6127        1914 :         needscan = true;
    6128        1914 :         partqualstate = ExecPrepareExpr(tab->partition_constraint, estate);
    6129             :     }
    6130             : 
    6131        6202 :     foreach(l, tab->newvals)
    6132             :     {
    6133         874 :         NewColumnValue *ex = lfirst(l);
    6134             : 
    6135             :         /* expr already planned */
    6136         874 :         ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
    6137             :     }
    6138             : 
    6139        5328 :     notnull_attrs = NIL;
    6140        5328 :     if (newrel || tab->verify_new_notnull)
    6141             :     {
    6142             :         /*
    6143             :          * If we are rebuilding the tuples OR if we added any new but not
    6144             :          * verified not-null constraints, check all not-null constraints. This
    6145             :          * is a bit of overkill but it minimizes risk of bugs, and
    6146             :          * heap_attisnull is a pretty cheap test anyway.
    6147             :          */
    6148        6970 :         for (i = 0; i < newTupDesc->natts; i++)
    6149             :         {
    6150        5112 :             Form_pg_attribute attr = TupleDescAttr(newTupDesc, i);
    6151             : 
    6152        5112 :             if (attr->attnotnull && !attr->attisdropped)
    6153        2010 :                 notnull_attrs = lappend_int(notnull_attrs, i);
    6154             :         }
    6155        1858 :         if (notnull_attrs)
    6156        1450 :             needscan = true;
    6157             :     }
    6158             : 
    6159        5328 :     if (newrel || needscan)
    6160             :     {
    6161             :         ExprContext *econtext;
    6162             :         TupleTableSlot *oldslot;
    6163             :         TupleTableSlot *newslot;
    6164             :         TableScanDesc scan;
    6165             :         MemoryContext oldCxt;
    6166        4422 :         List       *dropped_attrs = NIL;
    6167             :         ListCell   *lc;
    6168             :         Snapshot    snapshot;
    6169             : 
    6170        4422 :         if (newrel)
    6171         878 :             ereport(DEBUG1,
    6172             :                     (errmsg_internal("rewriting table \"%s\"",
    6173             :                                      RelationGetRelationName(oldrel))));
    6174             :         else
    6175        3544 :             ereport(DEBUG1,
    6176             :                     (errmsg_internal("verifying table \"%s\"",
    6177             :                                      RelationGetRelationName(oldrel))));
    6178             : 
    6179        4422 :         if (newrel)
    6180             :         {
    6181             :             /*
    6182             :              * All predicate locks on the tuples or pages are about to be made
    6183             :              * invalid, because we move tuples around.  Promote them to
    6184             :              * relation locks.
    6185             :              */
    6186         878 :             TransferPredicateLocksToHeapRelation(oldrel);
    6187             :         }
    6188             : 
    6189        4422 :         econtext = GetPerTupleExprContext(estate);
    6190             : 
    6191             :         /*
    6192             :          * Create necessary tuple slots. When rewriting, two slots are needed,
    6193             :          * otherwise one suffices. In the case where one slot suffices, we
    6194             :          * need to use the new tuple descriptor, otherwise some constraints
    6195             :          * can't be evaluated.  Note that even when the tuple layout is the
    6196             :          * same and no rewrite is required, the tupDescs might not be
    6197             :          * (consider ADD COLUMN without a default).
    6198             :          */
    6199        4422 :         if (tab->rewrite)
    6200             :         {
    6201             :             Assert(newrel != NULL);
    6202         878 :             oldslot = MakeSingleTupleTableSlot(oldTupDesc,
    6203             :                                                table_slot_callbacks(oldrel));
    6204         878 :             newslot = MakeSingleTupleTableSlot(newTupDesc,
    6205             :                                                table_slot_callbacks(newrel));
    6206             : 
    6207             :             /*
    6208             :              * Set all columns in the new slot to NULL initially, to ensure
    6209             :              * columns added as part of the rewrite are initialized to NULL.
    6210             :              * That is necessary as tab->newvals will not contain an
    6211             :              * expression for columns with a NULL default, e.g. when adding a
    6212             :              * column without a default together with a column with a default
    6213             :              * requiring an actual rewrite.
    6214             :              */
    6215         878 :             ExecStoreAllNullTuple(newslot);
    6216             :         }
    6217             :         else
    6218             :         {
    6219        3544 :             oldslot = MakeSingleTupleTableSlot(newTupDesc,
    6220             :                                                table_slot_callbacks(oldrel));
    6221        3544 :             newslot = NULL;
    6222             :         }
    6223             : 
    6224             :         /*
    6225             :          * Any attributes that are dropped according to the new tuple
    6226             :          * descriptor can be set to NULL. We precompute the list of dropped
    6227             :          * attributes to avoid needing to do so in the per-tuple loop.
    6228             :          */
    6229       15804 :         for (i = 0; i < newTupDesc->natts; i++)
    6230             :         {
    6231       11382 :             if (TupleDescAttr(newTupDesc, i)->attisdropped)
    6232         790 :                 dropped_attrs = lappend_int(dropped_attrs, i);
    6233             :         }
    6234             : 
    6235             :         /*
    6236             :          * Scan through the rows, generating a new row if needed and then
    6237             :          * checking all the constraints.
    6238             :          */
    6239        4422 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    6240        4422 :         scan = table_beginscan(oldrel, snapshot, 0, NULL);
    6241             : 
    6242             :         /*
    6243             :          * Switch to per-tuple memory context and reset it for each tuple
    6244             :          * produced, so we don't leak memory.
    6245             :          */
    6246        4422 :         oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
    6247             : 
    6248      766990 :         while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
    6249             :         {
    6250             :             TupleTableSlot *insertslot;
    6251             : 
    6252      762786 :             if (tab->rewrite > 0)
    6253             :             {
    6254             :                 /* Extract data from old tuple */
    6255       97564 :                 slot_getallattrs(oldslot);
    6256       97564 :                 ExecClearTuple(newslot);
    6257             : 
    6258             :                 /* copy attributes */
    6259       97564 :                 memcpy(newslot->tts_values, oldslot->tts_values,
    6260       97564 :                        sizeof(Datum) * oldslot->tts_nvalid);
    6261       97564 :                 memcpy(newslot->tts_isnull, oldslot->tts_isnull,
    6262       97564 :                        sizeof(bool) * oldslot->tts_nvalid);
    6263             : 
    6264             :                 /* Set dropped attributes to null in new tuple */
    6265       97650 :                 foreach(lc, dropped_attrs)
    6266          86 :                     newslot->tts_isnull[lfirst_int(lc)] = true;
    6267             : 
    6268             :                 /*
    6269             :                  * Constraints and GENERATED expressions might reference the
    6270             :                  * tableoid column, so fill tts_tableOid with the desired
    6271             :                  * value.  (We must do this each time, because it gets
    6272             :                  * overwritten with newrel's OID during storing.)
    6273             :                  */
    6274       97564 :                 newslot->tts_tableOid = RelationGetRelid(oldrel);
    6275             : 
    6276             :                 /*
    6277             :                  * Process supplied expressions to replace selected columns.
    6278             :                  *
    6279             :                  * First, evaluate expressions whose inputs come from the old
    6280             :                  * tuple.
    6281             :                  */
    6282       97564 :                 econtext->ecxt_scantuple = oldslot;
    6283             : 
    6284      200948 :                 foreach(l, tab->newvals)
    6285             :                 {
    6286      103396 :                     NewColumnValue *ex = lfirst(l);
    6287             : 
    6288      103396 :                     if (ex->is_generated)
    6289         150 :                         continue;
    6290             : 
    6291      103246 :                     newslot->tts_values[ex->attnum - 1]
    6292      103234 :                         = ExecEvalExpr(ex->exprstate,
    6293             :                                        econtext,
    6294      103246 :                                        &newslot->tts_isnull[ex->attnum - 1]);
    6295             :                 }
    6296             : 
    6297       97552 :                 ExecStoreVirtualTuple(newslot);
    6298             : 
    6299             :                 /*
    6300             :                  * Now, evaluate any expressions whose inputs come from the
    6301             :                  * new tuple.  We assume these columns won't reference each
    6302             :                  * other, so that there's no ordering dependency.
    6303             :                  */
    6304       97552 :                 econtext->ecxt_scantuple = newslot;
    6305             : 
    6306      200936 :                 foreach(l, tab->newvals)
    6307             :                 {
    6308      103384 :                     NewColumnValue *ex = lfirst(l);
    6309             : 
    6310      103384 :                     if (!ex->is_generated)
    6311      103234 :                         continue;
    6312             : 
    6313         150 :                     newslot->tts_values[ex->attnum - 1]
    6314         150 :                         = ExecEvalExpr(ex->exprstate,
    6315             :                                        econtext,
    6316         150 :                                        &newslot->tts_isnull[ex->attnum - 1]);
    6317             :                 }
    6318             : 
    6319       97552 :                 insertslot = newslot;
    6320             :             }
    6321             :             else
    6322             :             {
    6323             :                 /*
    6324             :                  * If there's no rewrite, old and new table are guaranteed to
    6325             :                  * have the same AM, so we can just use the old slot to verify
    6326             :                  * new constraints etc.
    6327             :                  */
    6328      665222 :                 insertslot = oldslot;
    6329             :             }
    6330             : 
    6331             :             /* Now check any constraints on the possibly-changed tuple */
    6332      762774 :             econtext->ecxt_scantuple = insertslot;
    6333             : 
    6334     3339076 :             foreach(l, notnull_attrs)
    6335             :             {
    6336     2576362 :                 int         attn = lfirst_int(l);
    6337             : 
    6338     2576362 :                 if (slot_attisnull(insertslot, attn + 1))
    6339             :                 {
    6340          60 :                     Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
    6341             : 
    6342          60 :                     ereport(ERROR,
    6343             :                             (errcode(ERRCODE_NOT_NULL_VIOLATION),
    6344             :                              errmsg("column \"%s\" of relation \"%s\" contains null values",
    6345             :                                     NameStr(attr->attname),
    6346             :                                     RelationGetRelationName(oldrel)),
    6347             :                              errtablecol(oldrel, attn + 1)));
    6348             :                 }
    6349             :             }
    6350             : 
    6351      770814 :             foreach(l, tab->constraints)
    6352             :             {
    6353        8172 :                 NewConstraint *con = lfirst(l);
    6354             : 
    6355        8172 :                 switch (con->contype)
    6356             :                 {
    6357        8072 :                     case CONSTR_CHECK:
    6358        8072 :                         if (!ExecCheck(con->qualstate, econtext))
    6359          72 :                             ereport(ERROR,
    6360             :                                     (errcode(ERRCODE_CHECK_VIOLATION),
    6361             :                                      errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
    6362             :                                             con->name,
    6363             :                                             RelationGetRelationName(oldrel)),
    6364             :                                      errtableconstraint(oldrel, con->name)));
    6365        8000 :                         break;
    6366         100 :                     case CONSTR_NOTNULL:
    6367             :                     case CONSTR_FOREIGN:
    6368             :                         /* Nothing to do here */
    6369         100 :                         break;
    6370           0 :                     default:
    6371           0 :                         elog(ERROR, "unrecognized constraint type: %d",
    6372             :                              (int) con->contype);
    6373             :                 }
    6374             :             }
    6375             : 
    6376      762642 :             if (partqualstate && !ExecCheck(partqualstate, econtext))
    6377             :             {
    6378          74 :                 if (tab->validate_default)
    6379          26 :                     ereport(ERROR,
    6380             :                             (errcode(ERRCODE_CHECK_VIOLATION),
    6381             :                              errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
    6382             :                                     RelationGetRelationName(oldrel)),
    6383             :                              errtable(oldrel)));
    6384             :                 else
    6385          48 :                     ereport(ERROR,
    6386             :                             (errcode(ERRCODE_CHECK_VIOLATION),
    6387             :                              errmsg("partition constraint of relation \"%s\" is violated by some row",
    6388             :                                     RelationGetRelationName(oldrel)),
    6389             :                              errtable(oldrel)));
    6390             :             }
    6391             : 
    6392             :             /* Write the tuple out to the new relation */
    6393      762568 :             if (newrel)
    6394       97540 :                 table_tuple_insert(newrel, insertslot, mycid,
    6395             :                                    ti_options, bistate);
    6396             : 
    6397      762568 :             ResetExprContext(econtext);
    6398             : 
    6399      762568 :             CHECK_FOR_INTERRUPTS();
    6400             :         }
    6401             : 
    6402        4204 :         MemoryContextSwitchTo(oldCxt);
    6403        4204 :         table_endscan(scan);
    6404        4204 :         UnregisterSnapshot(snapshot);
    6405             : 
    6406        4204 :         ExecDropSingleTupleTableSlot(oldslot);
    6407        4204 :         if (newslot)
    6408         854 :             ExecDropSingleTupleTableSlot(newslot);
    6409             :     }
    6410             : 
    6411        5110 :     FreeExecutorState(estate);
    6412             : 
    6413        5110 :     table_close(oldrel, NoLock);
    6414        5110 :     if (newrel)
    6415             :     {
    6416         854 :         FreeBulkInsertState(bistate);
    6417             : 
    6418         854 :         table_finish_bulk_insert(newrel, ti_options);
    6419             : 
    6420         854 :         table_close(newrel, NoLock);
    6421             :     }
    6422        5110 : }
    6423             : 
    6424             : /*
    6425             :  * ATGetQueueEntry: find or create an entry in the ALTER TABLE work queue
    6426             :  */
    6427             : static AlteredTableInfo *
    6428       43398 : ATGetQueueEntry(List **wqueue, Relation rel)
    6429             : {
    6430       43398 :     Oid         relid = RelationGetRelid(rel);
    6431             :     AlteredTableInfo *tab;
    6432             :     ListCell   *ltab;
    6433             : 
    6434       52406 :     foreach(ltab, *wqueue)
    6435             :     {
    6436       14004 :         tab = (AlteredTableInfo *) lfirst(ltab);
    6437       14004 :         if (tab->relid == relid)
    6438        4996 :             return tab;
    6439             :     }
    6440             : 
    6441             :     /*
    6442             :      * Not there, so add it.  Note that we make a copy of the relation's
    6443             :      * existing descriptor before anything interesting can happen to it.
    6444             :      */
    6445       38402 :     tab = (AlteredTableInfo *) palloc0(sizeof(AlteredTableInfo));
    6446       38402 :     tab->relid = relid;
    6447       38402 :     tab->rel = NULL;         /* set later */
    6448       38402 :     tab->relkind = rel->rd_rel->relkind;
    6449       38402 :     tab->oldDesc = CreateTupleDescCopyConstr(RelationGetDescr(rel));
    6450       38402 :     tab->newAccessMethod = InvalidOid;
    6451       38402 :     tab->chgAccessMethod = false;
    6452       38402 :     tab->newTableSpace = InvalidOid;
    6453       38402 :     tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
    6454       38402 :     tab->chgPersistence = false;
    6455             : 
    6456       38402 :     *wqueue = lappend(*wqueue, tab);
    6457             : 
    6458       38402 :     return tab;
    6459             : }
    6460             : 
    6461             : static const char *
    6462          42 : alter_table_type_to_string(AlterTableType cmdtype)
    6463             : {
    6464          42 :     switch (cmdtype)
    6465             :     {
    6466           0 :         case AT_AddColumn:
    6467             :         case AT_AddColumnToView:
    6468           0 :             return "ADD COLUMN";
    6469           0 :         case AT_ColumnDefault:
    6470             :         case AT_CookedColumnDefault:
    6471           0 :             return "ALTER COLUMN ... SET DEFAULT";
    6472           6 :         case AT_DropNotNull:
    6473           6 :             return "ALTER COLUMN ... DROP NOT NULL";
    6474           6 :         case AT_SetNotNull:
    6475           6 :             return "ALTER COLUMN ... SET NOT NULL";
    6476           0 :         case AT_SetAttNotNull:
    6477           0 :             return NULL;        /* not real grammar */
    6478           0 :         case AT_SetExpression:
    6479           0 :             return "ALTER COLUMN ... SET EXPRESSION";
    6480           0 :         case AT_DropExpression:
    6481           0 :             return "ALTER COLUMN ... DROP EXPRESSION";
    6482           0 :         case AT_SetStatistics:
    6483           0 :             return "ALTER COLUMN ... SET STATISTICS";
    6484          12 :         case AT_SetOptions:
    6485          12 :             return "ALTER COLUMN ... SET";
    6486           0 :         case AT_ResetOptions:
    6487           0 :             return "ALTER COLUMN ... RESET";
    6488           0 :         case AT_SetStorage:
    6489           0 :             return "ALTER COLUMN ... SET STORAGE";
    6490           0 :         case AT_SetCompression:
    6491           0 :             return "ALTER COLUMN ... SET COMPRESSION";
    6492           6 :         case AT_DropColumn:
    6493           6 :             return "DROP COLUMN";
    6494           0 :         case AT_AddIndex:
    6495             :         case AT_ReAddIndex:
    6496           0 :             return NULL;        /* not real grammar */
    6497           0 :         case AT_AddConstraint:
    6498             :         case AT_ReAddConstraint:
    6499             :         case AT_ReAddDomainConstraint:
    6500             :         case AT_AddIndexConstraint:
    6501           0 :             return "ADD CONSTRAINT";
    6502           6 :         case AT_AlterConstraint:
    6503           6 :             return "ALTER CONSTRAINT";
    6504           0 :         case AT_ValidateConstraint:
    6505           0 :             return "VALIDATE CONSTRAINT";
    6506           0 :         case AT_DropConstraint:
    6507           0 :             return "DROP CONSTRAINT";
    6508           0 :         case AT_ReAddComment:
    6509           0 :             return NULL;        /* not real grammar */
    6510           0 :         case AT_AlterColumnType:
    6511           0 :             return "ALTER COLUMN ... SET DATA TYPE";
    6512           0 :         case AT_AlterColumnGenericOptions:
    6513           0 :             return "ALTER COLUMN ... OPTIONS";
    6514           0 :         case AT_ChangeOwner:
    6515           0 :             return "OWNER TO";
    6516           0 :         case AT_ClusterOn:
    6517           0 :             return "CLUSTER ON";
    6518           0 :         case AT_DropCluster:
    6519           0 :             return "SET WITHOUT CLUSTER";
    6520           0 :         case AT_SetAccessMethod:
    6521           0 :             return "SET ACCESS METHOD";
    6522           0 :         case AT_SetLogged:
    6523           0 :             return "SET LOGGED";
    6524           0 :         case AT_SetUnLogged:
    6525           0 :             return "SET UNLOGGED";
    6526           0 :         case AT_DropOids:
    6527           0 :             return "SET WITHOUT OIDS";
    6528           0 :         case AT_SetTableSpace:
    6529           0 :             return "SET TABLESPACE";
    6530           0 :         case AT_SetRelOptions:
    6531           0 :             return "SET";
    6532           0 :         case AT_ResetRelOptions:
    6533           0 :             return "RESET";
    6534           0 :         case AT_ReplaceRelOptions:
    6535           0 :             return NULL;        /* not real grammar */
    6536           0 :         case AT_EnableTrig:
    6537           0 :             return "ENABLE TRIGGER";
    6538           0 :         case AT_EnableAlwaysTrig:
    6539           0 :             return "ENABLE ALWAYS TRIGGER";
    6540           0 :         case AT_EnableReplicaTrig:
    6541           0 :             return "ENABLE REPLICA TRIGGER";
    6542           0 :         case AT_DisableTrig:
    6543           0 :             return "DISABLE TRIGGER";
    6544           0 :         case AT_EnableTrigAll:
    6545           0 :             return "ENABLE TRIGGER ALL";
    6546           0 :         case AT_DisableTrigAll:
    6547           0 :             return "DISABLE TRIGGER ALL";
    6548           0 :         case AT_EnableTrigUser:
    6549           0 :             return "ENABLE TRIGGER USER";
    6550           0 :         case AT_DisableTrigUser:
    6551           0 :             return "DISABLE TRIGGER USER";
    6552           0 :         case AT_EnableRule:
    6553           0 :             return "ENABLE RULE";
    6554           0 :         case AT_EnableAlwaysRule:
    6555           0 :             return "ENABLE ALWAYS RULE";
    6556           0 :         case AT_EnableReplicaRule:
    6557           0 :             return "ENABLE REPLICA RULE";
    6558           0 :         case AT_DisableRule:
    6559           0 :             return "DISABLE RULE";
    6560           0 :         case AT_AddInherit:
    6561           0 :             return "INHERIT";
    6562           0 :         case AT_DropInherit:
    6563           0 :             return "NO INHERIT";
    6564           0 :         case AT_AddOf:
    6565           0 :             return "OF";
    6566           0 :         case AT_DropOf:
    6567           0 :             return "NOT OF";
    6568           0 :         case AT_ReplicaIdentity:
    6569           0 :             return "REPLICA IDENTITY";
    6570           0 :         case AT_EnableRowSecurity:
    6571           0 :             return "ENABLE ROW SECURITY";
    6572           0 :         case AT_DisableRowSecurity:
    6573           0 :             return "DISABLE ROW SECURITY";
    6574           0 :         case AT_ForceRowSecurity:
    6575           0 :             return "FORCE ROW SECURITY";
    6576           0 :         case AT_NoForceRowSecurity:
    6577           0 :             return "NO FORCE ROW SECURITY";
    6578           0 :         case AT_GenericOptions:
    6579           0 :             return "OPTIONS";
    6580           0 :         case AT_AttachPartition:
    6581           0 :             return "ATTACH PARTITION";
    6582           6 :         case AT_DetachPartition:
    6583           6 :             return "DETACH PARTITION";
    6584           0 :         case AT_DetachPartitionFinalize:
    6585           0 :             return "DETACH PARTITION ... FINALIZE";
    6586           0 :         case AT_SplitPartition:
    6587           0 :             return "SPLIT PARTITION";
    6588           0 :         case AT_MergePartitions:
    6589           0 :             return "MERGE PARTITIONS";
    6590           0 :         case AT_AddIdentity:
    6591           0 :             return "ALTER COLUMN ... ADD IDENTITY";
    6592           0 :         case AT_SetIdentity:
    6593           0 :             return "ALTER COLUMN ... SET";
    6594           0 :         case AT_DropIdentity:
    6595           0 :             return "ALTER COLUMN ... DROP IDENTITY";
    6596           0 :         case AT_ReAddStatistics:
    6597           0 :             return NULL;        /* not real grammar */
    6598             :     }
    6599             : 
    6600           0 :     return NULL;
    6601             : }
    6602             : 
    6603             : /*
    6604             :  * ATSimplePermissions
    6605             :  *
    6606             :  * - Ensure that it is a relation (or possibly a view)
    6607             :  * - Ensure this user is the owner
    6608             :  * - Ensure that it is not a system table
    6609             :  */
    6610             : static void
    6611       39778 : ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
    6612             : {
    6613             :     int         actual_target;
    6614             : 
    6615       39778 :     switch (rel->rd_rel->relkind)
    6616             :     {
    6617       37572 :         case RELKIND_RELATION:
    6618             :         case RELKIND_PARTITIONED_TABLE:
    6619       37572 :             actual_target = ATT_TABLE;
    6620       37572 :             break;
    6621         396 :         case RELKIND_VIEW:
    6622         396 :             actual_target = ATT_VIEW;
    6623         396 :             break;
    6624          46 :         case RELKIND_MATVIEW:
    6625          46 :             actual_target = ATT_MATVIEW;
    6626          46 :             break;
    6627         226 :         case RELKIND_INDEX:
    6628         226 :             actual_target = ATT_INDEX;
    6629         226 :             break;
    6630         426 :         case RELKIND_PARTITIONED_INDEX:
    6631         426 :             actual_target = ATT_PARTITIONED_INDEX;
    6632         426 :             break;
    6633         214 :         case RELKIND_COMPOSITE_TYPE:
    6634         214 :             actual_target = ATT_COMPOSITE_TYPE;
    6635         214 :             break;
    6636         886 :         case RELKIND_FOREIGN_TABLE:
    6637         886 :             actual_target = ATT_FOREIGN_TABLE;
    6638         886 :             break;
    6639          12 :         case RELKIND_SEQUENCE:
    6640          12 :             actual_target = ATT_SEQUENCE;
    6641          12 :             break;
    6642           0 :         default:
    6643           0 :             actual_target = 0;
    6644           0 :             break;
    6645             :     }
    6646             : 
    6647             :     /* Wrong target type? */
    6648       39778 :     if ((actual_target & allowed_targets) == 0)
    6649             :     {
    6650          42 :         const char *action_str = alter_table_type_to_string(cmdtype);
    6651             : 
    6652          42 :         if (action_str)
    6653          42 :             ereport(ERROR,
    6654             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    6655             :             /* translator: %s is a group of some SQL keywords */
    6656             :                      errmsg("ALTER action %s cannot be performed on relation \"%s\"",
    6657             :                             action_str, RelationGetRelationName(rel)),
    6658             :                      errdetail_relkind_not_supported(rel->rd_rel->relkind)));
    6659             :         else
    6660             :             /* internal error? */
    6661           0 :             elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
    6662             :                  RelationGetRelationName(rel));
    6663             :     }
    6664             : 
    6665             :     /* Permissions checks */
    6666       39736 :     if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
    6667          12 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
    6668          12 :                        RelationGetRelationName(rel));
    6669             : 
    6670       39724 :     if (!allowSystemTableMods && IsSystemRelation(rel))
    6671           0 :         ereport(ERROR,
    6672             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    6673             :                  errmsg("permission denied: \"%s\" is a system catalog",
    6674             :                         RelationGetRelationName(rel))));
    6675       39724 : }
    6676             : 
    6677             : /*
    6678             :  * ATSimpleRecursion
    6679             :  *
    6680             :  * Simple table recursion sufficient for most ALTER TABLE operations.
    6681             :  * All direct and indirect children are processed in an unspecified order.
    6682             :  * Note that if a child inherits from the original table via multiple
    6683             :  * inheritance paths, it will be visited just once.
    6684             :  */
    6685             : static void
    6686       15540 : ATSimpleRecursion(List **wqueue, Relation rel,
    6687             :                   AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode,
    6688             :                   AlterTableUtilityContext *context)
    6689             : {
    6690             :     /*
    6691             :      * Propagate to children, if desired and if there are (or might be) any
    6692             :      * children.
    6693             :      */
    6694       15540 :     if (recurse && rel->rd_rel->relhassubclass)
    6695             :     {
    6696         142 :         Oid         relid = RelationGetRelid(rel);
    6697             :         ListCell   *child;
    6698             :         List       *children;
    6699             : 
    6700         142 :         children = find_all_inheritors(relid, lockmode, NULL);
    6701             : 
    6702             :         /*
    6703             :          * find_all_inheritors does the recursive search of the inheritance
    6704             :          * hierarchy, so all we have to do is process all of the relids in the
    6705             :          * list that it returns.
    6706             :          */
    6707         606 :         foreach(child, children)
    6708             :         {
    6709         464 :             Oid         childrelid = lfirst_oid(child);
    6710             :             Relation    childrel;
    6711             : 
    6712         464 :             if (childrelid == relid)
    6713         142 :                 continue;
    6714             :             /* find_all_inheritors already got lock */
    6715         322 :             childrel = relation_open(childrelid, NoLock);
    6716         322 :             CheckTableNotInUse(childrel, "ALTER TABLE");
    6717         322 :             ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
    6718         322 :             relation_close(childrel, NoLock);
    6719             :         }
    6720             :     }
    6721       15540 : }
    6722             : 
    6723             : /*
    6724             :  * Obtain list of partitions of the given table, locking them all at the given
    6725             :  * lockmode and ensuring that they all pass CheckTableNotInUse.
    6726             :  *
    6727             :  * This function is a no-op if the given relation is not a partitioned table;
    6728             :  * in particular, nothing is done if it's a legacy inheritance parent.
    6729             :  */
    6730             : static void
    6731         946 : ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode)
    6732             : {
    6733         946 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    6734             :     {
    6735             :         List       *inh;
    6736             :         ListCell   *cell;
    6737             : 
    6738         172 :         inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
    6739             :         /* first element is the parent rel; must ignore it */
    6740         588 :         for_each_from(cell, inh, 1)
    6741             :         {
    6742             :             Relation    childrel;
    6743             : 
    6744             :             /* find_all_inheritors already got lock */
    6745         422 :             childrel = table_open(lfirst_oid(cell), NoLock);
    6746         422 :             CheckTableNotInUse(childrel, "ALTER TABLE");
    6747         416 :             table_close(childrel, NoLock);
    6748             :         }
    6749         166 :         list_free(inh);
    6750             :     }
    6751         940 : }
    6752             : 
    6753             : /*
    6754             :  * ATTypedTableRecursion
    6755             :  *
    6756             :  * Propagate ALTER TYPE operations to the typed tables of that type.
    6757             :  * Also check the RESTRICT/CASCADE behavior.  Given CASCADE, also permit
    6758             :  * recursion to inheritance children of the typed tables.
    6759             :  */
    6760             : static void
    6761         190 : ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
    6762             :                       LOCKMODE lockmode, AlterTableUtilityContext *context)
    6763             : {
    6764             :     ListCell   *child;
    6765             :     List       *children;
    6766             : 
    6767             :     Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
    6768             : 
    6769         190 :     children = find_typed_table_dependencies(rel->rd_rel->reltype,
    6770         190 :                                              RelationGetRelationName(rel),
    6771             :                                              cmd->behavior);
    6772             : 
    6773         202 :     foreach(child, children)
    6774             :     {
    6775          30 :         Oid         childrelid = lfirst_oid(child);
    6776             :         Relation    childrel;
    6777             : 
    6778          30 :         childrel = relation_open(childrelid, lockmode);
    6779          30 :         CheckTableNotInUse(childrel, "ALTER TABLE");
    6780          30 :         ATPrepCmd(wqueue, childrel, cmd, true, true, lockmode, context);
    6781          30 :         relation_close(childrel, NoLock);
    6782             :     }
    6783         172 : }
    6784             : 
    6785             : 
    6786             : /*
    6787             :  * find_composite_type_dependencies
    6788             :  *
    6789             :  * Check to see if the type "typeOid" is being used as a column in some table
    6790             :  * (possibly nested several levels deep in composite types, arrays, etc!).
    6791             :  * Eventually, we'd like to propagate the check or rewrite operation
    6792             :  * into such tables, but for now, just error out if we find any.
    6793             :  *
    6794             :  * Caller should provide either the associated relation of a rowtype,
    6795             :  * or a type name (not both) for use in the error message, if any.
    6796             :  *
    6797             :  * Note that "typeOid" is not necessarily a composite type; it could also be
    6798             :  * another container type such as an array or range, or a domain over one of
    6799             :  * these things.  The name of this function is therefore somewhat historical,
    6800             :  * but it's not worth changing.
    6801             :  *
    6802             :  * We assume that functions and views depending on the type are not reasons
    6803             :  * to reject the ALTER.  (How safe is this really?)
    6804             :  */
    6805             : void
    6806        3866 : find_composite_type_dependencies(Oid typeOid, Relation origRelation,
    6807             :                                  const char *origTypeName)
    6808             : {
    6809             :     Relation    depRel;
    6810             :     ScanKeyData key[2];
    6811             :     SysScanDesc depScan;
    6812             :     HeapTuple   depTup;
    6813             : 
    6814             :     /* since this function recurses, it could be driven to stack overflow */
    6815        3866 :     check_stack_depth();
    6816             : 
    6817             :     /*
    6818             :      * We scan pg_depend to find those things that depend on the given type.
    6819             :      * (We assume we can ignore refobjsubid for a type.)
    6820             :      */
    6821        3866 :     depRel = table_open(DependRelationId, AccessShareLock);
    6822             : 
    6823        3866 :     ScanKeyInit(&key[0],
    6824             :                 Anum_pg_depend_refclassid,
    6825             :                 BTEqualStrategyNumber, F_OIDEQ,
    6826             :                 ObjectIdGetDatum(TypeRelationId));
    6827        3866 :     ScanKeyInit(&key[1],
    6828             :                 Anum_pg_depend_refobjid,
    6829             :                 BTEqualStrategyNumber, F_OIDEQ,
    6830             :                 ObjectIdGetDatum(typeOid));
    6831             : 
    6832        3866 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
    6833             :                                  NULL, 2, key);
    6834             : 
    6835        5976 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
    6836             :     {
    6837        2206 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
    6838             :         Relation    rel;
    6839             :         TupleDesc   tupleDesc;
    6840             :         Form_pg_attribute att;
    6841             : 
    6842             :         /* Check for directly dependent types */
    6843        2206 :         if (pg_depend->classid == TypeRelationId)
    6844             :         {
    6845             :             /*
    6846             :              * This must be an array, domain, or range containing the given
    6847             :              * type, so recursively check for uses of this type.  Note that
    6848             :              * any error message will mention the original type not the
    6849             :              * container; this is intentional.
    6850             :              */
    6851        1860 :             find_composite_type_dependencies(pg_depend->objid,
    6852             :                                              origRelation, origTypeName);
    6853        1836 :             continue;
    6854             :         }
    6855             : 
    6856             :         /* Else, ignore dependees that aren't relations */
    6857         346 :         if (pg_depend->classid != RelationRelationId)
    6858         122 :             continue;
    6859             : 
    6860         224 :         rel = relation_open(pg_depend->objid, AccessShareLock);
    6861         224 :         tupleDesc = RelationGetDescr(rel);
    6862             : 
    6863             :         /*
    6864             :          * If objsubid identifies a specific column, refer to that in error
    6865             :          * messages.  Otherwise, search to see if there's a user column of the
    6866             :          * type.  (We assume system columns are never of interesting types.)
    6867             :          * The search is needed because an index containing an expression
    6868             :          * column of the target type will just be recorded as a whole-relation
    6869             :          * dependency.  If we do not find a column of the type, the dependency
    6870             :          * must indicate that the type is transiently referenced in an index
    6871             :          * expression but not stored on disk, which we assume is OK, just as
    6872             :          * we do for references in views.  (It could also be that the target
    6873             :          * type is embedded in some container type that is stored in an index
    6874             :          * column, but the previous recursion should catch such cases.)
    6875             :          */
    6876         224 :         if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
    6877          66 :             att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
    6878             :         else
    6879             :         {
    6880         158 :             att = NULL;
    6881         406 :             for (int attno = 1; attno <= tupleDesc->natts; attno++)
    6882             :             {
    6883         254 :                 att = TupleDescAttr(tupleDesc, attno - 1);
    6884         254 :                 if (att->atttypid == typeOid && !att->attisdropped)
    6885           6 :                     break;
    6886         248 :                 att = NULL;
    6887             :             }
    6888         158 :             if (att == NULL)
    6889             :             {
    6890             :                 /* No such column, so assume OK */
    6891         152 :                 relation_close(rel, AccessShareLock);
    6892         152 :                 continue;
    6893             :             }
    6894             :         }
    6895             : 
    6896             :         /*
    6897             :          * We definitely should reject if the relation has storage.  If it's
    6898             :          * partitioned, then perhaps we don't have to reject: if there are
    6899             :          * partitions then we'll fail when we find one, else there is no
    6900             :          * stored data to worry about.  However, it's possible that the type
    6901             :          * change would affect conclusions about whether the type is sortable
    6902             :          * or hashable and thus (if it's a partitioning column) break the
    6903             :          * partitioning rule.  For now, reject for partitioned rels too.
    6904             :          */
    6905          72 :         if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
    6906           0 :             RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
    6907             :         {
    6908          72 :             if (origTypeName)
    6909          30 :                 ereport(ERROR,
    6910             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6911             :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
    6912             :                                 origTypeName,
    6913             :                                 RelationGetRelationName(rel),
    6914             :                                 NameStr(att->attname))));
    6915          42 :             else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
    6916          18 :                 ereport(ERROR,
    6917             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6918             :                          errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
    6919             :                                 RelationGetRelationName(origRelation),
    6920             :                                 RelationGetRelationName(rel),
    6921             :                                 NameStr(att->attname))));
    6922          24 :             else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
    6923           6 :                 ereport(ERROR,
    6924             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6925             :                          errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
    6926             :                                 RelationGetRelationName(origRelation),
    6927             :                                 RelationGetRelationName(rel),
    6928             :                                 NameStr(att->attname))));
    6929             :             else
    6930          18 :                 ereport(ERROR,
    6931             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6932             :                          errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
    6933             :                                 RelationGetRelationName(origRelation),
    6934             :                                 RelationGetRelationName(rel),
    6935             :                                 NameStr(att->attname))));
    6936             :         }
    6937           0 :         else if (OidIsValid(rel->rd_rel->reltype))
    6938             :         {
    6939             :             /*
    6940             :              * A view or composite type itself isn't a problem, but we must
    6941             :              * recursively check for indirect dependencies via its rowtype.
    6942             :              */
    6943           0 :             find_composite_type_dependencies(rel->rd_rel->reltype,
    6944             :                                              origRelation, origTypeName);
    6945             :         }
    6946             : 
    6947           0 :         relation_close(rel, AccessShareLock);
    6948             :     }
    6949             : 
    6950        3770 :     systable_endscan(depScan);
    6951             : 
    6952        3770 :     relation_close(depRel, AccessShareLock);
    6953        3770 : }
    6954             : 
    6955             : 
    6956             : /*
    6957             :  * find_typed_table_dependencies
    6958             :  *
    6959             :  * Check to see if a composite type is being used as the type of a
    6960             :  * typed table.  Abort if any are found and behavior is RESTRICT.
    6961             :  * Else return the list of tables.
    6962             :  */
    6963             : static List *
    6964         214 : find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
    6965             : {
    6966             :     Relation    classRel;
    6967             :     ScanKeyData key[1];
    6968             :     TableScanDesc scan;
    6969             :     HeapTuple   tuple;
    6970         214 :     List       *result = NIL;
    6971             : 
    6972         214 :     classRel = table_open(RelationRelationId, AccessShareLock);
    6973             : 
    6974         214 :     ScanKeyInit(&key[0],
    6975             :                 Anum_pg_class_reloftype,
    6976             :                 BTEqualStrategyNumber, F_OIDEQ,
    6977             :                 ObjectIdGetDatum(typeOid));
    6978             : 
    6979         214 :     scan = table_beginscan_catalog(classRel, 1, key);
    6980             : 
    6981         250 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
    6982             :     {
    6983          60 :         Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
    6984             : 
    6985          60 :         if (behavior == DROP_RESTRICT)
    6986          24 :             ereport(ERROR,
    6987             :                     (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    6988             :                      errmsg("cannot alter type \"%s\" because it is the type of a typed table",
    6989             :                             typeName),
    6990             :                      errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
    6991             :         else
    6992          36 :             result = lappend_oid(result, classform->oid);
    6993             :     }
    6994             : 
    6995         190 :     table_endscan(scan);
    6996         190 :     table_close(classRel, AccessShareLock);
    6997             : 
    6998         190 :     return result;
    6999             : }
    7000             : 
    7001             : 
    7002             : /*
    7003             :  * check_of_type
    7004             :  *
    7005             :  * Check whether a type is suitable for CREATE TABLE OF/ALTER TABLE OF.  If it
    7006             :  * isn't suitable, throw an error.  Currently, we require that the type
    7007             :  * originated with CREATE TYPE AS.  We could support any row type, but doing so
    7008             :  * would require handling a number of extra corner cases in the DDL commands.
    7009             :  * (Also, allowing domain-over-composite would open up a can of worms about
    7010             :  * whether and how the domain's constraints should apply to derived tables.)
    7011             :  */
    7012             : void
    7013         170 : check_of_type(HeapTuple typetuple)
    7014             : {
    7015         170 :     Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
    7016         170 :     bool        typeOk = false;
    7017             : 
    7018         170 :     if (typ->typtype == TYPTYPE_COMPOSITE)
    7019             :     {
    7020             :         Relation    typeRelation;
    7021             : 
    7022             :         Assert(OidIsValid(typ->typrelid));
    7023         170 :         typeRelation = relation_open(typ->typrelid, AccessShareLock);
    7024         170 :         typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
    7025             : 
    7026             :         /*
    7027             :          * Close the parent rel, but keep our AccessShareLock on it until xact
    7028             :          * commit.  That will prevent someone else from deleting or ALTERing
    7029             :          * the type before the typed table creation/conversion commits.
    7030             :          */
    7031         170 :         relation_close(typeRelation, NoLock);
    7032             :     }
    7033         170 :     if (!typeOk)
    7034           6 :         ereport(ERROR,
    7035             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    7036             :                  errmsg("type %s is not a composite type",
    7037             :                         format_type_be(typ->oid))));
    7038         164 : }
    7039             : 
    7040             : 
    7041             : /*
    7042             :  * ALTER TABLE ADD COLUMN
    7043             :  *
    7044             :  * Adds an additional attribute to a relation making the assumption that
    7045             :  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
    7046             :  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
    7047             :  * AlterTableCmd's.
    7048             :  *
    7049             :  * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
    7050             :  * have to decide at runtime whether to recurse or not depending on whether we
    7051             :  * actually add a column or merely merge with an existing column.  (We can't
    7052             :  * check this in a static pre-pass because it won't handle multiple inheritance
    7053             :  * situations correctly.)
    7054             :  */
    7055             : static void
    7056        1980 : ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
    7057             :                 bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
    7058             :                 AlterTableUtilityContext *context)
    7059             : {
    7060        1980 :     if (rel->rd_rel->reloftype && !recursing)
    7061           6 :         ereport(ERROR,
    7062             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    7063             :                  errmsg("cannot add column to typed table")));
    7064             : 
    7065        1974 :     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
    7066          58 :         ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
    7067             : 
    7068        1968 :     if (recurse && !is_view)
    7069        1868 :         cmd->recurse = true;
    7070        1968 : }
    7071             : 
    7072             : /*
    7073             :  * Add a column to a table.  The return value is the address of the
    7074             :  * new column in the parent relation.
    7075             :  *
    7076             :  * cmd is pass-by-ref so that we can replace it with the parse-transformed
    7077             :  * copy (but that happens only after we check for IF NOT EXISTS).
    7078             :  */
    7079             : static ObjectAddress
    7080        2586 : ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
    7081             :                 AlterTableCmd **cmd, bool recurse, bool recursing,
    7082             :                 LOCKMODE lockmode, AlterTablePass cur_pass,
    7083             :                 AlterTableUtilityContext *context)
    7084             : {
    7085        2586 :     Oid         myrelid = RelationGetRelid(rel);
    7086        2586 :     ColumnDef  *colDef = castNode(ColumnDef, (*cmd)->def);
    7087        2586 :     bool        if_not_exists = (*cmd)->missing_ok;
    7088             :     Relation    pgclass,
    7089             :                 attrdesc;
    7090             :     HeapTuple   reltup;
    7091             :     Form_pg_attribute attribute;
    7092             :     int         newattnum;
    7093             :     char        relkind;
    7094             :     Expr       *defval;
    7095             :     List       *children;
    7096             :     ListCell   *child;
    7097             :     AlterTableCmd *childcmd;
    7098             :     ObjectAddress address;
    7099             :     TupleDesc   tupdesc;
    7100             : 
    7101             :     /* since this function recurses, it could be driven to stack overflow */
    7102        2586 :     check_stack_depth();
    7103             : 
    7104             :     /* At top level, permission check was done in ATPrepCmd, else do it */
    7105        2586 :     if (recursing)
    7106         624 :         ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    7107             : 
    7108        2586 :     if (rel->rd_rel->relispartition && !recursing)
    7109          12 :         ereport(ERROR,
    7110             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    7111             :                  errmsg("cannot add column to a partition")));
    7112             : 
    7113        2574 :     attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
    7114             : 
    7115             :     /*
    7116             :      * Are we adding the column to a recursion child?  If so, check whether to
    7117             :      * merge with an existing definition for the column.  If we do merge, we
    7118             :      * must not recurse.  Children will already have the column, and recursing
    7119             :      * into them would mess up attinhcount.
    7120             :      */
    7121        2574 :     if (colDef->inhcount > 0)
    7122             :     {
    7123             :         HeapTuple   tuple;
    7124             : 
    7125             :         /* Does child already have a column by this name? */
    7126         624 :         tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
    7127         624 :         if (HeapTupleIsValid(tuple))
    7128             :         {
    7129          36 :             Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
    7130             :             Oid         ctypeId;
    7131             :             int32       ctypmod;
    7132             :             Oid         ccollid;
    7133             : 
    7134             :             /* Child column must match on type, typmod, and collation */
    7135          36 :             typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
    7136          36 :             if (ctypeId != childatt->atttypid ||
    7137          36 :                 ctypmod != childatt->atttypmod)
    7138           0 :                 ereport(ERROR,
    7139             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    7140             :                          errmsg("child table \"%s\" has different type for column \"%s\"",
    7141             :                                 RelationGetRelationName(rel), colDef->colname)));
    7142          36 :             ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
    7143          36 :             if (ccollid != childatt->attcollation)
    7144           0 :                 ereport(ERROR,
    7145             :                         (errcode(ERRCODE_COLLATION_MISMATCH),
    7146             :                          errmsg("child table \"%s\" has different collation for column \"%s\"",
    7147             :                                 RelationGetRelationName(rel), colDef->colname),
    7148             :                          errdetail("\"%s\" versus \"%s\"",
    7149             :                                    get_collation_name(ccollid),
    7150             :                                    get_collation_name(childatt->attcollation))));
    7151             : 
    7152             :             /* Bump the existing child att's inhcount */
    7153          36 :             childatt->attinhcount++;
    7154          36 :             if (childatt->attinhcount < 0)
    7155           0 :                 ereport(ERROR,
    7156             :                         errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    7157             :                         errmsg("too many inheritance parents"));
    7158          36 :             CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
    7159             : 
    7160          36 :             heap_freetuple(tuple);
    7161             : 
    7162             :             /* Inform the user about the merge */
    7163          36 :             ereport(NOTICE,
    7164             :                     (errmsg("merging definition of column \"%s\" for child \"%s\"",
    7165             :                             colDef->colname, RelationGetRelationName(rel))));
    7166             : 
    7167          36 :             table_close(attrdesc, RowExclusiveLock);
    7168             : 
    7169             :             /* Make the child column change visible */
    7170          36 :             CommandCounterIncrement();
    7171             : 
    7172          36 :             return InvalidObjectAddress;
    7173             :         }
    7174             :     }
    7175             : 
    7176             :     /* skip if the name already exists and if_not_exists is true */
    7177        2538 :     if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
    7178             :     {
    7179          54 :         table_close(attrdesc, RowExclusiveLock);
    7180          54 :         return InvalidObjectAddress;
    7181             :     }
    7182             : 
    7183             :     /*
    7184             :      * Okay, we need to add the column, so go ahead and do parse
    7185             :      * transformation.  This can result in queueing up, or even immediately
    7186             :      * executing, subsidiary operations (such as creation of unique indexes);
    7187             :      * so we mustn't do it until we have made the if_not_exists check.
    7188             :      *
    7189             :      * When recursing, the command was already transformed and we needn't do
    7190             :      * so again.  Also, if context isn't given we can't transform.  (That
    7191             :      * currently happens only for AT_AddColumnToView; we expect that view.c
    7192             :      * passed us a ColumnDef that doesn't need work.)
    7193             :      */
    7194        2454 :     if (context != NULL && !recursing)
    7195             :     {
    7196        1842 :         *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
    7197             :                                    cur_pass, context);
    7198             :         Assert(*cmd != NULL);
    7199        1842 :         colDef = castNode(ColumnDef, (*cmd)->def);
    7200             :     }
    7201             : 
    7202             :     /*
    7203             :      * Regular inheritance children are independent enough not to inherit the
    7204             :      * identity column from parent hence cannot recursively add identity
    7205             :      * column if the table has inheritance children.
    7206             :      *
    7207             :      * Partitions, on the other hand, are integral part of a partitioned table
    7208             :      * and inherit identity column.  Hence propagate identity column down the
    7209             :      * partition hierarchy.
    7210             :      */
    7211        2454 :     if (colDef->identity &&
    7212          54 :         recurse &&
    7213         102 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
    7214          48 :         find_inheritance_children(myrelid, NoLock) != NIL)
    7215           6 :         ereport(ERROR,
    7216             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7217             :                  errmsg("cannot recursively add identity column to table that has child tables")));
    7218             : 
    7219        2448 :     pgclass = table_open(RelationRelationId, RowExclusiveLock);
    7220             : 
    7221        2448 :     reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
    7222        2448 :     if (!HeapTupleIsValid(reltup))
    7223           0 :         elog(ERROR, "cache lookup failed for relation %u", myrelid);
    7224        2448 :     relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
    7225             : 
    7226             :     /* Determine the new attribute's number */
    7227        2448 :     newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
    7228        2448 :     if (newattnum > MaxHeapAttributeNumber)
    7229           0 :         ereport(ERROR,
    7230             :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    7231             :                  errmsg("tables can have at most %d columns",
    7232             :                         MaxHeapAttributeNumber)));
    7233             : 
    7234             :     /*
    7235             :      * Construct new attribute's pg_attribute entry.
    7236             :      */
    7237        2448 :     tupdesc = BuildDescForRelation(list_make1(colDef));
    7238             : 
    7239        2436 :     attribute = TupleDescAttr(tupdesc, 0);
    7240             : 
    7241             :     /* Fix up attribute number */
    7242        2436 :     attribute->attnum = newattnum;
    7243             : 
    7244             :     /* make sure datatype is legal for a column */
    7245        2436 :     CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
    7246        2436 :                        list_make1_oid(rel->rd_rel->reltype),
    7247             :                        0);
    7248             : 
    7249        2406 :     InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
    7250             : 
    7251        2406 :     table_close(attrdesc, RowExclusiveLock);
    7252             : 
    7253             :     /*
    7254             :      * Update pg_class tuple as appropriate
    7255             :      */
    7256        2406 :     ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
    7257             : 
    7258        2406 :     CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
    7259             : 
    7260        2406 :     heap_freetuple(reltup);
    7261             : 
    7262             :     /* Post creation hook for new attribute */
    7263        2406 :     InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
    7264             : 
    7265        2406 :     table_close(pgclass, RowExclusiveLock);
    7266             : 
    7267             :     /* Make the attribute's catalog entry visible */
    7268        2406 :     CommandCounterIncrement();
    7269             : 
    7270             :     /*
    7271             :      * Store the DEFAULT, if any, in the catalogs
    7272             :      */
    7273        2406 :     if (colDef->raw_default)
    7274             :     {
    7275             :         RawColumnDefault *rawEnt;
    7276             : 
    7277         700 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
    7278         700 :         rawEnt->attnum = attribute->attnum;
    7279         700 :         rawEnt->raw_default = copyObject(colDef->raw_default);
    7280             : 
    7281             :         /*
    7282             :          * Attempt to skip a complete table rewrite by storing the specified
    7283             :          * DEFAULT value outside of the heap.  This may be disabled inside
    7284             :          * AddRelationNewConstraints if the optimization cannot be applied.
    7285             :          */
    7286         700 :         rawEnt->missingMode = (!colDef->generated);
    7287             : 
    7288         700 :         rawEnt->generated = colDef->generated;
    7289             : 
    7290             :         /*
    7291             :          * This function is intended for CREATE TABLE, so it processes a
    7292             :          * _list_ of defaults, but we just do one.
    7293             :          */
    7294         700 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
    7295             :                                   false, true, false, NULL);
    7296             : 
    7297             :         /* Make the additional catalog changes visible */
    7298         688 :         CommandCounterIncrement();
    7299             : 
    7300             :         /*
    7301             :          * Did the request for a missing value work? If not we'll have to do a
    7302             :          * rewrite
    7303             :          */
    7304         688 :         if (!rawEnt->missingMode)
    7305         108 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
    7306             :     }
    7307             : 
    7308             :     /*
    7309             :      * Tell Phase 3 to fill in the default expression, if there is one.
    7310             :      *
    7311             :      * If there is no default, Phase 3 doesn't have to do anything, because
    7312             :      * that effectively means that the default is NULL.  The heap tuple access
    7313             :      * routines always check for attnum > # of attributes in tuple, and return
    7314             :      * NULL if so, so without any modification of the tuple data we will get
    7315             :      * the effect of NULL values in the new column.
    7316             :      *
    7317             :      * An exception occurs when the new column is of a domain type: the domain
    7318             :      * might have a not-null constraint, or a check constraint that indirectly
    7319             :      * rejects nulls.  If there are any domain constraints then we construct
    7320             :      * an explicit NULL default value that will be passed through
    7321             :      * CoerceToDomain processing.  (This is a tad inefficient, since it causes
    7322             :      * rewriting the table which we really don't have to do, but the present
    7323             :      * design of domain processing doesn't offer any simple way of checking
    7324             :      * the constraints more directly.)
    7325             :      *
    7326             :      * Note: we use build_column_default, and not just the cooked default
    7327             :      * returned by AddRelationNewConstraints, so that the right thing happens
    7328             :      * when a datatype's default applies.
    7329             :      *
    7330             :      * Note: it might seem that this should happen at the end of Phase 2, so
    7331             :      * that the effects of subsequent subcommands can be taken into account.
    7332             :      * It's intentional that we do it now, though.  The new column should be
    7333             :      * filled according to what is said in the ADD COLUMN subcommand, so that
    7334             :      * the effects are the same as if this subcommand had been run by itself
    7335             :      * and the later subcommands had been issued in new ALTER TABLE commands.
    7336             :      *
    7337             :      * We can skip this entirely for relations without storage, since Phase 3
    7338             :      * is certainly not going to touch them.  System attributes don't have
    7339             :      * interesting defaults, either.
    7340             :      */
    7341        2394 :     if (RELKIND_HAS_STORAGE(relkind))
    7342             :     {
    7343             :         /*
    7344             :          * For an identity column, we can't use build_column_default(),
    7345             :          * because the sequence ownership isn't set yet.  So do it manually.
    7346             :          */
    7347        2042 :         if (colDef->identity)
    7348             :         {
    7349          42 :             NextValueExpr *nve = makeNode(NextValueExpr);
    7350             : 
    7351          42 :             nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
    7352          42 :             nve->typeId = attribute->atttypid;
    7353             : 
    7354          42 :             defval = (Expr *) nve;
    7355             : 
    7356             :             /* must do a rewrite for identity columns */
    7357          42 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
    7358             :         }
    7359             :         else
    7360        2000 :             defval = (Expr *) build_column_default(rel, attribute->attnum);
    7361             : 
    7362        2042 :         if (!defval && DomainHasConstraints(attribute->atttypid))
    7363             :         {
    7364             :             Oid         baseTypeId;
    7365             :             int32       baseTypeMod;
    7366             :             Oid         baseTypeColl;
    7367             : 
    7368           6 :             baseTypeMod = attribute->atttypmod;
    7369           6 :             baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
    7370           6 :             baseTypeColl = get_typcollation(baseTypeId);
    7371           6 :             defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
    7372           6 :             defval = (Expr *) coerce_to_target_type(NULL,
    7373             :                                                     (Node *) defval,
    7374             :                                                     baseTypeId,
    7375             :                                                     attribute->atttypid,
    7376             :                                                     attribute->atttypmod,
    7377             :                                                     COERCION_ASSIGNMENT,
    7378             :                                                     COERCE_IMPLICIT_CAST,
    7379             :                                                     -1);
    7380           6 :             if (defval == NULL) /* should not happen */
    7381           0 :                 elog(ERROR, "failed to coerce base type to domain");
    7382             :         }
    7383             : 
    7384        2042 :         if (defval)
    7385             :         {
    7386             :             NewColumnValue *newval;
    7387             : 
    7388         606 :             newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
    7389         606 :             newval->attnum = attribute->attnum;
    7390         606 :             newval->expr = expression_planner(defval);
    7391         606 :             newval->is_generated = (colDef->generated != '\0');
    7392             : 
    7393         606 :             tab->newvals = lappend(tab->newvals, newval);
    7394             :         }
    7395             : 
    7396        2042 :         if (DomainHasConstraints(attribute->atttypid))
    7397          12 :             tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
    7398             : 
    7399        2042 :         if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
    7400             :         {
    7401             :             /*
    7402             :              * If the new column is NOT NULL, and there is no missing value,
    7403             :              * tell Phase 3 it needs to check for NULLs.
    7404             :              */
    7405        1592 :             tab->verify_new_notnull |= colDef->is_not_null;
    7406             :         }
    7407             :     }
    7408             : 
    7409             :     /*
    7410             :      * Add needed dependency entries for the new column.
    7411             :      */
    7412        2394 :     add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
    7413        2394 :     add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
    7414             : 
    7415             :     /*
    7416             :      * Propagate to children as appropriate.  Unlike most other ALTER
    7417             :      * routines, we have to do this one level of recursion at a time; we can't
    7418             :      * use find_all_inheritors to do it in one pass.
    7419             :      */
    7420             :     children =
    7421        2394 :         find_inheritance_children(RelationGetRelid(rel), lockmode);
    7422             : 
    7423             :     /*
    7424             :      * If we are told not to recurse, there had better not be any child
    7425             :      * tables; else the addition would put them out of step.
    7426             :      */
    7427        2394 :     if (children && !recurse)
    7428          12 :         ereport(ERROR,
    7429             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7430             :                  errmsg("column must be added to child tables too")));
    7431             : 
    7432             :     /* Children should see column as singly inherited */
    7433        2382 :     if (!recursing)
    7434             :     {
    7435        1794 :         childcmd = copyObject(*cmd);
    7436        1794 :         colDef = castNode(ColumnDef, childcmd->def);
    7437        1794 :         colDef->inhcount = 1;
    7438        1794 :         colDef->is_local = false;
    7439             :     }
    7440             :     else
    7441         588 :         childcmd = *cmd;        /* no need to copy again */
    7442             : 
    7443        3006 :     foreach(child, children)
    7444             :     {
    7445         624 :         Oid         childrelid = lfirst_oid(child);
    7446             :         Relation    childrel;
    7447             :         AlteredTableInfo *childtab;
    7448             : 
    7449             :         /* find_inheritance_children already got lock */
    7450         624 :         childrel = table_open(childrelid, NoLock);
    7451         624 :         CheckTableNotInUse(childrel, "ALTER TABLE");
    7452             : 
    7453             :         /* Find or create work queue entry for this table */
    7454         624 :         childtab = ATGetQueueEntry(wqueue, childrel);
    7455             : 
    7456             :         /* Recurse to child; return value is ignored */
    7457         624 :         ATExecAddColumn(wqueue, childtab, childrel,
    7458             :                         &childcmd, recurse, true,
    7459             :                         lockmode, cur_pass, context);
    7460             : 
    7461         624 :         table_close(childrel, NoLock);
    7462             :     }
    7463             : 
    7464        2382 :     ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
    7465        2382 :     return address;
    7466             : }
    7467             : 
    7468             : /*
    7469             :  * If a new or renamed column will collide with the name of an existing
    7470             :  * column and if_not_exists is false then error out, else do nothing.
    7471             :  */
    7472             : static bool
    7473        2976 : check_for_column_name_collision(Relation rel, const char *colname,
    7474             :                                 bool if_not_exists)
    7475             : {
    7476             :     HeapTuple   attTuple;
    7477             :     int         attnum;
    7478             : 
    7479             :     /*
    7480             :      * this test is deliberately not attisdropped-aware, since if one tries to
    7481             :      * add a column matching a dropped column name, it's gonna fail anyway.
    7482             :      */
    7483        2976 :     attTuple = SearchSysCache2(ATTNAME,
    7484             :                                ObjectIdGetDatum(RelationGetRelid(rel)),
    7485             :                                PointerGetDatum(colname));
    7486        2976 :     if (!HeapTupleIsValid(attTuple))
    7487        2880 :         return true;
    7488             : 
    7489          96 :     attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
    7490          96 :     ReleaseSysCache(attTuple);
    7491             : 
    7492             :     /*
    7493             :      * We throw a different error message for conflicts with system column
    7494             :      * names, since they are normally not shown and the user might otherwise
    7495             :      * be confused about the reason for the conflict.
    7496             :      */
    7497          96 :     if (attnum <= 0)
    7498          12 :         ereport(ERROR,
    7499             :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    7500             :                  errmsg("column name \"%s\" conflicts with a system column name",
    7501             :                         colname)));
    7502             :     else
    7503             :     {
    7504          84 :         if (if_not_exists)
    7505             :         {
    7506          54 :             ereport(NOTICE,
    7507             :                     (errcode(ERRCODE_DUPLICATE_COLUMN),
    7508             :                      errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
    7509             :                             colname, RelationGetRelationName(rel))));
    7510          54 :             return false;
    7511             :         }
    7512             : 
    7513          30 :         ereport(ERROR,
    7514             :                 (errcode(ERRCODE_DUPLICATE_COLUMN),
    7515             :                  errmsg("column \"%s\" of relation \"%s\" already exists",
    7516             :                         colname, RelationGetRelationName(rel))));
    7517             :     }
    7518             : 
    7519             :     return true;
    7520             : }
    7521             : 
    7522             : /*
    7523             :  * Install a column's dependency on its datatype.
    7524             :  */
    7525             : static void
    7526        3306 : add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
    7527             : {
    7528             :     ObjectAddress myself,
    7529             :                 referenced;
    7530             : 
    7531        3306 :     myself.classId = RelationRelationId;
    7532        3306 :     myself.objectId = relid;
    7533        3306 :     myself.objectSubId = attnum;
    7534        3306 :     referenced.classId = TypeRelationId;
    7535        3306 :     referenced.objectId = typid;
    7536        3306 :     referenced.objectSubId = 0;
    7537        3306 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    7538        3306 : }
    7539             : 
    7540             : /*
    7541             :  * Install a column's dependency on its collation.
    7542             :  */
    7543             : static void
    7544        3306 : add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
    7545             : {
    7546             :     ObjectAddress myself,
    7547             :                 referenced;
    7548             : 
    7549             :     /* We know the default collation is pinned, so don't bother recording it */
    7550        3306 :     if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
    7551             :     {
    7552          18 :         myself.classId = RelationRelationId;
    7553          18 :         myself.objectId = relid;
    7554          18 :         myself.objectSubId = attnum;
    7555          18 :         referenced.classId = CollationRelationId;
    7556          18 :         referenced.objectId = collid;
    7557          18 :         referenced.objectSubId = 0;
    7558          18 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    7559             :     }
    7560        3306 : }
    7561             : 
    7562             : /*
    7563             :  * ALTER TABLE ALTER COLUMN DROP NOT NULL
    7564             :  *
    7565             :  * Return the address of the modified column.  If the column was already
    7566             :  * nullable, InvalidObjectAddress is returned.
    7567             :  */
    7568             : static ObjectAddress
    7569         238 : ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
    7570             :                   LOCKMODE lockmode)
    7571             : {
    7572             :     HeapTuple   tuple;
    7573             :     HeapTuple   conTup;
    7574             :     Form_pg_attribute attTup;
    7575             :     AttrNumber  attnum;
    7576             :     Relation    attr_rel;
    7577             :     ObjectAddress address;
    7578             :     List       *readyRels;
    7579             : 
    7580             :     /*
    7581             :      * lookup the attribute
    7582             :      */
    7583         238 :     attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
    7584             : 
    7585         238 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    7586         238 :     if (!HeapTupleIsValid(tuple))
    7587          18 :         ereport(ERROR,
    7588             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    7589             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    7590             :                         colName, RelationGetRelationName(rel))));
    7591         220 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    7592         220 :     attnum = attTup->attnum;
    7593         220 :     ObjectAddressSubSet(address, RelationRelationId,
    7594             :                         RelationGetRelid(rel), attnum);
    7595             : 
    7596             :     /* If the column is already nullable there's nothing to do. */
    7597         220 :     if (!attTup->attnotnull)
    7598             :     {
    7599           6 :         table_close(attr_rel, RowExclusiveLock);
    7600           6 :         return InvalidObjectAddress;
    7601             :     }
    7602             : 
    7603             :     /* Prevent them from altering a system attribute */
    7604         214 :     if (attnum <= 0)
    7605           0 :         ereport(ERROR,
    7606             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    7607             :                  errmsg("cannot alter system column \"%s\"",
    7608             :                         colName)));
    7609             : 
    7610         214 :     if (attTup->attidentity)
    7611          18 :         ereport(ERROR,
    7612             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    7613             :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
    7614             :                         colName, RelationGetRelationName(rel))));
    7615             : 
    7616             :     /*
    7617             :      * It's not OK to remove a constraint only for the parent and leave it in
    7618             :      * the children, so disallow that.
    7619             :      */
    7620         196 :     if (!recurse)
    7621             :     {
    7622          12 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    7623             :         {
    7624             :             PartitionDesc partdesc;
    7625             : 
    7626          12 :             partdesc = RelationGetPartitionDesc(rel, true);
    7627             : 
    7628          12 :             if (partdesc->nparts > 0)
    7629           6 :                 ereport(ERROR,
    7630             :                         errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7631             :                         errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
    7632             :                         errhint("Do not specify the ONLY keyword."));
    7633             :         }
    7634           0 :         else if (rel->rd_rel->relhassubclass &&
    7635           0 :                  find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
    7636             :         {
    7637           0 :             ereport(ERROR,
    7638             :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7639             :                     errmsg("not-null constraint on column \"%s\" must be removed in child tables too",
    7640             :                            colName),
    7641             :                     errhint("Do not specify the ONLY keyword."));
    7642             :         }
    7643             :     }
    7644             : 
    7645             :     /*
    7646             :      * If rel is partition, shouldn't drop NOT NULL if parent has the same.
    7647             :      */
    7648         190 :     if (rel->rd_rel->relispartition)
    7649             :     {
    7650          18 :         Oid         parentId = get_partition_parent(RelationGetRelid(rel), false);
    7651          18 :         Relation    parent = table_open(parentId, AccessShareLock);
    7652          18 :         TupleDesc   tupDesc = RelationGetDescr(parent);
    7653             :         AttrNumber  parent_attnum;
    7654             : 
    7655          18 :         parent_attnum = get_attnum(parentId, colName);
    7656          18 :         if (TupleDescAttr(tupDesc, parent_attnum - 1)->attnotnull)
    7657          18 :             ereport(ERROR,
    7658             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7659             :                      errmsg("column \"%s\" is marked NOT NULL in parent table",
    7660             :                             colName)));
    7661           0 :         table_close(parent, AccessShareLock);
    7662             :     }
    7663             : 
    7664             :     /*
    7665             :      * Find the constraint that makes this column NOT NULL.
    7666             :      */
    7667         172 :     conTup = findNotNullConstraint(RelationGetRelid(rel), colName);
    7668         172 :     if (conTup == NULL)
    7669             :     {
    7670             :         Bitmapset  *pkcols;
    7671             : 
    7672             :         /*
    7673             :          * There's no not-null constraint, so throw an error.  If the column
    7674             :          * is in a primary key, we can throw a specific error.  Otherwise,
    7675             :          * this is unexpected.
    7676             :          */
    7677          12 :         pkcols = RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_PRIMARY_KEY);
    7678          12 :         if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
    7679             :                           pkcols))
    7680          12 :             ereport(ERROR,
    7681             :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7682             :                     errmsg("column \"%s\" is in a primary key", colName));
    7683             : 
    7684             :         /* this shouldn't happen */
    7685           0 :         elog(ERROR, "could not find not-null constraint on column \"%s\", relation \"%s\"",
    7686             :              colName, RelationGetRelationName(rel));
    7687             :     }
    7688             : 
    7689         160 :     readyRels = NIL;
    7690         160 :     dropconstraint_internal(rel, conTup, DROP_RESTRICT, recurse, false,
    7691             :                             false, &readyRels, lockmode);
    7692             : 
    7693         124 :     heap_freetuple(conTup);
    7694             : 
    7695         124 :     InvokeObjectPostAlterHook(RelationRelationId,
    7696             :                               RelationGetRelid(rel), attnum);
    7697             : 
    7698         124 :     table_close(attr_rel, RowExclusiveLock);
    7699             : 
    7700         124 :     return address;
    7701             : }
    7702             : 
    7703             : /*
    7704             :  * Helper to set pg_attribute.attnotnull if it isn't set, and to tell phase 3
    7705             :  * to verify it; recurses to apply the same to children.
    7706             :  *
    7707             :  * When called to alter an existing table, 'wqueue' must be given so that we can
    7708             :  * queue a check that existing tuples pass the constraint.  When called from
    7709             :  * table creation, 'wqueue' should be passed as NULL.
    7710             :  *
    7711             :  * Returns true if the flag was set in any table, otherwise false.
    7712             :  */
    7713             : static bool
    7714       23306 : set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse,
    7715             :                LOCKMODE lockmode)
    7716             : {
    7717             :     HeapTuple   tuple;
    7718             :     Form_pg_attribute attForm;
    7719       23306 :     bool        retval = false;
    7720             : 
    7721             :     /* Guard against stack overflow due to overly deep inheritance tree. */
    7722       23306 :     check_stack_depth();
    7723             : 
    7724       23306 :     tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), attnum);
    7725       23306 :     if (!HeapTupleIsValid(tuple))
    7726           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    7727             :              attnum, RelationGetRelid(rel));
    7728       23306 :     attForm = (Form_pg_attribute) GETSTRUCT(tuple);
    7729       23306 :     if (!attForm->attnotnull)
    7730             :     {
    7731             :         Relation    attr_rel;
    7732             : 
    7733        1534 :         attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
    7734             : 
    7735        1534 :         attForm->attnotnull = true;
    7736        1534 :         CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
    7737             : 
    7738        1534 :         table_close(attr_rel, RowExclusiveLock);
    7739             : 
    7740             :         /*
    7741             :          * And set up for existing values to be checked, unless another
    7742             :          * constraint already proves this.
    7743             :          */
    7744        1534 :         if (wqueue && !NotNullImpliedByRelConstraints(rel, attForm))
    7745             :         {
    7746             :             AlteredTableInfo *tab;
    7747             : 
    7748        1282 :             tab = ATGetQueueEntry(wqueue, rel);
    7749        1282 :             tab->verify_new_notnull = true;
    7750             :         }
    7751             : 
    7752        1534 :         retval = true;
    7753             :     }
    7754             : 
    7755       23306 :     if (recurse)
    7756             :     {
    7757             :         List       *children;
    7758             :         ListCell   *lc;
    7759             : 
    7760         954 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
    7761        1098 :         foreach(lc, children)
    7762             :         {
    7763         144 :             Oid         childrelid = lfirst_oid(lc);
    7764             :             Relation    childrel;
    7765             :             AttrNumber  childattno;
    7766             : 
    7767             :             /* find_inheritance_children already got lock */
    7768         144 :             childrel = table_open(childrelid, NoLock);
    7769         144 :             CheckTableNotInUse(childrel, "ALTER TABLE");
    7770             : 
    7771         144 :             childattno = get_attnum(RelationGetRelid(childrel),
    7772         144 :                                     get_attname(RelationGetRelid(rel), attnum,
    7773             :                                                 false));
    7774         144 :             retval |= set_attnotnull(wqueue, childrel, childattno,
    7775             :                                      recurse, lockmode);
    7776         144 :             table_close(childrel, NoLock);
    7777             :         }
    7778             :     }
    7779             : 
    7780       23306 :     return retval;
    7781             : }
    7782             : 
    7783             : /*
    7784             :  * ALTER TABLE ALTER COLUMN SET NOT NULL
    7785             :  *
    7786             :  * Add a not-null constraint to a single table and its children.  Returns
    7787             :  * the address of the constraint added to the parent relation, if one gets
    7788             :  * added, or InvalidObjectAddress otherwise.
    7789             :  *
    7790             :  * We must recurse to child tables during execution, rather than using
    7791             :  * ALTER TABLE's normal prep-time recursion.
    7792             :  */
    7793             : static ObjectAddress
    7794         490 : ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName,
    7795             :                  bool recurse, bool recursing, List **readyRels,
    7796             :                  LOCKMODE lockmode)
    7797             : {
    7798             :     HeapTuple   tuple;
    7799             :     Relation    constr_rel;
    7800             :     ScanKeyData skey;
    7801             :     SysScanDesc conscan;
    7802             :     AttrNumber  attnum;
    7803             :     ObjectAddress address;
    7804             :     Constraint *constraint;
    7805             :     CookedConstraint *ccon;
    7806             :     List       *cooked;
    7807         490 :     bool        is_no_inherit = false;
    7808         490 :     List       *ready = NIL;
    7809             : 
    7810             :     /* Guard against stack overflow due to overly deep inheritance tree. */
    7811         490 :     check_stack_depth();
    7812             : 
    7813             :     /*
    7814             :      * In cases of multiple inheritance, we might visit the same child more
    7815             :      * than once.  In the topmost call, set up a list that we fill with all
    7816             :      * visited relations, to skip those.
    7817             :      */
    7818         490 :     if (readyRels == NULL)
    7819             :     {
    7820             :         Assert(!recursing);
    7821         360 :         readyRels = &ready;
    7822             :     }
    7823         490 :     if (list_member_oid(*readyRels, RelationGetRelid(rel)))
    7824           6 :         return InvalidObjectAddress;
    7825         484 :     *readyRels = lappend_oid(*readyRels, RelationGetRelid(rel));
    7826             : 
    7827             :     /* At top level, permission check was done in ATPrepCmd, else do it */
    7828         484 :     if (recursing)
    7829             :     {
    7830         124 :         ATSimplePermissions(AT_AddConstraint, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
    7831             :         Assert(conName != NULL);
    7832             :     }
    7833             : 
    7834         484 :     attnum = get_attnum(RelationGetRelid(rel), colName);
    7835         484 :     if (attnum == InvalidAttrNumber)
    7836          18 :         ereport(ERROR,
    7837             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    7838             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    7839             :                         colName, RelationGetRelationName(rel))));
    7840             : 
    7841             :     /* Prevent them from altering a system attribute */
    7842         466 :     if (attnum <= 0)
    7843           0 :         ereport(ERROR,
    7844             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    7845             :                  errmsg("cannot alter system column \"%s\"",
    7846             :                         colName)));
    7847             : 
    7848             :     /* See if there's already a constraint */
    7849         466 :     constr_rel = table_open(ConstraintRelationId, RowExclusiveLock);
    7850         466 :     ScanKeyInit(&skey,
    7851             :                 Anum_pg_constraint_conrelid,
    7852             :                 BTEqualStrategyNumber, F_OIDEQ,
    7853             :                 ObjectIdGetDatum(RelationGetRelid(rel)));
    7854         466 :     conscan = systable_beginscan(constr_rel, ConstraintRelidTypidNameIndexId, true,
    7855             :                                  NULL, 1, &skey);
    7856             : 
    7857         886 :     while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
    7858             :     {
    7859         440 :         Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple);
    7860         440 :         bool        changed = false;
    7861             :         HeapTuple   copytup;
    7862             : 
    7863         440 :         if (conForm->contype != CONSTRAINT_NOTNULL)
    7864         200 :             continue;
    7865             : 
    7866         240 :         if (extractNotNullColumn(tuple) != attnum)
    7867         220 :             continue;
    7868             : 
    7869          20 :         copytup = heap_copytuple(tuple);
    7870          20 :         conForm = (Form_pg_constraint) GETSTRUCT(copytup);
    7871             : 
    7872             :         /*
    7873             :          * If we find an appropriate constraint, we're almost done, but just
    7874             :          * need to change some properties on it: if we're recursing, increment
    7875             :          * coninhcount; if not, set conislocal if not already set.
    7876             :          */
    7877          20 :         if (recursing)
    7878             :         {
    7879           6 :             conForm->coninhcount++;
    7880           6 :             changed = true;
    7881             :         }
    7882          14 :         else if (!conForm->conislocal)
    7883             :         {
    7884           0 :             conForm->conislocal = true;
    7885           0 :             changed = true;
    7886             :         }
    7887             : 
    7888          20 :         if (changed)
    7889             :         {
    7890           6 :             CatalogTupleUpdate(constr_rel, &copytup->t_self, copytup);
    7891           6 :             ObjectAddressSet(address, ConstraintRelationId, conForm->oid);
    7892             :         }
    7893             : 
    7894          20 :         systable_endscan(conscan);
    7895          20 :         table_close(constr_rel, RowExclusiveLock);
    7896             : 
    7897          20 :         if (changed)
    7898           6 :             return address;
    7899             :         else
    7900          14 :             return InvalidObjectAddress;
    7901             :     }
    7902             : 
    7903         446 :     systable_endscan(conscan);
    7904         446 :     table_close(constr_rel, RowExclusiveLock);
    7905             : 
    7906             :     /*
    7907             :      * If we're asked not to recurse, and children exist, raise an error for
    7908             :      * partitioned tables.  For inheritance, we act as if NO INHERIT had been
    7909             :      * specified.
    7910             :      */
    7911         476 :     if (!recurse &&
    7912          30 :         find_inheritance_children(RelationGetRelid(rel),
    7913             :                                   NoLock) != NIL)
    7914             :     {
    7915          24 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
    7916          12 :             ereport(ERROR,
    7917             :                     errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    7918             :                     errmsg("constraint must be added to child tables too"),
    7919             :                     errhint("Do not specify the ONLY keyword."));
    7920             :         else
    7921          12 :             is_no_inherit = true;
    7922             :     }
    7923             : 
    7924             :     /*
    7925             :      * No constraint exists; we must add one.  First determine a name to use,
    7926             :      * if we haven't already.
    7927             :      */
    7928         434 :     if (!recursing)
    7929             :     {
    7930             :         Assert(conName == NULL);
    7931         316 :         conName = ChooseConstraintName(RelationGetRelationName(rel),
    7932             :                                        colName, "not_null",
    7933         316 :                                        RelationGetNamespace(rel),
    7934             :                                        NIL);
    7935             :     }
    7936         434 :     constraint = makeNode(Constraint);
    7937         434 :     constraint->contype = CONSTR_NOTNULL;
    7938         434 :     constraint->conname = conName;
    7939         434 :     constraint->deferrable = false;
    7940         434 :     constraint->initdeferred = false;
    7941         434 :     constraint->location = -1;
    7942         434 :     constraint->keys = list_make1(makeString(colName));
    7943         434 :     constraint->is_no_inherit = is_no_inherit;
    7944         434 :     constraint->inhcount = recursing ? 1 : 0;
    7945         434 :     constraint->skip_validation = false;
    7946         434 :     constraint->initially_valid = true;
    7947             : 
    7948             :     /* and do it */
    7949         434 :     cooked = AddRelationNewConstraints(rel, NIL, list_make1(constraint),
    7950         434 :                                        false, !recursing, false, NULL);
    7951         434 :     ccon = linitial(cooked);
    7952         434 :     ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
    7953             : 
    7954         434 :     InvokeObjectPostAlterHook(RelationRelationId,
    7955             :                               RelationGetRelid(rel), attnum);
    7956             : 
    7957             :     /*
    7958             :      * Mark pg_attribute.attnotnull for the column. Tell that function not to
    7959             :      * recurse, because we're going to do it here.
    7960             :      */
    7961         434 :     set_attnotnull(wqueue, rel, attnum, false, lockmode);
    7962             : 
    7963             :     /*
    7964             :      * Recurse to propagate the constraint to children that don't have one.
    7965             :      */
    7966         434 :     if (recurse)
    7967             :     {
    7968             :         List       *children;
    7969             :         ListCell   *lc;
    7970             : 
    7971         416 :         children = find_inheritance_children(RelationGetRelid(rel),
    7972             :                                              lockmode);
    7973             : 
    7974         546 :         foreach(lc, children)
    7975             :         {
    7976             :             Relation    childrel;
    7977             : 
    7978         130 :             childrel = table_open(lfirst_oid(lc), NoLock);
    7979             : 
    7980         130 :             ATExecSetNotNull(wqueue, childrel,
    7981             :                              conName, colName, recurse, true,
    7982             :                              readyRels, lockmode);
    7983             : 
    7984         130 :             table_close(childrel, NoLock);
    7985             :         }
    7986             :     }
    7987             : 
    7988         434 :     return address;
    7989             : }
    7990             : 
    7991             : /*
    7992             :  * ALTER TABLE ALTER COLUMN SET ATTNOTNULL
    7993             :  *
    7994             :  * This doesn't exist in the grammar; it's used when creating a
    7995             :  * primary key and the column is not already marked attnotnull.
    7996             :  */
    7997             : static ObjectAddress
    7998       14424 : ATExecSetAttNotNull(List **wqueue, Relation rel,
    7999             :                     const char *colName, LOCKMODE lockmode)
    8000             : {
    8001             :     AttrNumber  attnum;
    8002       14424 :     ObjectAddress address = InvalidObjectAddress;
    8003             : 
    8004       14424 :     attnum = get_attnum(RelationGetRelid(rel), colName);
    8005       14424 :     if (attnum == InvalidAttrNumber)
    8006          18 :         ereport(ERROR,
    8007             :                 errcode(ERRCODE_UNDEFINED_COLUMN),
    8008             :                 errmsg("column \"%s\" of relation \"%s\" does not exist",
    8009             :                        colName, RelationGetRelationName(rel)));
    8010             : 
    8011             :     /*
    8012             :      * Make the change, if necessary, and only if so report the column as
    8013             :      * changed
    8014             :      */
    8015       14406 :     if (set_attnotnull(wqueue, rel, attnum, false, lockmode))
    8016         676 :         ObjectAddressSubSet(address, RelationRelationId,
    8017             :                             RelationGetRelid(rel), attnum);
    8018             : 
    8019       14406 :     return address;
    8020             : }
    8021             : 
    8022             : /*
    8023             :  * NotNullImpliedByRelConstraints
    8024             :  *      Does rel's existing constraints imply NOT NULL for the given attribute?
    8025             :  */
    8026             : static bool
    8027        1332 : NotNullImpliedByRelConstraints(Relation rel, Form_pg_attribute attr)
    8028             : {
    8029        1332 :     NullTest   *nnulltest = makeNode(NullTest);
    8030             : 
    8031        2664 :     nnulltest->arg = (Expr *) makeVar(1,
    8032        1332 :                                       attr->attnum,
    8033             :                                       attr->atttypid,
    8034             :                                       attr->atttypmod,
    8035             :                                       attr->attcollation,
    8036             :                                       0);
    8037        1332 :     nnulltest->nulltesttype = IS_NOT_NULL;
    8038             : 
    8039             :     /*
    8040             :      * argisrow = false is correct even for a composite column, because
    8041             :      * attnotnull does not represent a SQL-spec IS NOT NULL test in such a
    8042             :      * case, just IS DISTINCT FROM NULL.
    8043             :      */
    8044        1332 :     nnulltest->argisrow = false;
    8045        1332 :     nnulltest->location = -1;
    8046             : 
    8047        1332 :     if (ConstraintImpliedByRelConstraint(rel, list_make1(nnulltest), NIL))
    8048             :     {
    8049          50 :         ereport(DEBUG1,
    8050             :                 (errmsg_internal("existing constraints on column \"%s.%s\" are sufficient to prove that it does not contain nulls",
    8051             :                                  RelationGetRelationName(rel), NameStr(attr->attname))));
    8052          50 :         return true;
    8053             :     }
    8054             : 
    8055        1282 :     return false;
    8056             : }
    8057             : 
    8058             : /*
    8059             :  * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
    8060             :  *
    8061             :  * Return the address of the affected column.
    8062             :  */
    8063             : static ObjectAddress
    8064         566 : ATExecColumnDefault(Relation rel, const char *colName,
    8065             :                     Node *newDefault, LOCKMODE lockmode)
    8066             : {
    8067         566 :     TupleDesc   tupdesc = RelationGetDescr(rel);
    8068             :     AttrNumber  attnum;
    8069             :     ObjectAddress address;
    8070             : 
    8071             :     /*
    8072             :      * get the number of the attribute
    8073             :      */
    8074         566 :     attnum = get_attnum(RelationGetRelid(rel), colName);
    8075         566 :     if (attnum == InvalidAttrNumber)
    8076          30 :         ereport(ERROR,
    8077             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8078             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    8079             :                         colName, RelationGetRelationName(rel))));
    8080             : 
    8081             :     /* Prevent them from altering a system attribute */
    8082         536 :     if (attnum <= 0)
    8083           0 :         ereport(ERROR,
    8084             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8085             :                  errmsg("cannot alter system column \"%s\"",
    8086             :                         colName)));
    8087             : 
    8088         536 :     if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
    8089          18 :         ereport(ERROR,
    8090             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    8091             :                  errmsg("column \"%s\" of relation \"%s\" is an identity column",
    8092             :                         colName, RelationGetRelationName(rel)),
    8093             :         /* translator: %s is an SQL ALTER command */
    8094             :                  newDefault ? 0 : errhint("Use %s instead.",
    8095             :                                           "ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY")));
    8096             : 
    8097         518 :     if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
    8098           6 :         ereport(ERROR,
    8099             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    8100             :                  errmsg("column \"%s\" of relation \"%s\" is a generated column",
    8101             :                         colName, RelationGetRelationName(rel)),
    8102             :                  newDefault ?
    8103             :         /* translator: %s is an SQL ALTER command */
    8104             :                  errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION") :
    8105             :                  (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_STORED ?
    8106             :                   errhint("Use %s instead.", "ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION") : 0)));
    8107             : 
    8108             :     /*
    8109             :      * Remove any old default for the column.  We use RESTRICT here for
    8110             :      * safety, but at present we do not expect anything to depend on the
    8111             :      * default.
    8112             :      *
    8113             :      * We treat removing the existing default as an internal operation when it
    8114             :      * is preparatory to adding a new default, but as a user-initiated
    8115             :      * operation when the user asked for a drop.
    8116             :      */
    8117         512 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
    8118             :                       newDefault != NULL);
    8119             : 
    8120         512 :     if (newDefault)
    8121             :     {
    8122             :         /* SET DEFAULT */
    8123             :         RawColumnDefault *rawEnt;
    8124             : 
    8125         338 :         rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
    8126         338 :         rawEnt->attnum = attnum;
    8127         338 :         rawEnt->raw_default = newDefault;
    8128         338 :         rawEnt->missingMode = false;
    8129         338 :         rawEnt->generated = '\0';
    8130             : 
    8131             :         /*
    8132             :          * This function is intended for CREATE TABLE, so it processes a
    8133             :          * _list_ of defaults, but we just do one.
    8134             :          */
    8135         338 :         AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
    8136             :                                   false, true, false, NULL);
    8137             :     }
    8138             : 
    8139         506 :     ObjectAddressSubSet(address, RelationRelationId,
    8140             :                         RelationGetRelid(rel), attnum);
    8141         506 :     return address;
    8142             : }
    8143             : 
    8144             : /*
    8145             :  * Add a pre-cooked default expression.
    8146             :  *
    8147             :  * Return the address of the affected column.
    8148             :  */
    8149             : static ObjectAddress
    8150         110 : ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
    8151             :                           Node *newDefault)
    8152             : {
    8153             :     ObjectAddress address;
    8154             : 
    8155             :     /* We assume no checking is required */
    8156             : 
    8157             :     /*
    8158             :      * Remove any old default for the column.  We use RESTRICT here for
    8159             :      * safety, but at present we do not expect anything to depend on the
    8160             :      * default.  (In ordinary cases, there could not be a default in place
    8161             :      * anyway, but it's possible when combining LIKE with inheritance.)
    8162             :      */
    8163         110 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
    8164             :                       true);
    8165             : 
    8166         110 :     (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
    8167             : 
    8168         110 :     ObjectAddressSubSet(address, RelationRelationId,
    8169             :                         RelationGetRelid(rel), attnum);
    8170         110 :     return address;
    8171             : }
    8172             : 
    8173             : /*
    8174             :  * ALTER TABLE ALTER COLUMN ADD IDENTITY
    8175             :  *
    8176             :  * Return the address of the affected column.
    8177             :  */
    8178             : static ObjectAddress
    8179         148 : ATExecAddIdentity(Relation rel, const char *colName,
    8180             :                   Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
    8181             : {
    8182             :     Relation    attrelation;
    8183             :     HeapTuple   tuple;
    8184             :     Form_pg_attribute attTup;
    8185             :     AttrNumber  attnum;
    8186             :     ObjectAddress address;
    8187         148 :     ColumnDef  *cdef = castNode(ColumnDef, def);
    8188             :     bool        ispartitioned;
    8189             : 
    8190         148 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    8191         148 :     if (ispartitioned && !recurse)
    8192           0 :         ereport(ERROR,
    8193             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8194             :                  errmsg("cannot add identity to a column of only the partitioned table"),
    8195             :                  errhint("Do not specify the ONLY keyword.")));
    8196             : 
    8197         148 :     if (rel->rd_rel->relispartition && !recursing)
    8198          12 :         ereport(ERROR,
    8199             :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8200             :                 errmsg("cannot add identity to a column of a partition"));
    8201             : 
    8202         136 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
    8203             : 
    8204         136 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    8205         136 :     if (!HeapTupleIsValid(tuple))
    8206           0 :         ereport(ERROR,
    8207             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8208             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    8209             :                         colName, RelationGetRelationName(rel))));
    8210         136 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    8211         136 :     attnum = attTup->attnum;
    8212             : 
    8213             :     /* Can't alter a system attribute */
    8214         136 :     if (attnum <= 0)
    8215           0 :         ereport(ERROR,
    8216             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8217             :                  errmsg("cannot alter system column \"%s\"",
    8218             :                         colName)));
    8219             : 
    8220             :     /*
    8221             :      * Creating a column as identity implies NOT NULL, so adding the identity
    8222             :      * to an existing column that is not NOT NULL would create a state that
    8223             :      * cannot be reproduced without contortions.
    8224             :      */
    8225         136 :     if (!attTup->attnotnull)
    8226           6 :         ereport(ERROR,
    8227             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8228             :                  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
    8229             :                         colName, RelationGetRelationName(rel))));
    8230             : 
    8231         130 :     if (attTup->attidentity)
    8232          18 :         ereport(ERROR,
    8233             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8234             :                  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
    8235             :                         colName, RelationGetRelationName(rel))));
    8236             : 
    8237         112 :     if (attTup->atthasdef)
    8238           6 :         ereport(ERROR,
    8239             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8240             :                  errmsg("column \"%s\" of relation \"%s\" already has a default value",
    8241             :                         colName, RelationGetRelationName(rel))));
    8242             : 
    8243         106 :     attTup->attidentity = cdef->identity;
    8244         106 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
    8245             : 
    8246         106 :     InvokeObjectPostAlterHook(RelationRelationId,
    8247             :                               RelationGetRelid(rel),
    8248             :                               attTup->attnum);
    8249         106 :     ObjectAddressSubSet(address, RelationRelationId,
    8250             :                         RelationGetRelid(rel), attnum);
    8251         106 :     heap_freetuple(tuple);
    8252             : 
    8253         106 :     table_close(attrelation, RowExclusiveLock);
    8254             : 
    8255             :     /*
    8256             :      * Recurse to propagate the identity column to partitions.  Identity is
    8257             :      * not inherited in regular inheritance children.
    8258             :      */
    8259         106 :     if (recurse && ispartitioned)
    8260             :     {
    8261             :         List       *children;
    8262             :         ListCell   *lc;
    8263             : 
    8264          10 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
    8265             : 
    8266          16 :         foreach(lc, children)
    8267             :         {
    8268             :             Relation    childrel;
    8269             : 
    8270           6 :             childrel = table_open(lfirst_oid(lc), NoLock);
    8271           6 :             ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
    8272           6 :             table_close(childrel, NoLock);
    8273             :         }
    8274             :     }
    8275             : 
    8276         106 :     return address;
    8277             : }
    8278             : 
    8279             : /*
    8280             :  * ALTER TABLE ALTER COLUMN SET { GENERATED or sequence options }
    8281             :  *
    8282             :  * Return the address of the affected column.
    8283             :  */
    8284             : static ObjectAddress
    8285          74 : ATExecSetIdentity(Relation rel, const char *colName, Node *def,
    8286             :                   LOCKMODE lockmode, bool recurse, bool recursing)
    8287             : {
    8288             :     ListCell   *option;
    8289          74 :     DefElem    *generatedEl = NULL;
    8290             :     HeapTuple   tuple;
    8291             :     Form_pg_attribute attTup;
    8292             :     AttrNumber  attnum;
    8293             :     Relation    attrelation;
    8294             :     ObjectAddress address;
    8295             :     bool        ispartitioned;
    8296             : 
    8297          74 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    8298          74 :     if (ispartitioned && !recurse)
    8299           6 :         ereport(ERROR,
    8300             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8301             :                  errmsg("cannot change identity column of only the partitioned table"),
    8302             :                  errhint("Do not specify the ONLY keyword.")));
    8303             : 
    8304          68 :     if (rel->rd_rel->relispartition && !recursing)
    8305          12 :         ereport(ERROR,
    8306             :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8307             :                 errmsg("cannot change identity column of a partition"));
    8308             : 
    8309         100 :     foreach(option, castNode(List, def))
    8310             :     {
    8311          44 :         DefElem    *defel = lfirst_node(DefElem, option);
    8312             : 
    8313          44 :         if (strcmp(defel->defname, "generated") == 0)
    8314             :         {
    8315          44 :             if (generatedEl)
    8316           0 :                 ereport(ERROR,
    8317             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    8318             :                          errmsg("conflicting or redundant options")));
    8319          44 :             generatedEl = defel;
    8320             :         }
    8321             :         else
    8322           0 :             elog(ERROR, "option \"%s\" not recognized",
    8323             :                  defel->defname);
    8324             :     }
    8325             : 
    8326             :     /*
    8327             :      * Even if there is nothing to change here, we run all the checks.  There
    8328             :      * will be a subsequent ALTER SEQUENCE that relies on everything being
    8329             :      * there.
    8330             :      */
    8331             : 
    8332          56 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
    8333          56 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    8334          56 :     if (!HeapTupleIsValid(tuple))
    8335           0 :         ereport(ERROR,
    8336             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8337             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    8338             :                         colName, RelationGetRelationName(rel))));
    8339             : 
    8340          56 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    8341          56 :     attnum = attTup->attnum;
    8342             : 
    8343          56 :     if (attnum <= 0)
    8344           0 :         ereport(ERROR,
    8345             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8346             :                  errmsg("cannot alter system column \"%s\"",
    8347             :                         colName)));
    8348             : 
    8349          56 :     if (!attTup->attidentity)
    8350           6 :         ereport(ERROR,
    8351             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8352             :                  errmsg("column \"%s\" of relation \"%s\" is not an identity column",
    8353             :                         colName, RelationGetRelationName(rel))));
    8354             : 
    8355          50 :     if (generatedEl)
    8356             :     {
    8357          44 :         attTup->attidentity = defGetInt32(generatedEl);
    8358          44 :         CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
    8359             : 
    8360          44 :         InvokeObjectPostAlterHook(RelationRelationId,
    8361             :                                   RelationGetRelid(rel),
    8362             :                                   attTup->attnum);
    8363          44 :         ObjectAddressSubSet(address, RelationRelationId,
    8364             :                             RelationGetRelid(rel), attnum);
    8365             :     }
    8366             :     else
    8367           6 :         address = InvalidObjectAddress;
    8368             : 
    8369          50 :     heap_freetuple(tuple);
    8370          50 :     table_close(attrelation, RowExclusiveLock);
    8371             : 
    8372             :     /*
    8373             :      * Recurse to propagate the identity change to partitions. Identity is not
    8374             :      * inherited in regular inheritance children.
    8375             :      */
    8376          50 :     if (generatedEl && recurse && ispartitioned)
    8377             :     {
    8378             :         List       *children;
    8379             :         ListCell   *lc;
    8380             : 
    8381           6 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
    8382             : 
    8383          18 :         foreach(lc, children)
    8384             :         {
    8385             :             Relation    childrel;
    8386             : 
    8387          12 :             childrel = table_open(lfirst_oid(lc), NoLock);
    8388          12 :             ATExecSetIdentity(childrel, colName, def, lockmode, recurse, true);
    8389          12 :             table_close(childrel, NoLock);
    8390             :         }
    8391             :     }
    8392             : 
    8393          50 :     return address;
    8394             : }
    8395             : 
    8396             : /*
    8397             :  * ALTER TABLE ALTER COLUMN DROP IDENTITY
    8398             :  *
    8399             :  * Return the address of the affected column.
    8400             :  */
    8401             : static ObjectAddress
    8402          92 : ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode,
    8403             :                    bool recurse, bool recursing)
    8404             : {
    8405             :     HeapTuple   tuple;
    8406             :     Form_pg_attribute attTup;
    8407             :     AttrNumber  attnum;
    8408             :     Relation    attrelation;
    8409             :     ObjectAddress address;
    8410             :     Oid         seqid;
    8411             :     ObjectAddress seqaddress;
    8412             :     bool        ispartitioned;
    8413             : 
    8414          92 :     ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
    8415          92 :     if (ispartitioned && !recurse)
    8416           6 :         ereport(ERROR,
    8417             :                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8418             :                  errmsg("cannot drop identity from a column of only the partitioned table"),
    8419             :                  errhint("Do not specify the ONLY keyword.")));
    8420             : 
    8421          86 :     if (rel->rd_rel->relispartition && !recursing)
    8422           6 :         ereport(ERROR,
    8423             :                 errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8424             :                 errmsg("cannot drop identity from a column of a partition"));
    8425             : 
    8426          80 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
    8427          80 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    8428          80 :     if (!HeapTupleIsValid(tuple))
    8429           0 :         ereport(ERROR,
    8430             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8431             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    8432             :                         colName, RelationGetRelationName(rel))));
    8433             : 
    8434          80 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    8435          80 :     attnum = attTup->attnum;
    8436             : 
    8437          80 :     if (attnum <= 0)
    8438           0 :         ereport(ERROR,
    8439             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8440             :                  errmsg("cannot alter system column \"%s\"",
    8441             :                         colName)));
    8442             : 
    8443          80 :     if (!attTup->attidentity)
    8444             :     {
    8445          12 :         if (!missing_ok)
    8446           6 :             ereport(ERROR,
    8447             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8448             :                      errmsg("column \"%s\" of relation \"%s\" is not an identity column",
    8449             :                             colName, RelationGetRelationName(rel))));
    8450             :         else
    8451             :         {
    8452           6 :             ereport(NOTICE,
    8453             :                     (errmsg("column \"%s\" of relation \"%s\" is not an identity column, skipping",
    8454             :                             colName, RelationGetRelationName(rel))));
    8455           6 :             heap_freetuple(tuple);
    8456           6 :             table_close(attrelation, RowExclusiveLock);
    8457           6 :             return InvalidObjectAddress;
    8458             :         }
    8459             :     }
    8460             : 
    8461          68 :     attTup->attidentity = '\0';
    8462          68 :     CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
    8463             : 
    8464          68 :     InvokeObjectPostAlterHook(RelationRelationId,
    8465             :                               RelationGetRelid(rel),
    8466             :                               attTup->attnum);
    8467          68 :     ObjectAddressSubSet(address, RelationRelationId,
    8468             :                         RelationGetRelid(rel), attnum);
    8469          68 :     heap_freetuple(tuple);
    8470             : 
    8471          68 :     table_close(attrelation, RowExclusiveLock);
    8472             : 
    8473             :     /*
    8474             :      * Recurse to drop the identity from column in partitions.  Identity is
    8475             :      * not inherited in regular inheritance children so ignore them.
    8476             :      */
    8477          68 :     if (recurse && ispartitioned)
    8478             :     {
    8479             :         List       *children;
    8480             :         ListCell   *lc;
    8481             : 
    8482           6 :         children = find_inheritance_children(RelationGetRelid(rel), lockmode);
    8483             : 
    8484          12 :         foreach(lc, children)
    8485             :         {
    8486             :             Relation    childrel;
    8487             : 
    8488           6 :             childrel = table_open(lfirst_oid(lc), NoLock);
    8489           6 :             ATExecDropIdentity(childrel, colName, false, lockmode, recurse, true);
    8490           6 :             table_close(childrel, NoLock);
    8491             :         }
    8492             :     }
    8493             : 
    8494          68 :     if (!recursing)
    8495             :     {
    8496             :         /* drop the internal sequence */
    8497          32 :         seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
    8498          32 :         deleteDependencyRecordsForClass(RelationRelationId, seqid,
    8499             :                                         RelationRelationId, DEPENDENCY_INTERNAL);
    8500          32 :         CommandCounterIncrement();
    8501          32 :         seqaddress.classId = RelationRelationId;
    8502          32 :         seqaddress.objectId = seqid;
    8503          32 :         seqaddress.objectSubId = 0;
    8504          32 :         performDeletion(&seqaddress, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);
    8505             :     }
    8506             : 
    8507          68 :     return address;
    8508             : }
    8509             : 
    8510             : /*
    8511             :  * ALTER TABLE ALTER COLUMN SET EXPRESSION
    8512             :  *
    8513             :  * Return the address of the affected column.
    8514             :  */
    8515             : static ObjectAddress
    8516          84 : ATExecSetExpression(AlteredTableInfo *tab, Relation rel, const char *colName,
    8517             :                     Node *newExpr, LOCKMODE lockmode)
    8518             : {
    8519             :     HeapTuple   tuple;
    8520             :     Form_pg_attribute attTup;
    8521             :     AttrNumber  attnum;
    8522             :     Oid         attrdefoid;
    8523             :     ObjectAddress address;
    8524             :     Expr       *defval;
    8525             :     NewColumnValue *newval;
    8526             :     RawColumnDefault *rawEnt;
    8527             : 
    8528          84 :     tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
    8529          84 :     if (!HeapTupleIsValid(tuple))
    8530           0 :         ereport(ERROR,
    8531             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8532             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    8533             :                         colName, RelationGetRelationName(rel))));
    8534             : 
    8535          84 :     attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    8536          84 :     attnum = attTup->attnum;
    8537             : 
    8538          84 :     if (attnum <= 0)
    8539           0 :         ereport(ERROR,
    8540             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8541             :                  errmsg("cannot alter system column \"%s\"",
    8542             :                         colName)));
    8543             : 
    8544          84 :     if (attTup->attgenerated != ATTRIBUTE_GENERATED_STORED)
    8545           6 :         ereport(ERROR,
    8546             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    8547             :                  errmsg("column \"%s\" of relation \"%s\" is not a generated column",
    8548             :                         colName, RelationGetRelationName(rel))));
    8549          78 :     ReleaseSysCache(tuple);
    8550             : 
    8551             :     /*
    8552             :      * Clear all the missing values if we're rewriting the table, since this
    8553             :      * renders them pointless.
    8554             :      */
    8555          78 :     RelationClearMissing(rel);
    8556             : 
    8557             :     /* make sure we don't conflict with later attribute modifications */
    8558          78 :     CommandCounterIncrement();
    8559             : 
    8560             :     /*
    8561             :      * Find everything that depends on the column (constraints, indexes, etc),
    8562             :      * and record enough information to let us recreate the objects after
    8563             :      * rewrite.
    8564             :      */
    8565          78 :     RememberAllDependentForRebuilding(tab, AT_SetExpression, rel, attnum, colName);
    8566             : 
    8567             :     /*
    8568             :      * Drop the dependency records of the GENERATED expression, in particular
    8569             :      * its INTERNAL dependency on the column, which would otherwise cause
    8570             :      * dependency.c to refuse to perform the deletion.
    8571             :      */
    8572          78 :     attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
    8573          78 :     if (!OidIsValid(attrdefoid))
    8574           0 :         elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
    8575             :              RelationGetRelid(rel), attnum);
    8576          78 :     (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
    8577             : 
    8578             :     /* Make above changes visible */
    8579          78 :     CommandCounterIncrement();
    8580             : 
    8581             :     /*
    8582             :      * Get rid of the GENERATED expression itself.  We use RESTRICT here for
    8583             :      * safety, but at present we do not expect anything to depend on the
    8584             :      * expression.
    8585             :      */
    8586          78 :     RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
    8587             :                       false, false);
    8588             : 
    8589             :     /* Prepare to store the new expression, in the catalogs */
    8590          78 :     rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
    8591          78 :     rawEnt->attnum = attnum;
    8592          78 :     rawEnt->raw_default = newExpr;
    8593          78 :     rawEnt->missingMode = false;
    8594          78 :     rawEnt->generated = ATTRIBUTE_GENERATED_STORED;
    8595             : 
    8596             :     /* Store the generated expression */
    8597          78 :     AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
    8598             :                               false, true, false, NULL);
    8599             : 
    8600             :     /* Make above new expression visible */
    8601          78 :     CommandCounterIncrement();
    8602             : 
    8603             :     /* Prepare for table rewrite */
    8604          78 :     defval = (Expr *) build_column_default(rel, attnum);
    8605             : 
    8606          78 :     newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
    8607          78 :     newval->attnum = attnum;
    8608          78 :     newval->expr = expression_planner(defval);
    8609          78 :     newval->is_generated = true;
    8610             : 
    8611          78 :     tab->newvals = lappend(tab->newvals, newval);
    8612          78 :     tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
    8613             : 
    8614             :     /* Drop any pg_statistic entry for the column */
    8615          78 :     RemoveStatistics(RelationGetRelid(rel), attnum);
    8616             : 
    8617          78 :     InvokeObjectPostAlterHook(RelationRelationId,
    8618             :                               RelationGetRelid(rel), attnum);
    8619             : 
    8620          78 :     ObjectAddressSubSet(address, RelationRelationId,
    8621             :                         RelationGetRelid(rel), attnum);
    8622          78 :     return address;
    8623             : }
    8624             : 
    8625             : /*
    8626             :  * ALTER TABLE ALTER COLUMN DROP EXPRESSION
    8627             :  */
    8628             : static void
    8629          44 : ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
    8630             : {
    8631             :     /*
    8632             :      * Reject ONLY if there are child tables.  We could implement this, but it
    8633             :      * is a bit complicated.  GENERATED clauses must be attached to the column
    8634             :      * definition and cannot be added later like DEFAULT, so if a child table
    8635             :      * has a generation expression that the parent does not have, the child
    8636             :      * column will necessarily be an attislocal column.  So to implement ONLY
    8637             :      * here, we'd need extra code to update attislocal of the direct child
    8638             :      * tables, somewhat similar to how DROP COLUMN does it, so that the
    8639             :      * resulting state can be properly dumped and restored.
    8640             :      */
    8641          56 :     if (!recurse &&
    8642          12 :         find_inheritance_children(RelationGetRelid(rel), lockmode))
    8643           6 :         ereport(ERROR,
    8644             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    8645             :                  errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
    8646             : 
    8647             :     /*
    8648             :      * Cannot drop generation expression from inherited columns.
    8649             :      */
    8650          38 :     if (!recursing)
    8651             :     {
    8652             :         HeapTuple   tuple;
    8653             :         Form_pg_attribute attTup;
    8654             : 
    8655          32 :         tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), cmd->name);
    8656          32 :         if (!HeapTupleIsValid(tuple))
    8657           0 :             ereport(ERROR,
    8658             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    8659             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    8660             :                             cmd->name, RelationGetRelationName(rel))));
    8661             : 
    8662          32 :         attTup = (Form_pg_attribute) GETSTRUCT(tuple);
    8663             : 
    8664          32 :         if (attTup->attinhcount > 0)
    8665           6 :             ereport(ERROR,
    8666             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
    8667             :                      errmsg("cannot drop generation expression from inherited column")));
    8668             :     }
    8669          32 : }
    8670             : 
    8671             : /*
    8672             :  * Return the address of the affected column.
    8673             :  */
    8674             : static ObjectAddress
    8675          32 : ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
    8676             : {
    8677             :     HeapTuple   tuple;
    8678             :     Form_pg_attribute attTup;
    8679             :     AttrNumber  attnum;
    8680             :     Relation    attrelation;
    8681             :     Oid         attrdefoid;
    8682             :     ObjectAddress address;
    8683             : 
    8684          32 :     attrelation = table_open(AttributeRelationId, RowExclusiveLock);
    8685          32 :     tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    8686          32 :     if (!HeapTupleIsValid(tuple))
    8687           0 :         ereport(ERROR,
    8688             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    8689             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",