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