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